socialmag v0.1 — 4/5 platforms live (Threads, FB, IG, TikTok)
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
# socialmag
|
||||
|
||||
MCP server that posts to Threads / Facebook / Instagram / YouTube / TikTok by
|
||||
driving abang's already-logged-in Brave over CDP. No API keys, no OAuth.
|
||||
|
||||
Built to `PROPOSAL.md` (2026-09-10). **Nothing here has been run against a live
|
||||
platform yet** — every step whose selector or timing needs a real page is
|
||||
marked `# TODO: VALIDATE LIVE`.
|
||||
|
||||
## Run
|
||||
|
||||
```bash
|
||||
cd /mnt/playground/Playground_V2
|
||||
python3 -m socialmag # stdio MCP server, logs to stderr
|
||||
```
|
||||
|
||||
⚠️ **Must run as a package.** `python3 socialmag/server.py` puts the package
|
||||
dir first on `sys.path`, where `selectors.py` and `queue.py` shadow the stdlib
|
||||
modules `asyncio` imports — asyncio then dies at import with
|
||||
`module 'selectors' has no attribute 'SelectSelector'`. Run `-m`.
|
||||
|
||||
Brave must be listening on `http://127.0.0.1:9222`. Override with
|
||||
`SOCIALMAG_CDP_ENDPOINT`.
|
||||
|
||||
Requires `websockets` (17.1 present on this box). Everything else is stdlib.
|
||||
|
||||
## Tools
|
||||
|
||||
| Tool | Args | Returns |
|
||||
|---|---|---|
|
||||
| `create_post` | `platforms[]`, `text`, `media`, `visibility` | `{platform: {status, detail}}` |
|
||||
| `check_login` | `platforms[]` (default all) | `{platform: true/false/"error: ..."}` |
|
||||
| `get_status` | — | last run's results + queue history |
|
||||
|
||||
`text` is required for threads/fb/yt and used as the caption for ig/tiktok.
|
||||
`media` must be an **absolute path to an existing file**; it is required for
|
||||
ig/tiktok, optional for threads/fb, and rejected for yt.
|
||||
|
||||
## Layout
|
||||
|
||||
```
|
||||
server.py MCP stdio JSON-RPC loop + the 3 tools
|
||||
cdp.py CDP client: CDPClient (browser) + Tab (page verbs)
|
||||
queue.py PostQueue — strictly sequential, one tab at a time
|
||||
selectors.py every platform selector, one file
|
||||
platforms/ one module per platform: post() + check_login()
|
||||
```
|
||||
|
||||
Each platform module exposes:
|
||||
|
||||
```python
|
||||
async def post(cdp_client, text, media_path, options) -> {"status": ..., "detail": ...}
|
||||
async def check_login(cdp_client) -> bool
|
||||
```
|
||||
|
||||
`post` opens its own tab, drives the flow, closes the tab. A failure inside the
|
||||
flow is caught by `platforms.guard`, which screenshots the page as it actually
|
||||
looked into `/tmp/socialmag/` and puts the path in the result.
|
||||
|
||||
## House rules honoured
|
||||
|
||||
- **No silent fallbacks.** Missing media, missing text, an unknown platform, a
|
||||
selector that never appears, a CDP call that errors — all raise with the
|
||||
reason. Nothing picks a default and carries on.
|
||||
- Unmapped flows **refuse** rather than guess: Facebook `visibility` switching
|
||||
and YouTube media both raise, because clicking through an unmapped dialog
|
||||
outward-facing is worse than a stop.
|
||||
- Human-like delays (`random.uniform`) between every discrete action, longer on
|
||||
TikTok.
|
||||
|
||||
## Not built (out of the brief's scope)
|
||||
|
||||
- `post_youtube_video` (video upload) — the brief scoped yt to community posts.
|
||||
- `socialmag.service` — explicitly deferred until after live validation.
|
||||
- Scheduling, analytics, multi-account (proposal "Future").
|
||||
Reference in New Issue
Block a user