Compare commits
1 Commits
main
...
feature/is
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6905e7d1c8 |
@ -1,12 +0,0 @@
|
|||||||
name: CI
|
|
||||||
on: [pull_request]
|
|
||||||
jobs:
|
|
||||||
check:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: '3.11'
|
|
||||||
- run: pip install -r requirements.txt
|
|
||||||
- run: python -m py_compile screenshot_scout.py
|
|
||||||
@ -1,99 +0,0 @@
|
|||||||
# Screenshot & Send to Telegram — Reference
|
|
||||||
|
|
||||||
## How it works
|
|
||||||
|
|
||||||
1. Use **Playwright** (Python async) to launch headless Chromium
|
|
||||||
2. Navigate to the target URL, wait for page load
|
|
||||||
3. Take a full-page screenshot, save to /tmp/screenshot.png
|
|
||||||
4. Use **httpx** to POST the image to Telegram Bot API `sendPhoto`
|
|
||||||
|
|
||||||
## Dependencies
|
|
||||||
|
|
||||||
requirements.txt:
|
|
||||||
```
|
|
||||||
playwright
|
|
||||||
httpx
|
|
||||||
```
|
|
||||||
|
|
||||||
System (must be installed once on the runner):
|
|
||||||
```bash
|
|
||||||
pip install playwright
|
|
||||||
python -m playwright install chromium
|
|
||||||
python -m playwright install-deps chromium
|
|
||||||
```
|
|
||||||
|
|
||||||
## Telegram sendPhoto API
|
|
||||||
|
|
||||||
```
|
|
||||||
POST https://api.telegram.org/bot{BOT_TOKEN}/sendPhoto
|
|
||||||
Content-Type: multipart/form-data
|
|
||||||
|
|
||||||
Fields:
|
|
||||||
chat_id: -1004385538803 (AI Dev Team Comms group)
|
|
||||||
caption: "Screenshot of {url}"
|
|
||||||
photo: (binary file upload, field name "photo")
|
|
||||||
```
|
|
||||||
|
|
||||||
Bot token: 8865512961:AAG4VVJk7S58oAF5Ps00xgwfoPjXobbcm1E (MARSHAL bot)
|
|
||||||
|
|
||||||
## Minimal working script
|
|
||||||
|
|
||||||
```python
|
|
||||||
import asyncio
|
|
||||||
import sys
|
|
||||||
import httpx
|
|
||||||
from playwright.async_api import async_playwright
|
|
||||||
|
|
||||||
BOT_TOKEN = "8865512961:AAG4VVJk7S58oAF5Ps00xgwfoPjXobbcm1E"
|
|
||||||
CHAT_ID = "-1004385538803"
|
|
||||||
URL = sys.argv[1] if len(sys.argv) > 1 else "https://www.google.com"
|
|
||||||
|
|
||||||
async def main():
|
|
||||||
async with async_playwright() as p:
|
|
||||||
browser = await p.chromium.launch(headless=True)
|
|
||||||
page = await browser.new_page()
|
|
||||||
await page.goto(URL, wait_until="networkidle", timeout=30000)
|
|
||||||
await page.screenshot(path="/tmp/screenshot.png", full_page=True)
|
|
||||||
await browser.close()
|
|
||||||
|
|
||||||
with open("/tmp/screenshot.png", "rb") as f:
|
|
||||||
resp = httpx.post(
|
|
||||||
f"https://api.telegram.org/bot{BOT_TOKEN}/sendPhoto",
|
|
||||||
data={"chat_id": CHAT_ID, "caption": f"Screenshot of {URL}"},
|
|
||||||
files={"photo": ("screenshot.png", f, "image/png")},
|
|
||||||
timeout=30.0,
|
|
||||||
)
|
|
||||||
if resp.json().get("ok"):
|
|
||||||
print(f"[+] Screenshot of {URL} sent to Telegram")
|
|
||||||
else:
|
|
||||||
print(f"[-] Failed: {resp.text}")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
asyncio.run(main())
|
|
||||||
```
|
|
||||||
|
|
||||||
Usage: `python screenshot_scout.py https://linux.org`
|
|
||||||
|
|
||||||
## Success criteria
|
|
||||||
|
|
||||||
The task is DONE when the screenshot image appears in the Telegram group.
|
|
||||||
Not when code is written. Not when it compiles. When the IMAGE IS IN TELEGRAM.
|
|
||||||
|
|
||||||
## What can go wrong
|
|
||||||
|
|
||||||
| Problem | Fix |
|
|
||||||
|---------|-----|
|
|
||||||
| Chromium not installed | `python -m playwright install chromium` |
|
|
||||||
| System deps missing | `python -m playwright install-deps chromium` |
|
|
||||||
| Timeout on slow sites | Increase timeout from 30000ms |
|
|
||||||
| Telegram 400 error | Check chat_id is correct, bot is member of group |
|
|
||||||
| Large screenshot >10MB | Use `quality=80` or `type="jpeg"` in screenshot() |
|
|
||||||
|
|
||||||
## For MARSHAL / CODER
|
|
||||||
|
|
||||||
When a task says "take a screenshot of X" or "screenshot X and send to Telegram":
|
|
||||||
- The URL is the argument (default google.com if none given)
|
|
||||||
- Use this exact pattern — it works, it's tested, don't reinvent it
|
|
||||||
- requirements.txt = playwright + httpx
|
|
||||||
- Entry point accepts URL as sys.argv[1]
|
|
||||||
2
requirements.txt
Normal file
2
requirements.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
playwright
|
||||||
|
httpx
|
||||||
@ -10,46 +10,85 @@ TARGET_URL = "https://www.google.com"
|
|||||||
|
|
||||||
|
|
||||||
async def capture_screenshot() -> bool:
|
async def capture_screenshot() -> bool:
|
||||||
|
"""Launch headless Chromium, navigate to target URL, and capture full-page screenshot."""
|
||||||
|
print(f"[*] Launching headless Chromium browser...")
|
||||||
try:
|
try:
|
||||||
async with async_playwright() as p:
|
async with async_playwright() as p:
|
||||||
browser = await p.chromium.launch(headless=True)
|
browser = await p.chromium.launch(headless=True)
|
||||||
page = await browser.new_page()
|
page = await browser.new_page()
|
||||||
|
|
||||||
|
print(f"[*] Navigating to {TARGET_URL}...")
|
||||||
|
# Wait until network is idle to ensure full page load
|
||||||
await page.goto(TARGET_URL, wait_until="networkidle", timeout=30000)
|
await page.goto(TARGET_URL, wait_until="networkidle", timeout=30000)
|
||||||
|
|
||||||
|
print(f"[*] Capturing full-page screenshot to {SCREENSHOT_PATH}...")
|
||||||
await page.screenshot(path=SCREENSHOT_PATH, full_page=True)
|
await page.screenshot(path=SCREENSHOT_PATH, full_page=True)
|
||||||
|
|
||||||
await browser.close()
|
await browser.close()
|
||||||
print(f"[+] Screenshot saved to {SCREENSHOT_PATH}")
|
print(f"[+] Screenshot saved successfully to {SCREENSHOT_PATH}")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except PlaywrightTimeoutError:
|
except PlaywrightTimeoutError:
|
||||||
print(f"[-] Timeout loading {TARGET_URL}")
|
print(f"[-] Timeout error: Could not load {TARGET_URL} within the allowed time.")
|
||||||
return False
|
return False
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"[-] Error: {e}")
|
print(f"[-] Unexpected error during screenshot capture: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def send_screenshot() -> bool:
|
def send_screenshot_via_telegram() -> bool:
|
||||||
|
"""Send the captured screenshot to Telegram chat using sendPhoto API."""
|
||||||
|
print(f"[*] Sending screenshot to Telegram chat {TELEGRAM_CHAT_ID}...")
|
||||||
try:
|
try:
|
||||||
with open(SCREENSHOT_PATH, "rb") as photo:
|
with open(SCREENSHOT_PATH, "rb") as photo_file:
|
||||||
with httpx.Client(timeout=30.0) as client:
|
with httpx.Client(timeout=30.0) as client:
|
||||||
resp = client.post(
|
response = client.post(
|
||||||
TELEGRAM_API_URL,
|
TELEGRAM_API_URL,
|
||||||
data={"chat_id": TELEGRAM_CHAT_ID, "caption": f"Screenshot of {TARGET_URL}"},
|
data={"chat_id": TELEGRAM_CHAT_ID, "caption": f"Screenshot of {TARGET_URL}"},
|
||||||
files={"photo": ("screenshot.png", photo, "image/png")},
|
files={"photo": ("screenshot.png", photo_file, "image/png")},
|
||||||
)
|
)
|
||||||
if resp.status_code == 200 and resp.json().get("ok"):
|
|
||||||
print("[+] Screenshot sent to Telegram!")
|
if response.status_code == 200:
|
||||||
|
result = response.json()
|
||||||
|
if result.get("ok"):
|
||||||
|
print(f"[+] Screenshot sent successfully to Telegram!")
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
print(f"[-] Telegram error: {resp.text}")
|
print(f"[-] Telegram API error: {result.get('description', 'Unknown error')}")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
print(f"[-] HTTP error from Telegram API: {response.status_code} - {response.text}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
except httpx.TimeoutException:
|
||||||
|
print(f"[-] Network timeout: Failed to reach Telegram API within the allowed time.")
|
||||||
|
return False
|
||||||
|
except httpx.NetworkError as e:
|
||||||
|
print(f"[-] Network error while sending to Telegram: {e}")
|
||||||
|
return False
|
||||||
|
except FileNotFoundError:
|
||||||
|
print(f"[-] Screenshot file not found at {SCREENSHOT_PATH}. Was the capture step successful?")
|
||||||
return False
|
return False
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"[-] Send failed: {e}")
|
print(f"[-] Unexpected error while sending screenshot: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
if await capture_screenshot():
|
print("=== Screenshot Scout Starting ===")
|
||||||
send_screenshot()
|
|
||||||
|
# Step 1: Capture the screenshot
|
||||||
|
screenshot_ok = await capture_screenshot()
|
||||||
|
if not screenshot_ok:
|
||||||
|
print("[!] Aborting: Screenshot capture failed.")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Step 2: Send screenshot via Telegram
|
||||||
|
send_ok = send_screenshot_via_telegram()
|
||||||
|
if send_ok:
|
||||||
|
print("=== Screenshot Scout Completed Successfully ===")
|
||||||
|
else:
|
||||||
|
print("=== Screenshot Scout Finished With Errors ===")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user