imperium-crawl 2.0.0 → 2.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.
- package/README.md +17 -10
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +1 -1
- package/dist/recipes/index.d.ts.map +1 -1
- package/dist/recipes/index.js +6 -0
- package/dist/recipes/index.js.map +1 -1
- package/dist/recipes/influencer-competitor-spy.json +14 -0
- package/dist/recipes/influencer-hashtag-scout.json +14 -0
- package/dist/recipes/influencer-niche-discovery.json +14 -0
- package/dist/skills/manager.d.ts +11 -2
- package/dist/skills/manager.d.ts.map +1 -1
- package/dist/skills/manager.js.map +1 -1
- package/dist/social/ai-fallback.d.ts +22 -0
- package/dist/social/ai-fallback.d.ts.map +1 -0
- package/dist/social/ai-fallback.js +137 -0
- package/dist/social/ai-fallback.js.map +1 -0
- package/dist/social/parsers.d.ts +28 -0
- package/dist/social/parsers.d.ts.map +1 -0
- package/dist/social/parsers.js +146 -0
- package/dist/social/parsers.js.map +1 -0
- package/dist/social/types.d.ts +55 -0
- package/dist/social/types.d.ts.map +1 -0
- package/dist/social/types.js +5 -0
- package/dist/social/types.js.map +1 -0
- package/dist/social/whisper.d.ts +29 -0
- package/dist/social/whisper.d.ts.map +1 -0
- package/dist/social/whisper.js +88 -0
- package/dist/social/whisper.js.map +1 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +5 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/manifest.d.ts.map +1 -1
- package/dist/tools/manifest.js +9 -0
- package/dist/tools/manifest.js.map +1 -1
- package/dist/tools/reddit.d.ts +36 -0
- package/dist/tools/reddit.d.ts.map +1 -0
- package/dist/tools/reddit.js +190 -0
- package/dist/tools/reddit.js.map +1 -0
- package/dist/tools/run-skill.d.ts +18 -0
- package/dist/tools/run-skill.d.ts.map +1 -1
- package/dist/tools/run-skill.js +681 -0
- package/dist/tools/run-skill.js.map +1 -1
- package/dist/tools/tiktok.d.ts +30 -0
- package/dist/tools/tiktok.d.ts.map +1 -0
- package/dist/tools/tiktok.js +246 -0
- package/dist/tools/tiktok.js.map +1 -0
- package/dist/tools/youtube.d.ts +33 -0
- package/dist/tools/youtube.d.ts.map +1 -0
- package/dist/tools/youtube.js +489 -0
- package/dist/tools/youtube.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
|
|
5
5
|
**The most powerful open-source MCP server for web scraping, crawling, and data extraction.**
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
25 tools. Zero API keys required. One `npx` command.
|
|
8
8
|
|
|
9
9
|
[](https://www.npmjs.com/package/imperium-crawl)
|
|
10
10
|
[](./LICENSE)
|
|
11
|
-
[]()
|
|
12
12
|
[](https://www.npmjs.com/package/imperium-crawl)
|
|
13
13
|
|
|
14
14
|
</div>
|
|
@@ -44,7 +44,7 @@ npx -y imperium-crawl scrape --url https://example.com
|
|
|
44
44
|
npm install -g imperium-crawl
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
> That's it.
|
|
47
|
+
> That's it. 20 of 25 tools work with zero API keys. Add optional keys later to unlock search, AI extraction, and CAPTCHA solving.
|
|
48
48
|
|
|
49
49
|
---
|
|
50
50
|
|
|
@@ -120,7 +120,7 @@ Scraping 4 URLs (concurrency: 3)...
|
|
|
120
120
|
## Why imperium-crawl?
|
|
121
121
|
|
|
122
122
|
🔓 **Zero API Keys Required**
|
|
123
|
-
|
|
123
|
+
20 of 25 tools work out of the box. No accounts, no tokens, no credit cards. Just `npx` and go.
|
|
124
124
|
|
|
125
125
|
🛡️ **3-Level Auto-Escalating Stealth**
|
|
126
126
|
Headers → TLS fingerprinting → headless browser + CAPTCHA solving. Automatically escalates until it gets through.
|
|
@@ -128,7 +128,7 @@ Headers → TLS fingerprinting → headless browser + CAPTCHA solving. Automatic
|
|
|
128
128
|
🧠 **Self-Improving**
|
|
129
129
|
Adaptive learning engine remembers what works per domain. Second visit is 3x faster. The more you use it, the smarter it gets.
|
|
130
130
|
|
|
131
|
-
🧰 **
|
|
131
|
+
🧰 **25 Tools, 3 Modes**
|
|
132
132
|
MCP server, CLI tool, or interactive TUI. Scraping, crawling, search, extraction, API discovery, WebSocket monitoring, browser automation, batch processing.
|
|
133
133
|
|
|
134
134
|
📜 **10 Built-in Recipes**
|
|
@@ -144,7 +144,7 @@ Teach it once, run forever. Auto-detect patterns on any page, save as reusable s
|
|
|
144
144
|
| Feature | **imperium-crawl** | Firecrawl MCP | fetch MCP | Crawl4AI MCP | Browserbase MCP |
|
|
145
145
|
|---------|:------------------:|:-------------:|:---------:|:------------:|:---------------:|
|
|
146
146
|
| Price | **Free forever** | $19+/month | Free | Free | $0.01/min |
|
|
147
|
-
| Total tools | **
|
|
147
|
+
| Total tools | **25** | 5 | 2 | 2 | 4 |
|
|
148
148
|
| Stealth levels | **3 (auto-escalate)** | Cloud-based | None | 1 | Cloud-based |
|
|
149
149
|
| Anti-bot detection | **7 systems** | Partial | None | Partial | Partial |
|
|
150
150
|
| TLS fingerprinting | **JA3/JA4** | No | No | No | No |
|
|
@@ -239,7 +239,7 @@ Second visit to cloudflare.com:
|
|
|
239
239
|
|
|
240
240
|
---
|
|
241
241
|
|
|
242
|
-
## All
|
|
242
|
+
## All 25 Tools
|
|
243
243
|
|
|
244
244
|
### 📄 Scraping (no API key needed)
|
|
245
245
|
|
|
@@ -290,6 +290,13 @@ Second visit to cloudflare.com:
|
|
|
290
290
|
| **interact** | Browser automation with 18 action types (click, type, scroll, wait, screenshot, evaluate, select, hover, press, navigate, drag, upload, storage, cookies, pdf, auth_login). Ref targeting via ARIA snapshot, session encryption, action policy, domain filter, network interception, device emulation. |
|
|
291
291
|
| **snapshot** | ARIA-based page snapshot with interactive element refs. Use refs in interact for precise targeting. Annotated screenshots. |
|
|
292
292
|
|
|
293
|
+
### 📱 Social Media (no API key needed)
|
|
294
|
+
|
|
295
|
+
| Tool | What It Does |
|
|
296
|
+
|------|-------------|
|
|
297
|
+
| **youtube** | Search videos, get video details, comments, transcripts, and channel info. Parses `ytInitialData` — no API key needed. |
|
|
298
|
+
| **reddit** | Search Reddit, browse subreddits, get posts and comments via Reddit's public JSON API. |
|
|
299
|
+
|
|
293
300
|
### 📦 Batch Processing (no API key needed)
|
|
294
301
|
|
|
295
302
|
| Tool | What It Does |
|
|
@@ -461,7 +468,7 @@ Turn any website into an API. No documentation needed.
|
|
|
461
468
|
|
|
462
469
|
## AI Agent Guide
|
|
463
470
|
|
|
464
|
-
imperium-crawl ships with [`SKILL/`](./SKILL/) — a structured guide that teaches AI agents how to use all
|
|
471
|
+
imperium-crawl ships with [`SKILL/`](./SKILL/) — a structured guide that teaches AI agents how to use all 25 tools effectively. Includes proven workflows, decision trees, error recovery, and advanced patterns.
|
|
465
472
|
|
|
466
473
|
### Three Ways to Connect
|
|
467
474
|
|
|
@@ -524,7 +531,7 @@ Every tool tested against production websites with real anti-bot defenses:
|
|
|
524
531
|
| 📊 **job_status** | Batch job | Full per-URL results with timing |
|
|
525
532
|
| 🗑️ **delete_job** | Completed job | Cleaned up job data from disk |
|
|
526
533
|
|
|
527
|
-
> **
|
|
534
|
+
> **25/25 tools. 34 hidden APIs on Airbnb. Live BTC feed. Zero API keys for scraping.**
|
|
528
535
|
|
|
529
536
|
---
|
|
530
537
|
|
|
@@ -558,7 +565,7 @@ cd imperium-crawl
|
|
|
558
565
|
npm install
|
|
559
566
|
npm run build
|
|
560
567
|
npm run dev # Watch mode (rebuild on changes)
|
|
561
|
-
npm test #
|
|
568
|
+
npm test # 370 tests
|
|
562
569
|
npm start # Start MCP server
|
|
563
570
|
```
|
|
564
571
|
|
package/dist/constants.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare const PACKAGE_NAME = "imperium-crawl";
|
|
2
|
-
export declare const PACKAGE_VERSION = "2.
|
|
2
|
+
export declare const PACKAGE_VERSION = "2.1.0";
|
|
3
3
|
export declare const DEFAULT_TIMEOUT_MS = 30000;
|
|
4
4
|
export declare const DEFAULT_MAX_PAGES = 10;
|
|
5
5
|
export declare const DEFAULT_MAX_DEPTH = 2;
|
package/dist/constants.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/recipes/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/recipes/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAgBxD,eAAO,MAAM,cAAc,EAAE,WAAW,EActB,CAAC"}
|
package/dist/recipes/index.js
CHANGED
|
@@ -8,6 +8,9 @@ import newsArticleReader from "./news-article-reader.json" with { type: "json" }
|
|
|
8
8
|
import redditPosts from "./reddit-posts.json" with { type: "json" };
|
|
9
9
|
import seoPageAudit from "./seo-page-audit.json" with { type: "json" };
|
|
10
10
|
import socialMediaMentions from "./social-media-mentions.json" with { type: "json" };
|
|
11
|
+
import influencerNicheDiscovery from "./influencer-niche-discovery.json" with { type: "json" };
|
|
12
|
+
import influencerHashtagScout from "./influencer-hashtag-scout.json" with { type: "json" };
|
|
13
|
+
import influencerCompetitorSpy from "./influencer-competitor-spy.json" with { type: "json" };
|
|
11
14
|
export const builtinRecipes = [
|
|
12
15
|
hnTopStories,
|
|
13
16
|
githubTrending,
|
|
@@ -19,5 +22,8 @@ export const builtinRecipes = [
|
|
|
19
22
|
redditPosts,
|
|
20
23
|
seoPageAudit,
|
|
21
24
|
socialMediaMentions,
|
|
25
|
+
influencerNicheDiscovery,
|
|
26
|
+
influencerHashtagScout,
|
|
27
|
+
influencerCompetitorSpy,
|
|
22
28
|
];
|
|
23
29
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/recipes/index.ts"],"names":[],"mappings":"AAEA,OAAO,YAAY,MAAM,uBAAuB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AACvE,OAAO,cAAc,MAAM,wBAAwB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAC1E,OAAO,qBAAqB,MAAM,gCAAgC,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AACzF,OAAO,gBAAgB,MAAM,0BAA0B,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAC9E,OAAO,cAAc,MAAM,wBAAwB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAC1E,OAAO,eAAe,MAAM,yBAAyB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAC5E,OAAO,iBAAiB,MAAM,4BAA4B,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AACjF,OAAO,WAAW,MAAM,qBAAqB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AACpE,OAAO,YAAY,MAAM,uBAAuB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AACvE,OAAO,mBAAmB,MAAM,8BAA8B,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/recipes/index.ts"],"names":[],"mappings":"AAEA,OAAO,YAAY,MAAM,uBAAuB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AACvE,OAAO,cAAc,MAAM,wBAAwB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAC1E,OAAO,qBAAqB,MAAM,gCAAgC,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AACzF,OAAO,gBAAgB,MAAM,0BAA0B,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAC9E,OAAO,cAAc,MAAM,wBAAwB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAC1E,OAAO,eAAe,MAAM,yBAAyB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAC5E,OAAO,iBAAiB,MAAM,4BAA4B,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AACjF,OAAO,WAAW,MAAM,qBAAqB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AACpE,OAAO,YAAY,MAAM,uBAAuB,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AACvE,OAAO,mBAAmB,MAAM,8BAA8B,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AACrF,OAAO,wBAAwB,MAAM,mCAAmC,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAC/F,OAAO,sBAAsB,MAAM,iCAAiC,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAC3F,OAAO,uBAAuB,MAAM,kCAAkC,CAAC,OAAO,IAAI,EAAE,MAAM,EAAE,CAAC;AAE7F,MAAM,CAAC,MAAM,cAAc,GAAkB;IAC3C,YAAY;IACZ,cAAc;IACd,qBAAqB;IACrB,gBAAgB;IAChB,cAAc;IACd,eAAe;IACf,iBAAiB;IACjB,WAAW;IACX,YAAY;IACZ,mBAAmB;IACnB,wBAAwB;IACxB,sBAAsB;IACtB,uBAAuB;CACP,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "influencer-competitor-spy",
|
|
3
|
+
"description": "Find influencers who work with competitors via Brave Search + YouTube",
|
|
4
|
+
"url": "https://youtube.com",
|
|
5
|
+
"created_at": "2026-03-06T00:00:00Z",
|
|
6
|
+
"builtin": true,
|
|
7
|
+
"tool": "influencer_discovery",
|
|
8
|
+
"workflow": "competitor_spy",
|
|
9
|
+
"niche": "travel",
|
|
10
|
+
"platforms": ["youtube", "brave"],
|
|
11
|
+
"output_format": "json",
|
|
12
|
+
"threshold": 60,
|
|
13
|
+
"ig_max_calls": 15
|
|
14
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "influencer-hashtag-scout",
|
|
3
|
+
"description": "Find influencers by Instagram hashtags with cross-platform verification",
|
|
4
|
+
"url": "https://instagram.com",
|
|
5
|
+
"created_at": "2026-03-06T00:00:00Z",
|
|
6
|
+
"builtin": true,
|
|
7
|
+
"tool": "influencer_discovery",
|
|
8
|
+
"workflow": "hashtag_scout",
|
|
9
|
+
"niche": "travel",
|
|
10
|
+
"platforms": ["instagram", "brave", "youtube"],
|
|
11
|
+
"output_format": "json",
|
|
12
|
+
"threshold": 60,
|
|
13
|
+
"ig_max_calls": 15
|
|
14
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "influencer-niche-discovery",
|
|
3
|
+
"description": "Discover influencers in any niche via YouTube + Brave Search + Instagram enrichment",
|
|
4
|
+
"url": "https://youtube.com",
|
|
5
|
+
"created_at": "2026-03-06T00:00:00Z",
|
|
6
|
+
"builtin": true,
|
|
7
|
+
"tool": "influencer_discovery",
|
|
8
|
+
"workflow": "niche_discovery",
|
|
9
|
+
"niche": "travel",
|
|
10
|
+
"platforms": ["youtube", "instagram", "brave"],
|
|
11
|
+
"output_format": "json",
|
|
12
|
+
"threshold": 60,
|
|
13
|
+
"ig_max_calls": 15
|
|
14
|
+
}
|
package/dist/skills/manager.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export interface SkillPagination {
|
|
|
6
6
|
next?: string;
|
|
7
7
|
max_pages?: number;
|
|
8
8
|
}
|
|
9
|
-
export type RecipeTool = "extract" | "ai_extract" | "readability" | "scrape" | "monitor_websocket";
|
|
9
|
+
export type RecipeTool = "extract" | "ai_extract" | "readability" | "scrape" | "monitor_websocket" | "influencer_discovery";
|
|
10
10
|
interface SkillConfigBase {
|
|
11
11
|
name: string;
|
|
12
12
|
description: string;
|
|
@@ -42,7 +42,16 @@ export interface WebSocketSkillConfig extends SkillConfigBase {
|
|
|
42
42
|
max_messages?: number;
|
|
43
43
|
filter_url?: string;
|
|
44
44
|
}
|
|
45
|
-
export
|
|
45
|
+
export interface InfluencerDiscoverySkillConfig extends SkillConfigBase {
|
|
46
|
+
tool: "influencer_discovery";
|
|
47
|
+
workflow: "niche_discovery" | "hashtag_scout" | "competitor_spy";
|
|
48
|
+
niche: string;
|
|
49
|
+
platforms?: ("youtube" | "instagram" | "brave")[];
|
|
50
|
+
output_format?: "json" | "markdown" | "csv";
|
|
51
|
+
threshold?: number;
|
|
52
|
+
ig_max_calls?: number;
|
|
53
|
+
}
|
|
54
|
+
export type SkillConfig = ExtractSkillConfig | AiExtractSkillConfig | ReadabilitySkillConfig | ScrapeSkillConfig | WebSocketSkillConfig | InfluencerDiscoverySkillConfig;
|
|
46
55
|
export declare function save(name: string, config: SkillConfig): Promise<void>;
|
|
47
56
|
export declare function load(name: string): Promise<SkillConfig | null>;
|
|
48
57
|
export declare function list(): Promise<SkillConfig[]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/skills/manager.ts"],"names":[],"mappings":"AAMA,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAMpD;AAED,MAAM,WAAW,mBAAmB;IAClC,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAID,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,YAAY,GAAG,aAAa,GAAG,QAAQ,GAAG,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/skills/manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/skills/manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,MAAM,aAAa,GAAG,kBAAkB,CAAC;AAEzC,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CACb,uBAAuB,IAAI,iEAAiE,CAC7F,CAAC;IACJ,CAAC;AACH,CAAC;
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/skills/manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI fallback for social media tools.
|
|
3
|
+
*
|
|
4
|
+
* When structured parsers fail (ytInitialData, .json API, rehydration data),
|
|
5
|
+
* this uses the existing LLM infrastructure to extract data from ARIA trees
|
|
6
|
+
* or raw HTML markdown.
|
|
7
|
+
*
|
|
8
|
+
* Structured extraction = primary (free, fast).
|
|
9
|
+
* AI fallback = backup (costs tokens, slower, but always works).
|
|
10
|
+
*/
|
|
11
|
+
import type { Page } from "rebrowser-playwright";
|
|
12
|
+
export type SocialAction = "youtube:search" | "youtube:video" | "youtube:comments" | "youtube:transcript" | "youtube:channel" | "reddit:search" | "reddit:posts" | "reddit:comments" | "reddit:subreddit";
|
|
13
|
+
export declare function socialAiFallback<T>(opts: {
|
|
14
|
+
action: SocialAction;
|
|
15
|
+
page?: Page;
|
|
16
|
+
url?: string;
|
|
17
|
+
maxTokens?: number;
|
|
18
|
+
}): Promise<{
|
|
19
|
+
data: T;
|
|
20
|
+
model: string;
|
|
21
|
+
} | null>;
|
|
22
|
+
//# sourceMappingURL=ai-fallback.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-fallback.d.ts","sourceRoot":"","sources":["../../src/social/ai-fallback.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AAWjD,MAAM,MAAM,YAAY,GACpB,gBAAgB,GAAG,eAAe,GAAG,kBAAkB,GACvD,oBAAoB,GAAG,iBAAiB,GACxC,eAAe,GAAG,cAAc,GAAG,iBAAiB,GAAG,kBAAkB,CAAC;AAkB9E,wBAAsB,gBAAgB,CAAC,CAAC,EAAE,IAAI,EAAE;IAC9C,MAAM,EAAE,YAAY,CAAC;IACrB,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,CAAC,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CA6B7C"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI fallback for social media tools.
|
|
3
|
+
*
|
|
4
|
+
* When structured parsers fail (ytInitialData, .json API, rehydration data),
|
|
5
|
+
* this uses the existing LLM infrastructure to extract data from ARIA trees
|
|
6
|
+
* or raw HTML markdown.
|
|
7
|
+
*
|
|
8
|
+
* Structured extraction = primary (free, fast).
|
|
9
|
+
* AI fallback = backup (costs tokens, slower, but always works).
|
|
10
|
+
*/
|
|
11
|
+
import { hasLLMConfigured, createLLMClient } from "../llm/index.js";
|
|
12
|
+
import { extractWithLLM } from "../llm/extractor.js";
|
|
13
|
+
import { getEnhancedSnapshot } from "../snapshot/extractor.js";
|
|
14
|
+
import { smartFetch } from "../stealth/index.js";
|
|
15
|
+
import { htmlToMarkdown } from "../utils/markdown.js";
|
|
16
|
+
import { parseCompactNumber } from "./parsers.js";
|
|
17
|
+
// ── Schemas for LLM extraction ──
|
|
18
|
+
const SOCIAL_SCHEMAS = {
|
|
19
|
+
"youtube:search": `{ "videos": [{ "id": "video ID", "title": "string", "url": "full URL", "duration": "M:SS", "views": "view count text", "author": "channel name", "author_url": "channel URL", "published": "relative time" }] }`,
|
|
20
|
+
"youtube:video": `{ "id": "video ID", "title": "string", "url": "full URL", "views": "view count text", "likes": "like count text", "author": "channel name", "author_url": "channel URL", "published": "date text", "description": "first 2000 chars" }`,
|
|
21
|
+
"youtube:comments": `{ "comments": [{ "author": "string", "text": "comment text", "likes": "like count", "published": "relative time" }] }`,
|
|
22
|
+
"youtube:transcript": `{ "segments": [{ "start": "timestamp M:SS", "text": "string" }] }`,
|
|
23
|
+
"youtube:channel": `{ "name": "channel name", "url": "channel URL", "description": "about text", "subscribers": "subscriber count text", "verified": true/false }`,
|
|
24
|
+
"reddit:search": `{ "posts": [{ "title": "string", "url": "permalink", "author": "string", "score": "number or text", "comments_count": "number", "subreddit": "string", "published": "relative time" }] }`,
|
|
25
|
+
"reddit:posts": `{ "posts": [{ "title": "string", "url": "permalink", "author": "string", "score": "number or text", "comments_count": "number", "published": "relative time", "flair": "flair text or null" }] }`,
|
|
26
|
+
"reddit:comments": `{ "post": { "title": "string", "author": "string", "score": "number" }, "comments": [{ "author": "string", "text": "comment body", "score": "number", "published": "relative time" }] }`,
|
|
27
|
+
"reddit:subreddit": `{ "name": "subreddit name", "description": "description text", "subscribers": "subscriber count text", "created": "creation date" }`,
|
|
28
|
+
};
|
|
29
|
+
// ── Main fallback function ──
|
|
30
|
+
export async function socialAiFallback(opts) {
|
|
31
|
+
if (!hasLLMConfigured())
|
|
32
|
+
return null;
|
|
33
|
+
const schema = SOCIAL_SCHEMAS[opts.action];
|
|
34
|
+
if (!schema)
|
|
35
|
+
return null;
|
|
36
|
+
let content;
|
|
37
|
+
if (opts.page) {
|
|
38
|
+
// Playwright mode: ARIA tree from already-open page
|
|
39
|
+
const snapshot = await getEnhancedSnapshot(opts.page, { compact: true });
|
|
40
|
+
content = snapshot.tree;
|
|
41
|
+
}
|
|
42
|
+
else if (opts.url) {
|
|
43
|
+
// HTTP mode: fetch + convert to markdown
|
|
44
|
+
const result = await smartFetch(opts.url, { maxLevel: 2 });
|
|
45
|
+
content = htmlToMarkdown(result.html);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
if (!content || content.length < 50)
|
|
51
|
+
return null;
|
|
52
|
+
const client = await createLLMClient();
|
|
53
|
+
const extraction = await extractWithLLM(client, content, schema, opts.maxTokens ?? 4000);
|
|
54
|
+
const raw = extraction.data;
|
|
55
|
+
const normalized = normalizeResult(opts.action, raw);
|
|
56
|
+
return { data: normalized, model: extraction.model };
|
|
57
|
+
}
|
|
58
|
+
// ── Normalizers ──
|
|
59
|
+
function normalizeResult(action, raw) {
|
|
60
|
+
const platform = action.split(":")[0];
|
|
61
|
+
const type = action.split(":")[1];
|
|
62
|
+
if (type === "search" || type === "posts") {
|
|
63
|
+
const items = (raw.videos || raw.posts || []);
|
|
64
|
+
const normalized = items.map((item) => platform === "reddit" ? normalizePost(item) : normalizeVideo(item));
|
|
65
|
+
return platform === "reddit"
|
|
66
|
+
? { platform: "reddit", results: normalized }
|
|
67
|
+
: { platform, results: normalized };
|
|
68
|
+
}
|
|
69
|
+
if (type === "video")
|
|
70
|
+
return normalizeVideo(raw);
|
|
71
|
+
if (type === "user" || type === "channel" || type === "subreddit")
|
|
72
|
+
return normalizeProfile(raw);
|
|
73
|
+
if (type === "comments") {
|
|
74
|
+
const comments = (raw.comments || []).map(normalizeComment);
|
|
75
|
+
return { ...raw, comments };
|
|
76
|
+
}
|
|
77
|
+
return raw;
|
|
78
|
+
}
|
|
79
|
+
function normalizeVideo(raw) {
|
|
80
|
+
return {
|
|
81
|
+
id: raw.id || "",
|
|
82
|
+
title: raw.title || "",
|
|
83
|
+
url: raw.url || "",
|
|
84
|
+
thumbnail: raw.thumbnail,
|
|
85
|
+
duration: raw.duration,
|
|
86
|
+
views: typeof raw.views === "number" ? raw.views : parseNum(raw.views),
|
|
87
|
+
likes: typeof raw.likes === "number" ? raw.likes : parseNum(raw.likes),
|
|
88
|
+
author: raw.author || "",
|
|
89
|
+
author_url: raw.author_url,
|
|
90
|
+
published: raw.published,
|
|
91
|
+
description: raw.description?.substring(0, 2000),
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function normalizePost(raw) {
|
|
95
|
+
return {
|
|
96
|
+
id: raw.id || "",
|
|
97
|
+
title: raw.title || "",
|
|
98
|
+
url: raw.url || "",
|
|
99
|
+
author: raw.author || "",
|
|
100
|
+
score: typeof raw.score === "number" ? raw.score : parseNum(raw.score),
|
|
101
|
+
comments_count: typeof raw.comments_count === "number" ? raw.comments_count : parseNum(raw.comments_count),
|
|
102
|
+
published: raw.published,
|
|
103
|
+
subreddit: raw.subreddit,
|
|
104
|
+
text: raw.text,
|
|
105
|
+
flair: raw.flair,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function normalizeComment(raw) {
|
|
109
|
+
return {
|
|
110
|
+
id: raw.id || `comment-${Math.random().toString(36).slice(2, 8)}`,
|
|
111
|
+
author: raw.author || "",
|
|
112
|
+
text: raw.text || "",
|
|
113
|
+
score: typeof raw.score === "number" ? raw.score : (typeof raw.likes === "number" ? raw.likes : parseNum(raw.score || raw.likes)),
|
|
114
|
+
published: raw.published,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function normalizeProfile(raw) {
|
|
118
|
+
const subs = raw.subscribers || raw.followers;
|
|
119
|
+
return {
|
|
120
|
+
name: raw.name || raw.username || "",
|
|
121
|
+
url: raw.url || "",
|
|
122
|
+
description: raw.description?.substring(0, 1000),
|
|
123
|
+
subscribers: typeof subs === "number" ? subs : parseNum(subs),
|
|
124
|
+
avatar: raw.avatar,
|
|
125
|
+
verified: raw.verified ?? false,
|
|
126
|
+
video_count: typeof raw.video_count === "number" ? raw.video_count : parseNum(raw.video_count),
|
|
127
|
+
created: raw.created,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/** Parse a number string, returning undefined for NaN. */
|
|
131
|
+
function parseNum(val) {
|
|
132
|
+
if (val == null)
|
|
133
|
+
return undefined;
|
|
134
|
+
const n = parseCompactNumber(String(val));
|
|
135
|
+
return isNaN(n) ? undefined : n;
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=ai-fallback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-fallback.js","sourceRoot":"","sources":["../../src/social/ai-fallback.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared parsers for social media tools.
|
|
3
|
+
*
|
|
4
|
+
* parseCompactNumber: "1.2M" -> 1200000
|
|
5
|
+
* parseRelativeTime: "3 hours ago" -> ISO date string
|
|
6
|
+
* sanitizeText: strip HTML tags, collapse whitespace
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Parse compact number strings like "1.2M", "842K", "3.5B", "1,234".
|
|
10
|
+
* Returns NaN for unparseable input.
|
|
11
|
+
*/
|
|
12
|
+
export declare function parseCompactNumber(str: string): number;
|
|
13
|
+
/**
|
|
14
|
+
* Parse relative time strings like "3 hours ago", "1 day ago", "2 months ago".
|
|
15
|
+
* Returns ISO date string, or null if unparseable.
|
|
16
|
+
*/
|
|
17
|
+
export declare function parseRelativeTime(str: string): string | null;
|
|
18
|
+
/**
|
|
19
|
+
* Strip HTML tags and collapse whitespace.
|
|
20
|
+
*/
|
|
21
|
+
export declare function sanitizeText(html: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* Extract JSON from a script tag pattern like `var ytInitialData = {...};`
|
|
24
|
+
* Also handles `<script id="varName" type="application/json">{...}</script>`.
|
|
25
|
+
* Returns parsed object or null.
|
|
26
|
+
*/
|
|
27
|
+
export declare function extractScriptJson(html: string, varName: string): unknown | null;
|
|
28
|
+
//# sourceMappingURL=parsers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parsers.d.ts","sourceRoot":"","sources":["../../src/social/parsers.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AASH;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAgBtD;AAYD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAY5D;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAYjD;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAwE/E"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared parsers for social media tools.
|
|
3
|
+
*
|
|
4
|
+
* parseCompactNumber: "1.2M" -> 1200000
|
|
5
|
+
* parseRelativeTime: "3 hours ago" -> ISO date string
|
|
6
|
+
* sanitizeText: strip HTML tags, collapse whitespace
|
|
7
|
+
*/
|
|
8
|
+
const MULTIPLIERS = {
|
|
9
|
+
K: 1_000,
|
|
10
|
+
M: 1_000_000,
|
|
11
|
+
B: 1_000_000_000,
|
|
12
|
+
T: 1_000_000_000_000,
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Parse compact number strings like "1.2M", "842K", "3.5B", "1,234".
|
|
16
|
+
* Returns NaN for unparseable input.
|
|
17
|
+
*/
|
|
18
|
+
export function parseCompactNumber(str) {
|
|
19
|
+
if (!str)
|
|
20
|
+
return NaN;
|
|
21
|
+
// Clean: remove commas, spaces, plus signs
|
|
22
|
+
const cleaned = str.replace(/[,\s+]/g, "").trim();
|
|
23
|
+
// Try suffix match: "1.2M", "842K"
|
|
24
|
+
const match = cleaned.match(/^([\d.]+)\s*([KMBT])/i);
|
|
25
|
+
if (match) {
|
|
26
|
+
const num = parseFloat(match[1]);
|
|
27
|
+
const suffix = match[2].toUpperCase();
|
|
28
|
+
return Math.round(num * (MULTIPLIERS[suffix] || 1));
|
|
29
|
+
}
|
|
30
|
+
// Plain number
|
|
31
|
+
return parseFloat(cleaned) || NaN;
|
|
32
|
+
}
|
|
33
|
+
const TIME_UNITS = {
|
|
34
|
+
second: 1_000,
|
|
35
|
+
minute: 60_000,
|
|
36
|
+
hour: 3_600_000,
|
|
37
|
+
day: 86_400_000,
|
|
38
|
+
week: 604_800_000,
|
|
39
|
+
month: 2_592_000_000, // ~30 days
|
|
40
|
+
year: 31_536_000_000, // ~365 days
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Parse relative time strings like "3 hours ago", "1 day ago", "2 months ago".
|
|
44
|
+
* Returns ISO date string, or null if unparseable.
|
|
45
|
+
*/
|
|
46
|
+
export function parseRelativeTime(str) {
|
|
47
|
+
if (!str)
|
|
48
|
+
return null;
|
|
49
|
+
const match = str.match(/(\d+)\s+(second|minute|hour|day|week|month|year)s?\s+ago/i);
|
|
50
|
+
if (!match)
|
|
51
|
+
return null;
|
|
52
|
+
const amount = parseInt(match[1], 10);
|
|
53
|
+
const unit = match[2].toLowerCase();
|
|
54
|
+
const ms = TIME_UNITS[unit];
|
|
55
|
+
if (!ms)
|
|
56
|
+
return null;
|
|
57
|
+
return new Date(Date.now() - amount * ms).toISOString();
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Strip HTML tags and collapse whitespace.
|
|
61
|
+
*/
|
|
62
|
+
export function sanitizeText(html) {
|
|
63
|
+
if (!html)
|
|
64
|
+
return "";
|
|
65
|
+
return html
|
|
66
|
+
.replace(/<[^>]*>/g, "")
|
|
67
|
+
.replace(/&/g, "&")
|
|
68
|
+
.replace(/</g, "<")
|
|
69
|
+
.replace(/>/g, ">")
|
|
70
|
+
.replace(/"/g, '"')
|
|
71
|
+
.replace(/'/g, "'")
|
|
72
|
+
.replace(/ /g, " ")
|
|
73
|
+
.replace(/\s+/g, " ")
|
|
74
|
+
.trim();
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Extract JSON from a script tag pattern like `var ytInitialData = {...};`
|
|
78
|
+
* Also handles `<script id="varName" type="application/json">{...}</script>`.
|
|
79
|
+
* Returns parsed object or null.
|
|
80
|
+
*/
|
|
81
|
+
export function extractScriptJson(html, varName) {
|
|
82
|
+
// Strategy 1: <script id="varName" type="application/json">{...}</script>
|
|
83
|
+
const scriptTagPattern = new RegExp(`<script[^>]+id=["']${varName}["'][^>]*>([\\s\\S]*?)</script>`, "i");
|
|
84
|
+
const scriptTagMatch = scriptTagPattern.exec(html);
|
|
85
|
+
if (scriptTagMatch) {
|
|
86
|
+
try {
|
|
87
|
+
return JSON.parse(scriptTagMatch[1]);
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// Fall through to other strategies
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// Strategy 2: var varName = {...}; or window['varName'] = {...};
|
|
94
|
+
const patterns = [
|
|
95
|
+
new RegExp(`var\\s+${varName}\\s*=\\s*`, "i"),
|
|
96
|
+
new RegExp(`window\\[['"]${varName}['"]\\]\\s*=\\s*`, "i"),
|
|
97
|
+
];
|
|
98
|
+
for (const pattern of patterns) {
|
|
99
|
+
const match = pattern.exec(html);
|
|
100
|
+
if (!match)
|
|
101
|
+
continue;
|
|
102
|
+
const start = match.index + match[0].length;
|
|
103
|
+
// Find matching brace
|
|
104
|
+
let depth = 0;
|
|
105
|
+
let inString = false;
|
|
106
|
+
let escape = false;
|
|
107
|
+
let stringChar = "";
|
|
108
|
+
for (let i = start; i < html.length; i++) {
|
|
109
|
+
const ch = html[i];
|
|
110
|
+
if (escape) {
|
|
111
|
+
escape = false;
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (ch === "\\") {
|
|
115
|
+
escape = true;
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (inString) {
|
|
119
|
+
if (ch === stringChar)
|
|
120
|
+
inString = false;
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
if (ch === '"' || ch === "'") {
|
|
124
|
+
inString = true;
|
|
125
|
+
stringChar = ch;
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
if (ch === "{" || ch === "[")
|
|
129
|
+
depth++;
|
|
130
|
+
if (ch === "}" || ch === "]") {
|
|
131
|
+
depth--;
|
|
132
|
+
if (depth === 0) {
|
|
133
|
+
const jsonStr = html.substring(start, i + 1);
|
|
134
|
+
try {
|
|
135
|
+
return JSON.parse(jsonStr);
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=parsers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parsers.js","sourceRoot":"","sources":["../../src/social/parsers.ts"],"names":[],"mappings":"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"}
|