From 1ac06c1bbe8180905724b9c79e526c679bfa6734 Mon Sep 17 00:00:00 2001 From: Muhammad Aizat Date: Fri, 11 Sep 2026 10:18:38 +0800 Subject: [PATCH] v0.3: dashboard local mode, openbridge tab reuse, tab activation fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - dashboard.html: local dashboard.json mode (10s poll) alongside artifact db mode; clickable cards behind an http(s)-only safeUrl filter; meta charset; mode-aware freshness line - openbridge.py: localhost shim exposing open_link so dashboard clicks reuse the platform's warm tab instead of spawning one per click - cdp.py: Tab.activate(); get_or_open_tab activates reused tabs — a backgrounded tab never finishes rendering, which made YouTube's login check read a signed-in account as signed out - README/MANIFEST: corrected CDP port (9336, was documented as 9222), removed the false claim that the server writes dashboard.json, documented the reboot/VPS requirements - .gitignore: __pycache__/, *.pyc, state.json, Archived/; removed stale tracked pycache and state.json from index --- .gitignore | 4 + MANIFEST.md | 137 ++++++++--- README.md | 181 ++++++++++++++- __pycache__/__init__.cpython-314.pyc | Bin 765 -> 0 bytes __pycache__/__main__.cpython-314.pyc | Bin 456 -> 0 bytes __pycache__/cdp.cpython-314.pyc | Bin 25344 -> 0 bytes __pycache__/queue.cpython-314.pyc | Bin 5689 -> 0 bytes __pycache__/selectors.cpython-314.pyc | Bin 5028 -> 0 bytes __pycache__/server.cpython-314.pyc | Bin 15112 -> 0 bytes cdp.py | 19 +- dashboard.html | 215 ++++++++++++++++-- dashboard.json | 90 ++++++++ openbridge.py | 134 +++++++++++ .../__pycache__/__init__.cpython-314.pyc | Bin 3531 -> 0 bytes .../__pycache__/facebook.cpython-314.pyc | Bin 5320 -> 0 bytes .../__pycache__/instagram.cpython-314.pyc | Bin 6884 -> 0 bytes platforms/__pycache__/threads.cpython-314.pyc | Bin 6601 -> 0 bytes platforms/__pycache__/tiktok.cpython-314.pyc | Bin 7715 -> 0 bytes platforms/__pycache__/youtube.cpython-314.pyc | Bin 6405 -> 0 bytes state.json | 11 - 20 files changed, 719 insertions(+), 72 deletions(-) create mode 100644 .gitignore delete mode 100644 __pycache__/__init__.cpython-314.pyc delete mode 100644 __pycache__/__main__.cpython-314.pyc delete mode 100644 __pycache__/cdp.cpython-314.pyc delete mode 100644 __pycache__/queue.cpython-314.pyc delete mode 100644 __pycache__/selectors.cpython-314.pyc delete mode 100644 __pycache__/server.cpython-314.pyc create mode 100644 dashboard.json create mode 100644 openbridge.py delete mode 100644 platforms/__pycache__/__init__.cpython-314.pyc delete mode 100644 platforms/__pycache__/facebook.cpython-314.pyc delete mode 100644 platforms/__pycache__/instagram.cpython-314.pyc delete mode 100644 platforms/__pycache__/threads.cpython-314.pyc delete mode 100644 platforms/__pycache__/tiktok.cpython-314.pyc delete mode 100644 platforms/__pycache__/youtube.cpython-314.pyc delete mode 100644 state.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cc00901 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +__pycache__/ +*.pyc +state.json +Archived/ diff --git a/MANIFEST.md b/MANIFEST.md index 53d2bec..f5b9508 100644 --- a/MANIFEST.md +++ b/MANIFEST.md @@ -1,39 +1,50 @@ # socialmag — Social Media MCP Server -**One tool, all platforms.** Post to Threads, Facebook, Instagram, TikTok (and YouTube when eligible) through a single MCP call. Built on CDP — no API keys, no rate limits, no approval process. Just a browser and a logged-in account. +**One tool, all platforms.** Post to Threads, Facebook, Instagram, TikTok, Twitter/X (and YouTube when eligible) through a single MCP call. Built on CDP — no API keys, no rate limits, no approval process. Just a browser and a logged-in account. ## What It Does +**Write** - **`create_post`** — Post text/media to one or more platforms in one call +- **`reply_tweet`** — Reply to a tweet found by search + +**Read** - **`check_login`** — Verify which platforms are logged in - **`get_status`** — Last post results + open browser tabs +- **`get_feed`** — Twitter timeline or search, with X operators (`from:`, `min_faves:`, …) +- **`get_notifications`** — Platform activity (Threads) + +**Navigate** +- **`open_link`** — Send a platform's existing tab to a URL, instead of spawning a new one ## Architecture ``` -Claude/MCP Client - ↓ stdio (JSON-RPC) -socialmag server.py +Claude/MCP Client dashboard.html (browser) + ↓ stdio (JSON-RPC) ↓ fetch (localhost) +socialmag server.py ←────────────── openbridge.py :8322 ↓ CDP WebSocket Brave Browser (dedicated instance, port 9336) ↓ real browser sessions -Threads · Facebook · Instagram · TikTok · YouTube +Threads · Facebook · Instagram · TikTok · YouTube · Twitter/X ``` - **Tab reuse** — attaches to existing tabs, no cold loads +- **Tab activation** — a reused tab is brought to the front, because a backgrounded tab is not guaranteed to have rendered (see *Journey*) - **Per-platform modules** — each platform has its own flow + selectors - **Sequential queue** — one platform at a time, no race conditions - **Error screenshots** — failed flows capture the page state to `/tmp/socialmag/` ## Platform Status -| Platform | Text | Media | Tab Reuse | Status | -|----------|:----:|:-----:|:---------:|--------| -| Threads | ✅ | 🔲 | ✅ | **Live** — inline composer | -| Facebook | ✅ | 🔲 | ✅ | **Live** — dialog flow | -| Instagram | — | ✅ | ✅ | **Live** — media required | -| TikTok | — | ✅ | ✅ | **Live** — video/photo upload | -| YouTube | 🔲 | 🔲 | ✅ | **Parked** — needs 500 subs | +| Platform | Text | Media | Read | Status | +|----------|:----:|:-----:|:----:|--------| +| Threads | ✅ | 🔲 | ✅ | **Live** — inline composer + activity scraping | +| Facebook | ✅ | 🔲 | — | **Live** — dialog flow | +| Instagram | — | ✅ | — | **Live** — media required | +| TikTok | — | ✅ | — | **Live** — video/photo upload | +| Twitter/X | ✅ | 🔲 | ✅ | **Live** — post, reply, timeline + search | +| YouTube | 🔲 | 🔲 | — | **Parked** — needs 500 subs | ✅ = tested live · 🔲 = coded but untested · — = not applicable @@ -56,33 +67,86 @@ brave --remote-debugging-port=9336 \ Log into each platform manually once. socialmag reuses those sessions. -## Future Roadmap +--- -### v0.2 — Read Side -- [ ] `get_notifications(platform)` — pull notifications via CDP scraping -- [ ] `get_comments(platform, post_id?)` — read comments on recent posts -- [ ] `get_engagement(platform)` — likes, shares, reach per post +## Journey So Far -### v0.3 — Monitoring -- [ ] Cron/loop polling — periodic checks, dump to JSON +### v0.1 — 2026-09-10 · it posts +Five platforms coded, four live. Threads, Facebook, Instagram, TikTok posting +through a real logged-in browser. YouTube parked behind its 500-subscriber gate. +First automated post from the house went out that night. + +### v0.2 — 2026-09-11 (early hours) · it reads +Twitter/X joined as a full module — post, reply, timeline, search. +`get_notifications` landed for Threads. `open_link` built for warm-tab reuse. +Pushed to a private GitHub repo. + +**What the read side cost that the plan didn't predict:** +- The Threads scraper was believed to already return a post `link`. It did not — + it returned `{text}` only. Row detection had to be built from the live DOM. The + rule that worked: *a row is an element that links somewhere, carries a + relative-time marker, and contains no smaller element that does the same.* +- A tweet's permalink is **not** "the first `/status/` href" — an article carries + three (canonical, `/analytics`, `/photo/N`). It's the anchor wrapping `