feat: one-click cookie import from browser
New: agent-eyes configure --from-browser chrome - Extracts Twitter, XiaoHongShu, Bilibili cookies in ONE command - No F12, no manual copying, no extension needed - Supports: chrome, firefox, edge, brave, opera - Uses browser-cookie3 (optional dependency: pip install agent-eyes[cookies]) Install guide now 3x shorter: 1. pip install + agent-eyes install (auto-detect env) 2. agent-eyes configure --from-browser chrome (one-click all cookies) 3. agent-eyes configure exa-key KEY (one API key) 4. Done User actions reduced from 4 trips to 2: - Before: go to exa.ai + F12 Twitter + F12 XHS + go to webshare.io - After: go to exa.ai + say 'yes' to auto-import cookies
This commit is contained in:
+46
-7
@@ -80,11 +80,15 @@ def main():
|
|||||||
help="Exa API key (get free at https://exa.ai)")
|
help="Exa API key (get free at https://exa.ai)")
|
||||||
|
|
||||||
# ── configure ──
|
# ── configure ──
|
||||||
p_conf = sub.add_parser("configure", help="Set a config value")
|
p_conf = sub.add_parser("configure", help="Set a config value or auto-extract from browser")
|
||||||
p_conf.add_argument("key", choices=["exa-key", "proxy", "github-token", "groq-key",
|
p_conf.add_argument("key", nargs="?", default=None,
|
||||||
"twitter-cookies", "xhs-cookie", "youtube-cookies"],
|
choices=["exa-key", "proxy", "github-token", "groq-key",
|
||||||
help="What to configure")
|
"twitter-cookies", "xhs-cookie", "youtube-cookies"],
|
||||||
p_conf.add_argument("value", nargs="+", help="The value(s) to set")
|
help="What to configure (omit if using --from-browser)")
|
||||||
|
p_conf.add_argument("value", nargs="*", help="The value(s) to set")
|
||||||
|
p_conf.add_argument("--from-browser", metavar="BROWSER",
|
||||||
|
choices=["chrome", "firefox", "edge", "brave", "opera"],
|
||||||
|
help="Auto-extract ALL platform cookies from browser (chrome/firefox/edge/brave/opera)")
|
||||||
|
|
||||||
# ── doctor ──
|
# ── doctor ──
|
||||||
sub.add_parser("doctor", help="Check platform availability")
|
sub.add_parser("doctor", help="Check platform availability")
|
||||||
@@ -224,11 +228,46 @@ def _detect_environment():
|
|||||||
|
|
||||||
|
|
||||||
def _cmd_configure(args):
|
def _cmd_configure(args):
|
||||||
"""Set a config value and test it."""
|
"""Set a config value and test it, or auto-extract from browser."""
|
||||||
from agent_eyes.config import Config
|
from agent_eyes.config import Config
|
||||||
|
|
||||||
config = Config()
|
config = Config()
|
||||||
value = " ".join(args.value) if isinstance(args.value, list) else args.value
|
|
||||||
|
# ── Auto-extract from browser ──
|
||||||
|
if args.from_browser:
|
||||||
|
from agent_eyes.cookie_extract import configure_from_browser
|
||||||
|
|
||||||
|
browser = args.from_browser
|
||||||
|
print(f"🔍 Extracting cookies from {browser}...")
|
||||||
|
print()
|
||||||
|
|
||||||
|
results = configure_from_browser(browser, config)
|
||||||
|
|
||||||
|
found_any = False
|
||||||
|
for platform, success, message in results:
|
||||||
|
if success:
|
||||||
|
print(f" ✅ {platform}: {message}")
|
||||||
|
found_any = True
|
||||||
|
else:
|
||||||
|
print(f" ⬜ {platform}: {message}")
|
||||||
|
|
||||||
|
print()
|
||||||
|
if found_any:
|
||||||
|
print("✅ Cookies configured! Run `agent-eyes doctor` to see updated status.")
|
||||||
|
else:
|
||||||
|
print(f"No cookies found. Make sure you're logged into the platforms in {browser}.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# ── Manual configure ──
|
||||||
|
if not args.key:
|
||||||
|
print("Usage: agent-eyes configure <key> <value>")
|
||||||
|
print(" or: agent-eyes configure --from-browser chrome")
|
||||||
|
return
|
||||||
|
|
||||||
|
value = " ".join(args.value) if args.value else ""
|
||||||
|
if not value:
|
||||||
|
print(f"Missing value for {args.key}")
|
||||||
|
return
|
||||||
|
|
||||||
if args.key == "proxy":
|
if args.key == "proxy":
|
||||||
config.set("reddit_proxy", value)
|
config.set("reddit_proxy", value)
|
||||||
|
|||||||
@@ -0,0 +1,166 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""Auto-extract cookies from local browsers for all supported platforms.
|
||||||
|
|
||||||
|
Supports: Chrome, Firefox, Edge, Brave, Opera
|
||||||
|
Extracts: Twitter, XiaoHongShu, Bilibili cookies in one shot.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
agent-eyes configure --from-browser chrome
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from typing import Dict, List, Optional, Tuple
|
||||||
|
|
||||||
|
|
||||||
|
# Platform cookie specs: (platform_name, domain_pattern, needed_cookies)
|
||||||
|
PLATFORM_SPECS = [
|
||||||
|
{
|
||||||
|
"name": "Twitter/X",
|
||||||
|
"domains": [".x.com", ".twitter.com"],
|
||||||
|
"cookies": ["auth_token", "ct0"],
|
||||||
|
"config_key": "twitter",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "XiaoHongShu",
|
||||||
|
"domains": [".xiaohongshu.com"],
|
||||||
|
"cookies": None, # None = grab all cookies as header string
|
||||||
|
"config_key": "xhs",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Bilibili",
|
||||||
|
"domains": [".bilibili.com"],
|
||||||
|
"cookies": ["SESSDATA", "bili_jct"],
|
||||||
|
"config_key": "bilibili",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def extract_all(browser: str = "chrome") -> Dict[str, dict]:
|
||||||
|
"""
|
||||||
|
Extract cookies for all supported platforms from the specified browser.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
{
|
||||||
|
"twitter": {"auth_token": "xxx", "ct0": "yyy"},
|
||||||
|
"xhs": {"cookie_string": "a=1; b=2; ..."},
|
||||||
|
"bilibili": {"SESSDATA": "xxx", "bili_jct": "yyy"},
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
import browser_cookie3
|
||||||
|
except ImportError:
|
||||||
|
raise RuntimeError(
|
||||||
|
"browser_cookie3 not installed. Run: pip install browser-cookie3"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Get browser cookie jar
|
||||||
|
browser_funcs = {
|
||||||
|
"chrome": browser_cookie3.chrome,
|
||||||
|
"firefox": browser_cookie3.firefox,
|
||||||
|
"edge": browser_cookie3.edge,
|
||||||
|
"brave": browser_cookie3.brave,
|
||||||
|
"opera": browser_cookie3.opera,
|
||||||
|
}
|
||||||
|
|
||||||
|
browser = browser.lower()
|
||||||
|
if browser not in browser_funcs:
|
||||||
|
raise ValueError(
|
||||||
|
f"Unsupported browser: {browser}. "
|
||||||
|
f"Supported: {', '.join(browser_funcs.keys())}"
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
cookie_jar = browser_funcs[browser]()
|
||||||
|
except Exception as e:
|
||||||
|
raise RuntimeError(
|
||||||
|
f"Could not read {browser} cookies: {e}\n"
|
||||||
|
f"Make sure {browser} is closed and you have permission to read its data."
|
||||||
|
)
|
||||||
|
|
||||||
|
results = {}
|
||||||
|
|
||||||
|
for spec in PLATFORM_SPECS:
|
||||||
|
platform_cookies = {}
|
||||||
|
all_cookies_for_domain = []
|
||||||
|
|
||||||
|
for cookie in cookie_jar:
|
||||||
|
# Check if cookie belongs to this platform
|
||||||
|
domain_match = any(
|
||||||
|
cookie.domain.endswith(d) or cookie.domain == d.lstrip(".")
|
||||||
|
for d in spec["domains"]
|
||||||
|
)
|
||||||
|
if not domain_match:
|
||||||
|
continue
|
||||||
|
|
||||||
|
all_cookies_for_domain.append(cookie)
|
||||||
|
|
||||||
|
if spec["cookies"] is not None:
|
||||||
|
if cookie.name in spec["cookies"]:
|
||||||
|
platform_cookies[cookie.name] = cookie.value
|
||||||
|
|
||||||
|
if spec["cookies"] is None:
|
||||||
|
# Grab all as header string
|
||||||
|
if all_cookies_for_domain:
|
||||||
|
cookie_str = "; ".join(
|
||||||
|
f"{c.name}={c.value}" for c in all_cookies_for_domain
|
||||||
|
)
|
||||||
|
results[spec["config_key"]] = {"cookie_string": cookie_str}
|
||||||
|
else:
|
||||||
|
if platform_cookies:
|
||||||
|
results[spec["config_key"]] = platform_cookies
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
|
|
||||||
|
def configure_from_browser(browser: str, config) -> List[Tuple[str, bool, str]]:
|
||||||
|
"""
|
||||||
|
Extract cookies and configure all found platforms.
|
||||||
|
|
||||||
|
Returns list of (platform_name, success, message) tuples.
|
||||||
|
"""
|
||||||
|
results_list = []
|
||||||
|
|
||||||
|
try:
|
||||||
|
extracted = extract_all(browser)
|
||||||
|
except Exception as e:
|
||||||
|
return [("Browser", False, str(e))]
|
||||||
|
|
||||||
|
if not extracted:
|
||||||
|
return [("All platforms", False,
|
||||||
|
f"No platform cookies found in {browser}. "
|
||||||
|
f"Make sure you're logged into Twitter, XiaoHongShu, etc. in {browser}.")]
|
||||||
|
|
||||||
|
# Configure each found platform
|
||||||
|
if "twitter" in extracted:
|
||||||
|
tc = extracted["twitter"]
|
||||||
|
if "auth_token" in tc and "ct0" in tc:
|
||||||
|
config.set("twitter_auth_token", tc["auth_token"])
|
||||||
|
config.set("twitter_ct0", tc["ct0"])
|
||||||
|
results_list.append(("Twitter/X", True, "auth_token + ct0"))
|
||||||
|
else:
|
||||||
|
found = ", ".join(tc.keys())
|
||||||
|
missing = [k for k in ["auth_token", "ct0"] if k not in tc]
|
||||||
|
results_list.append(("Twitter/X", False,
|
||||||
|
f"Found {found}, but missing: {', '.join(missing)}. "
|
||||||
|
f"Make sure you're logged into x.com in {browser}."))
|
||||||
|
|
||||||
|
if "xhs" in extracted:
|
||||||
|
cookie_str = extracted["xhs"].get("cookie_string", "")
|
||||||
|
if cookie_str:
|
||||||
|
config.set("xhs_cookie", cookie_str)
|
||||||
|
n_cookies = len(cookie_str.split(";"))
|
||||||
|
results_list.append(("XiaoHongShu", True, f"{n_cookies} cookies"))
|
||||||
|
|
||||||
|
if "bilibili" in extracted:
|
||||||
|
bc = extracted["bilibili"]
|
||||||
|
if "SESSDATA" in bc:
|
||||||
|
config.set("bilibili_sessdata", bc["SESSDATA"])
|
||||||
|
if "bili_jct" in bc:
|
||||||
|
config.set("bilibili_csrf", bc["bili_jct"])
|
||||||
|
results_list.append(("Bilibili", True, "SESSDATA" +
|
||||||
|
(" + bili_jct" if "bili_jct" in bc else "")))
|
||||||
|
else:
|
||||||
|
results_list.append(("Bilibili", False,
|
||||||
|
f"No SESSDATA found. Make sure you're logged into bilibili.com in {browser}."))
|
||||||
|
|
||||||
|
return results_list
|
||||||
+43
-71
@@ -12,7 +12,7 @@ Install Agent Eyes: https://raw.githubusercontent.com/Panniantong/agent-eyes/mai
|
|||||||
|
|
||||||
## For AI Agents
|
## For AI Agents
|
||||||
|
|
||||||
Install Agent Eyes and set it up for the user. Minimize friction — ask as few questions as possible.
|
Install Agent Eyes and set it up with minimal user effort.
|
||||||
|
|
||||||
### Step 1: Install and check
|
### Step 1: Install and check
|
||||||
|
|
||||||
@@ -21,103 +21,75 @@ pip install git+https://github.com/Panniantong/agent-eyes.git || pip3 install gi
|
|||||||
agent-eyes install --env=auto
|
agent-eyes install --env=auto
|
||||||
```
|
```
|
||||||
|
|
||||||
That's it. This installs the package, auto-detects the environment, and shows what's working.
|
### Step 2: One-click cookie import (LOCAL COMPUTERS ONLY)
|
||||||
|
|
||||||
### Step 2: Tell user what's ready + offer ONE upgrade
|
If the environment was detected as **local**, offer to grab all cookies at once:
|
||||||
|
|
||||||
Tell the user what already works, then offer the single highest-value upgrade:
|
> "I can automatically import your cookies from Chrome to unlock Twitter, XiaoHongShu, and Bilibili — all at once, one command. Want me to do that?
|
||||||
|
> (Make sure Chrome is closed first)"
|
||||||
|
|
||||||
> "✅ Agent Eyes installed! Here's what I can already do:
|
If yes:
|
||||||
> - Read web pages, GitHub repos, RSS feeds, YouTube transcripts
|
```bash
|
||||||
> - Read individual tweets
|
pip install browser-cookie3
|
||||||
>
|
agent-eyes configure --from-browser chrome
|
||||||
> **Want me to unlock search too?** One free API key lets me search the entire web, Reddit, and Twitter for you.
|
```
|
||||||
> Just go to https://exa.ai → sign up (free, 1000 searches/month) → send me the API key.
|
|
||||||
>
|
|
||||||
> Or say 'skip' and I'm ready to use as-is."
|
|
||||||
|
|
||||||
If the user provides a key:
|
This extracts cookies for ALL supported platforms in one shot. No F12, no manual copying.
|
||||||
|
|
||||||
|
If user uses a different browser:
|
||||||
|
```bash
|
||||||
|
agent-eyes configure --from-browser firefox # or edge, brave, opera
|
||||||
|
```
|
||||||
|
|
||||||
|
If the environment is **server** or the user declines, skip to Step 3.
|
||||||
|
|
||||||
|
### Step 3: Offer search upgrade
|
||||||
|
|
||||||
|
> "Want to unlock web search? One free API key lets me search the entire web, Reddit, and Twitter.
|
||||||
|
> → Go to https://exa.ai → sign up (free) → send me the API key.
|
||||||
|
> Or say 'skip'."
|
||||||
|
|
||||||
|
If user provides key:
|
||||||
```bash
|
```bash
|
||||||
agent-eyes configure exa-key THE_KEY
|
agent-eyes configure exa-key THE_KEY
|
||||||
```
|
```
|
||||||
|
|
||||||
If the user says skip, move to Step 4.
|
### Step 4: Server-only — offer proxy
|
||||||
|
|
||||||
### Step 3: Offer additional channels
|
Only if auto-detected as server:
|
||||||
|
|
||||||
After Exa is configured (or skipped), briefly mention what else is available:
|
> "Reddit and Bilibili block server IPs. Reddit search still works free via Exa, but for full access you'd need a cheap proxy ($1/month).
|
||||||
|
> → Get one at https://webshare.io if interested. Or skip — search still works!"
|
||||||
> "I can also unlock these with cookies from your browser (2 min each):
|
|
||||||
> 🐦 **Twitter** deep search — timelines, threads, advanced search
|
|
||||||
> 📕 **XiaoHongShu** — read notes and comments
|
|
||||||
>
|
|
||||||
> Want any of these? Or say 'done' and we're good to go."
|
|
||||||
|
|
||||||
Only proceed with channels the user explicitly asks for.
|
|
||||||
|
|
||||||
#### How to get cookies (for any platform)
|
|
||||||
|
|
||||||
When the user wants to set up a cookie-based channel, give them the SIMPLEST method:
|
|
||||||
|
|
||||||
**Method 1 — Browser extension (easiest):**
|
|
||||||
> "Install the 'Cookie-Editor' extension for Chrome/Firefox (free). Open [the site], click the extension icon, click 'Export' → 'Header String'. Paste it to me."
|
|
||||||
|
|
||||||
**Method 2 — Manual (if they don't want to install an extension):**
|
|
||||||
> "Open [the site] in Chrome. Press F12. Click 'Application' tab at the top. Click 'Cookies' on the left. Find and copy the values I need."
|
|
||||||
|
|
||||||
#### Twitter setup
|
|
||||||
Cookie-Editor export, or manually copy **auth_token** and **ct0** from x.com cookies.
|
|
||||||
```bash
|
|
||||||
agent-eyes configure twitter-cookies AUTH_TOKEN CT0
|
|
||||||
```
|
|
||||||
|
|
||||||
#### XiaoHongShu setup
|
|
||||||
Cookie-Editor export the full cookie string from xiaohongshu.com.
|
|
||||||
```bash
|
|
||||||
agent-eyes configure xhs-cookie COOKIE_STRING
|
|
||||||
```
|
|
||||||
|
|
||||||
#### YouTube (only mention if user has age-restricted video needs)
|
|
||||||
No cookies needed for public videos. For age-restricted/member content:
|
|
||||||
```bash
|
|
||||||
agent-eyes configure youtube-cookies chrome
|
|
||||||
```
|
|
||||||
(yt-dlp reads cookies directly from the browser — just tell it which browser)
|
|
||||||
|
|
||||||
#### Bilibili
|
|
||||||
- Local computer: already works
|
|
||||||
- Server: needs proxy (see below)
|
|
||||||
|
|
||||||
#### Reddit full reader + Bilibili on server
|
|
||||||
Only offer this if `agent-eyes install` detected server environment:
|
|
||||||
> "Reddit and Bilibili block server IPs. Reddit search already works (via Exa), but for reading full posts you'd need a $1/month proxy from https://webshare.io. Want to set that up?"
|
|
||||||
|
|
||||||
|
If user provides proxy:
|
||||||
```bash
|
```bash
|
||||||
agent-eyes configure proxy http://user:pass@ip:port
|
agent-eyes configure proxy http://user:pass@ip:port
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 4: Done
|
### Step 5: Done
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
agent-eyes doctor
|
agent-eyes doctor
|
||||||
```
|
```
|
||||||
|
|
||||||
Summarize naturally:
|
> "✅ All set! [list what's active]. Try asking me to search or read something!"
|
||||||
> "✅ Ready! Here's everything I can do: [list channels]. Try asking me to search or read something!"
|
|
||||||
|
|
||||||
**Remember**: the user can always come back and say "set up Twitter" or "add a proxy" later. You just run the corresponding `agent-eyes configure` command.
|
**Users can always configure more later** by saying things like "set up Twitter for Agent Eyes" or "add my XiaoHongShu cookies".
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Quick Reference
|
## Manual configure (one channel at a time)
|
||||||
|
|
||||||
|
These commands are for manual setup or adding individual channels later:
|
||||||
|
|
||||||
| Command | What it does |
|
| Command | What it does |
|
||||||
|---------|-------------|
|
|---------|-------------|
|
||||||
| `agent-eyes doctor` | Show all channels and status |
|
| `agent-eyes configure --from-browser chrome` | Import ALL cookies at once |
|
||||||
| `agent-eyes configure exa-key KEY` | Unlock search (web + Reddit + Twitter) |
|
| `agent-eyes configure exa-key KEY` | Unlock search (web + Reddit + Twitter) |
|
||||||
| `agent-eyes configure twitter-cookies TOKEN CT0` | Unlock Twitter deep search |
|
| `agent-eyes configure twitter-cookies TOKEN CT0` | Twitter deep search (manual) |
|
||||||
| `agent-eyes configure xhs-cookie COOKIE` | Unlock XiaoHongShu |
|
| `agent-eyes configure xhs-cookie COOKIE` | XiaoHongShu (manual) |
|
||||||
| `agent-eyes configure youtube-cookies BROWSER` | Unlock age-restricted YouTube |
|
| `agent-eyes configure youtube-cookies chrome` | Age-restricted YouTube |
|
||||||
| `agent-eyes configure proxy URL` | Unlock Reddit reader + Bilibili (server) |
|
| `agent-eyes configure proxy URL` | Reddit + Bilibili on servers |
|
||||||
|
| `agent-eyes doctor` | Show all channels and status |
|
||||||
| `agent-eyes read URL` | Read any URL |
|
| `agent-eyes read URL` | Read any URL |
|
||||||
| `agent-eyes search "query"` | Search the web |
|
| `agent-eyes search "query"` | Search the web |
|
||||||
|
|||||||
+2
-1
@@ -30,8 +30,9 @@ dependencies = [
|
|||||||
|
|
||||||
[project.optional-dependencies]
|
[project.optional-dependencies]
|
||||||
browser = ["playwright>=1.40"]
|
browser = ["playwright>=1.40"]
|
||||||
|
cookies = ["browser-cookie3>=0.19"]
|
||||||
mcp = ["mcp[cli]>=1.0"]
|
mcp = ["mcp[cli]>=1.0"]
|
||||||
all = ["playwright>=1.40", "mcp[cli]>=1.0"]
|
all = ["playwright>=1.40", "mcp[cli]>=1.0", "browser-cookie3>=0.19"]
|
||||||
|
|
||||||
[project.scripts]
|
[project.scripts]
|
||||||
agent-eyes = "agent_eyes.cli:main"
|
agent-eyes = "agent_eyes.cli:main"
|
||||||
|
|||||||
Reference in New Issue
Block a user