Skill: mcbaivn/facebook-management-skills-by-mcbai (version 1.0.0)

--- name: facebook-page-manager description: > Quản lý và đăng nội dung tự động lên Facebook Fanpage qua Graph API. Hỗ trợ đầy đủ: post text/ảnh, carousel (nhiều ảnh), video, Reels, Story (ảnh/video), hẹn giờ đăng bài (scheduled_publish_time), xem/sửa/xóa bài đã hẹn giờ, comment vào bài viết, reply comment, xóa comment. Dùng khi user yêu cầu "đăng bài lên Facebook Page", "hẹn giờ đăng Facebook", "upload video lên Fanpage", "đăng story Facebook", "carousel Facebook", "quản lý lịch đăng Facebook", "comment vào bài Facebook", "reply comment Facebook", hoặc bất kỳ thao tác post/manage nội dung trên Facebook Page. --- # Facebook Page Manager Skill đăng và quản lý nội dung Facebook Page qua **Graph API v19.0** bằng Python. ## Setup nhanh ### 1. Cài dependencies ```bash pip install requests ``` ### 2. Lấy Access Token Xem hướng dẫn chi tiết: `references/get-token.md` **Tóm tắt nhanh:** - Vào [Graph API Explorer](https://developers.facebook.com/tools/explorer/) - Tạo token với permissions: `pages_manage_posts`, `pages_read_engagement`, `pages_manage_engagement`, `publish_video` - Gọi `GET /me/accounts` để lấy **Page Access Token** và **Page ID** ### 3. Tạo config Tạo file `scripts/fb_config.json`: ```json { "access_token": "EAAxxxxxxxxxxxxxxx", "page_id": "123456789012345" } ``` > ⚠️ Thêm vào `.gitignore`, không commit file này! --- ## Script chính: `scripts/fb_post.py` ### Đăng text ```bash python fb_post.py text --message "Nội dung bài viết" ``` ### Đăng ảnh ```bash python fb_post.py photo --message "Caption" --images anh1.jpg ``` ### Carousel (nhiều ảnh) ```bash python fb_post.py photo --message "Caption" --images a.jpg b.jpg c.jpg ``` ### Video ```bash python fb_post.py video --message "Caption" --video clip.mp4 ``` ### Reels ```bash python fb_post.py video --message "Caption" --video clip.mp4 --reel ``` ### Story ảnh ```bash python fb_post.py story --type photo --media story.jpg ``` ### Story video ```bash python fb_post.py story --type video --media story.mp4 ``` --- ## Hẹn giờ đăng bài Thêm `--schedule "YYYY-MM-DD HH:MM"` vào bất kỳ lệnh text/photo/video: ```bash python fb_post.py text --message "Bài sáng thứ Hai" --schedule "2024-12-25 08:00" python fb_post.py photo --message "Caption" --images anh.jpg --schedule "2024-12-25 10:00" python fb_post.py video --message "Video mới" --video clip.mp4 --schedule "2024-12-25 20:00" ``` > ⏰ Thời gian phải sau hiện tại ít nhất **10 phút** và không quá **6 tháng**. > Story **không hỗ trợ** hẹn giờ. --- ## Quản lý lịch đăng ### Xem danh sách bài hẹn giờ ```bash python fb_post.py list-scheduled ``` ### Xóa bài ```bash python fb_post.py delete --post-id 123456789_987654321 ``` ### Đổi giờ đăng ```bash python fb_post.py reschedule --post-id 123456789_987654321 --schedule "2024-12-26 09:00" ``` --- ## Quản lý Comment > **Permission cần thêm:** `pages_manage_engagement` ### Comment vào bài viết ```bash python fb_post.py comment --post-id 123456789_987654321 --message "Nội dung comment" ``` ### Reply vào comment ```bash python fb_post.py reply --comment-id COMMENT_ID --message "Nội dung reply" ``` ### Xem danh sách comment của bài viết ```bash python fb_post.py list-comments --post-id 123456789_987654321 ``` ### Xóa comment ```bash python fb_post.py delete-comment --comment-id COMMENT_ID ``` --- ## References - `references/get-token.md` — Hướng dẫn lấy Access Token từng bước - `references/api-reference.md` — Chi tiết endpoints, format, giới hạn ## Lưu ý quan trọng - **Page phải ở trạng thái Published** (không phải Unpublished/Restricted) - **Video** upload có thể mất vài phút xử lý sau khi upload xong - **Carousel** tối đa 10 ảnh theo giới hạn Facebook - **Reels** phải từ 3-90 giây - **Comment/Reply** cần permission `pages_manage_engagement` - Nếu gặp lỗi permission, xem `references/get-token.md` phần Troubleshooting

path: README.md
content: # 📘 Facebook Page Manager — by MCB AI

Skill quản lý và đăng nội dung **tự động** lên Facebook Fanpage qua **Graph API v19.0**.

> 🌐 [English version](https://github.com/mcbaivn/openclaw-skills-mcbai-en/tree/main/skills/social-media/facebook-page-manager)

---

## ✨ Tính năng

| Tính năng | Hỗ trợ |
|-----------|--------|
| Đăng text | ✅ |
| Đăng ảnh đơn | ✅ |
| Carousel (nhiều ảnh) | ✅ tối đa 10 ảnh |
| Đăng video | ✅ |
| Reels | ✅ 3–90 giây |
| Story ảnh/video | ✅ |
| Hẹn giờ đăng bài | ✅ |
| Xem/xóa/reschedule bài | ✅ |
| Comment vào bài viết | ✅ |
| Reply comment | ✅ |
| Xóa comment | ✅ |

---

## 🚀 Cài đặt nhanh

```bash
npx clawhub@latest install facebook-management-skills-by-mcbai
```

Hoặc copy thủ công vào `~/.agents/skills/`

---

## ⚙️ Setup

### 1. Cài dependencies
```bash
pip install requests
```

### 2. Lấy Page Access Token
- Vào [Graph API Explorer](https://developers.facebook.com/tools/explorer/)
- Chọn permissions: `pages_manage_posts`, `pages_read_engagement`, `pages_manage_engagement`, `publish_video`
- Gọi `GET /me/accounts` → lấy **Page Access Token** và **Page ID**
- Xem hướng dẫn chi tiết: [`references/get-token.md`](./references/get-token.md)

### 3. Tạo file config
Tạo `scripts/fb_config.json`:
```json
{
  "access_token": "EAAxxxxxxxxxxxxxxx",
  "page_id": "123456789012345"
}
```

---

## 📖 Cách dùng

### Đăng bài
```bash
python fb_post.py text --message "Nội dung bài viết"
python fb_post.py photo --message "Caption" --images anh1.jpg anh2.jpg
python fb_post.py video --message "Caption" --video clip.mp4
python fb_post.py video --message "Caption" --video clip.mp4 --reel
python fb_post.py story --type photo --media story.jpg
python fb_post.py story --type video --media story.mp4
```

### Hẹn giờ đăng
```bash
python fb_post.py text --message "Bài sáng thứ Hai" --schedule "2024-12-25 08:00"
python fb_post.py photo --message "Caption" --images anh.jpg --schedule "2024-12-25 10:00"
```

### Quản lý lịch đăng
```bash
python fb_post.py list-scheduled
python fb_post.py delete --post-id PAGE_ID_POST_ID
python fb_post.py reschedule --post-id PAGE_ID_POST_ID --schedule "2024-12-26 09:00"
```

### Comment & Reply
```bash
python fb_post.py comment --post-id PAGE_ID_POST_ID --message "Nội dung comment"
python fb_post.py reply --comment-id COMMENT_ID --message "Nội dung reply"
python fb_post.py list-comments --post-id PAGE_ID_POST_ID
python fb_post.py delete-comment --comment-id COMMENT_ID
```

---

## 🔑 Permissions cần thiết

| Tính năng | Permission |
|-----------|------------|
| Đăng text/ảnh/video/story | `pages_manage_posts` |
| Đăng video/Reels | `pages_manage_posts` + `publish_video` |
| Xem/xóa bài | `pages_read_engagement` |
| Comment/Reply/Xóa comment | `pages_manage_engagement` |

---

## 📁 Cấu trúc

```
facebook-page-manager/
├── SKILL.md                    ← OpenClaw đọc file này
├── README.md                   ← Hướng dẫn (file này)
├── scripts/
│   └── fb_post.py              ← Script chính
└── references/
    ├── get-token.md            ← Hướng dẫn lấy token từng bước
    └── api-reference.md        ← Chi tiết endpoints & format
```

---

## ⚠️ Lưu ý

- Page phải ở trạng thái **Published** (không phải Unpublished/Restricted)
- Video upload có thể mất vài phút xử lý
- Story **không hỗ trợ** hẹn giờ
- **Không commit** `fb_config.json` lên GitHub

---

## 🔗 Liên kết

🌐 [mcbai.vn](https://www.mcbai.vn) · 📘 [Fanpage MCB AI](https://www.facebook.com/mcb.ai.vn) · 🎬 [YouTube @mcbaivn](https://www.youtube.com/@mcbaivn)

Made with ❤️ by [MCB AI](https://www.mcbai.vn)


path: references/api-reference.md
content: # API Reference - Facebook Page Manager

## Endpoints dùng trong skill

| Tính năng | Method | Endpoint |
|-----------|--------|----------|
| Đăng text | POST | `/{page-id}/feed` |
| Đăng ảnh | POST | `/{page-id}/photos` |
| Carousel | POST | `/{page-id}/feed` (với `attached_media`) |
| Video/Reels | POST | `/{page-id}/videos` |
| Story ảnh | POST | `/{page-id}/photo_stories` |
| Story video | POST | `/{page-id}/video_stories` |
| Scheduled posts | GET | `/{page-id}/scheduled_posts` |
| Xóa bài | DELETE | `/{post-id}` |
| Sửa scheduled | POST | `/{post-id}` |
| Comment vào bài | POST | `/{post-id}/comments` |
| Reply vào comment | POST | `/{comment-id}/comments` |
| Xem comments | GET | `/{post-id}/comments` |
| Xóa comment | DELETE | `/{comment-id}` |

---

## Hẹn giờ đăng bài

`scheduled_publish_time` phải là **Unix timestamp** và phải:
- Trong tương lai ít nhất **10 phút**
- Không quá **6 tháng** từ hiện tại

Kèm theo `"published": "false"` trong request.

Ví dụ Python:
```python
from datetime import datetime
ts = int(datetime(2024, 12, 25, 8, 0).timestamp())
```

---

## Carousel

Upload từng ảnh với `published=false` → lấy photo ID → gộp vào feed post:

```json
{
  "message": "Caption đây",
  "attached_media": [
    {"media_fbid": "photo_id_1"},
    {"media_fbid": "photo_id_2"},
    {"media_fbid": "photo_id_3"}
  ]
}
```

---

## Video/Reels

- Format: MP4 (H.264 video, AAC audio)
- Reels: thêm `"video_type": "REELS"`
- Max size: 10GB, max duration: 240 phút
- Reels: 3-90 giây

---

## Story

- Photo story: JPEG/PNG, ratio 9:16 khuyến nghị
- Video story: MP4, max 15 giây
- **Không hỗ trợ schedule** — đăng ngay

---

## Graph API Version

Skill dùng `v19.0`. Kiểm tra version mới nhất tại:
https://developers.facebook.com/docs/graph-api/changelog



path: references/get-token.md
content: # Cách lấy Facebook Page Access Token

## Tổng quan

Để dùng Facebook Graph API đăng bài lên Page, cần **Page Access Token** (không phải User Token thông thường).

---

## Bước 1: Tạo Facebook App

1. Vào **[Meta for Developers](https://developers.facebook.com/)**
2. Click **My Apps → Create App**
3. Chọn **"Other"** → **"Business"** → Đặt tên app → Create
4. Vào **App Dashboard** → Ghi lại **App ID** và **App Secret**

---

## Bước 2: Lấy User Access Token tạm thời (để test)

1. Vào **[Graph API Explorer](https://developers.facebook.com/tools/explorer/)**
2. Chọn app của bạn ở dropdown
3. Click **"Generate Access Token"**
4. Chọn permissions:
   - `pages_manage_posts` ✅
   - `pages_read_engagement` ✅
   - `pages_manage_engagement` ✅ (nếu cần)
   - `publish_video` ✅ (nếu đăng video)
5. Click **Generate Token** → Cho phép quyền

> ⚠️ Token này chỉ có hiệu lực **1-2 giờ** — dùng để test thôi!

---

## Bước 3: Lấy Page Access Token

Sau khi có User Token tạm, chạy lệnh sau để lấy danh sách Page và token dài hạn:

```bash
curl "https://graph.facebook.com/v19.0/me/accounts?access_token=USER_TOKEN_CỦA_BẠN"
```

Response sẽ trả về:
```json
{
  "data": [
    {
      "access_token": "EAAxxxxxxxx...",   ← ĐÂY LÀ PAGE TOKEN
      "category": "Media/News Company",
      "name": "Tên Page của bạn",
      "id": "123456789",                  ← PAGE ID
      "tasks": ["ANALYZE", "ADVERTISE", "MODERATE", "CREATE_CONTENT"]
    }
  ]
}
```

Lưu lại `access_token` (Page Token) và `id` (Page ID).

---

## Bước 4: Tạo Long-Lived Page Access Token (không hết hạn)

Page Access Token từ bước 3 thường **không hết hạn** nếu page đã publish và app đã qua review cơ bản.

Để chắc chắn, đổi sang long-lived [REDACTED_SECRET] 4a:** Đổi User Token ngắn → Long-lived User Token
```bash
curl "https://graph.facebook.com/oauth/access_token
  ?grant_type=fb_exchange_token
  &client_id=APP_ID
  &client_secret=APP_SECRET
  &fb_exchange_token=SHORT_USER_TOKEN"
```

**Bước 4b:** Lấy lại Page Token từ long-lived User Token
```bash
curl "https://graph.facebook.com/v19.0/me/accounts?access_token=LONG_LIVED_USER_TOKEN"
```

Page Token lúc này sẽ **không hết hạn** (never expires).

---

## Bước 5: Kiểm tra token

Dán token vào [Access Token Debugger](https://developers.facebook.com/tools/debug/accesstoken/) để kiểm tra:
- Type: `PAGE`
- Expires: `Never` ✅
- Scopes có đủ permissions không

---

## Bước 6: Lưu config vào `fb_config.json`

Tạo file `fb_config.json` trong cùng thư mục với `fb_post.py`:

```json
{
  "access_token": "EAAxxxxxxxxxxxxxxxxxxxxxxxx",
  "page_id": "123456789012345"
}
```

> 🔒 **QUAN TRỌNG:** Thêm `fb_config.json` vào `.gitignore` — đừng commit token lên GitHub!

---

## Troubleshooting

| Lỗi | Nguyên nhân | Cách fix |
|-----|-------------|----------|
| `(#200) Requires manage_pages permission` | Thiếu permission | Regenerate token với đủ scopes |
| `(#100) Invalid parameter` | Sai page_id hoặc endpoint | Kiểm tra lại page_id |
| `Token expired` | Token hết hạn | Làm lại từ Bước 4 |
| `(#368) The action attempted...` | Page chưa publish hoặc bị hạn chế | Kiểm tra trạng thái Page |
| `Video upload failed` | File quá lớn hoặc sai format | MP4 H.264, max 10GB, dưới 240 phút |

---

## Permissions cần thiết

| Tính năng | Permission |
|-----------|------------|
| Đăng text/ảnh | `pages_manage_posts` |
| Đăng video/Reels | `pages_manage_posts` + `publish_video` |
| Đăng Story | `pages_manage_posts` |
| Xem/xóa bài | `pages_read_engagement` |
| Hẹn giờ đăng | `pages_manage_posts` |

---

## Note về Story

Facebook Graph API hỗ trợ đăng Story qua:
- `/{page-id}/photo_stories` (ảnh)
- `/{page-id}/video_stories` (video)

Story **không hỗ trợ hẹn giờ** qua API — đăng ngay lập tức.



path: scripts/fb_post.py
content: #!/usr/bin/env python3
"""
Facebook Page Manager - Post Script
Supports: text post, photo post, video, carousel, story, scheduled posts
"""

import argparse
import json
import sys
import time
import os
import requests
from datetime import datetime

# ── Config ──────────────────────────────────────────────────────────────────
GRAPH_API = "https://graph.facebook.com/v19.0"


def get_config():
    """Load token & page_id from env or fb_config.json"""
    config_path = os.path.join(os.path.dirname(__file__), "fb_config.json")
    if os.path.exists(config_path):
        with open(config_path) as f:
            return json.load(f)
    return {
        "access_token": os.environ.get("FB_ACCESS_TOKEN", ""),
        "page_id": os.environ.get("FB_PAGE_ID", ""),
    }


def api(method, endpoint, **kwargs):
    cfg = get_config()
    url = f"{GRAPH_API}/{endpoint}"
    params = kwargs.pop("params", {})
    params["access_token"] = cfg["access_token"]
    resp = getattr(requests, method)(url, params=params, **kwargs)
    data = resp.json()
    if "error" in data:
        print(f"❌ API Error: {data['error']['message']}")
        sys.exit(1)
    return data


# ── Post Types ───────────────────────────────────────────────────────────────

def post_text(page_id, message, scheduled_time=None):
    """Đăng bài text thuần"""
    payload = {"message": message}
    if scheduled_time:
        payload["scheduled_publish_time"] = scheduled_time
        payload["published"] = "false"
    result = api("post", f"{page_id}/feed", data=payload)
    return result


def post_photo(page_id, message, image_paths, scheduled_time=None):
    """Đăng 1 ảnh hoặc carousel nhiều ảnh"""
    cfg = get_config()

    if len(image_paths) == 1:
        # Single photo post
        with open(image_paths[0], "rb") as f:
            payload = {"caption": message}
            if scheduled_time:
                payload["scheduled_publish_time"] = scheduled_time
                payload["published"] = "false"
            result = api("post", f"{page_id}/photos",
                         data=payload, files={"source": f})
        return result
    else:
        # Carousel: upload each photo unpublished then combine
        photo_ids = []
        for path in image_paths:
            with open(path, "rb") as f:
                r = api("post", f"{page_id}/photos",
                        data={"published": "false"},
                        files={"source": f})
                photo_ids.append(r["id"])
                print(f"  ✅ Uploaded {path} → {r['id']}")

        attached = [{"media_fbid": pid} for pid in photo_ids]
        payload = {
            "message": message,
            "attached_media": json.dumps(attached),
        }
        if scheduled_time:
            payload["scheduled_publish_time"] = scheduled_time
            payload["published"] = "false"
        result = api("post", f"{page_id}/feed", data=payload)
        return result


def post_video(page_id, message, video_path, scheduled_time=None, is_reel=False):
    """Upload và đăng video / Reels"""
    cfg = get_config()
    endpoint = f"{page_id}/videos"

    with open(video_path, "rb") as f:
        payload = {
            "description": message,
        }
        if is_reel:
            payload["video_type"] = "REELS"
        if scheduled_time:
            payload["scheduled_publish_time"] = scheduled_time
            payload["published"] = "false"
        result = api("post", endpoint, data=payload, files={"source": f})
    return result


def post_story_photo(page_id, image_path):
    """Đăng Story ảnh"""
    with open(image_path, "rb") as f:
        result = api("post", f"{page_id}/photo_stories",
                     files={"source": f})
    return result


def post_story_video(page_id, video_path):
    """Đăng Story video"""
    with open(video_path, "rb") as f:
        result = api("post", f"{page_id}/video_stories",
                     data={"upload_phase": "single"},
                     files={"source": f})
    return result


# ── Schedule Management ───────────────────────────────────────────────────────

def list_scheduled(page_id):
    """Xem danh sách bài hẹn giờ"""
    result = api("get", f"{page_id}/scheduled_posts",
                 params={"fields": "id,message,scheduled_publish_time,story"})
    posts = result.get("data", [])
    if not posts:
        print("📭 Không có bài hẹn giờ nào.")
        return
    print(f"\n📅 Có {len(posts)} bài hẹn giờ:\n")
    for p in posts:
        ts = p.get("scheduled_publish_time", "N/A")
        if isinstance(ts, int):
            ts = datetime.fromtimestamp(ts).strftime("%Y-%m-%d %H:%M")
        msg = (p.get("message") or p.get("story") or "")[:80]
        print(f"  ID: {p['id']}")
        print(f"  ⏰ {ts}")
        print(f"  💬 {msg}")
        print()


def delete_post(post_id):
    """Xóa bài (kể cả scheduled)"""
    result = api("delete", post_id)
    return result


def reschedule_post(post_id, new_timestamp):
    """Đổi giờ đăng bài đã hẹn"""
    result = api("post", post_id,
                 data={"scheduled_publish_time": new_timestamp,
                       "published": "false"})
    return result


# ── CLI ───────────────────────────────────────────────────────────────────────

def parse_schedule(s):
    """Parse '2024-12-25 10:00' → Unix timestamp"""
    dt = datetime.strptime(s, "%Y-%m-%d %H:%M")
    return int(dt.timestamp())


def main():
    parser = argparse.ArgumentParser(
        description="Facebook Page Manager CLI",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  # Đăng text
  python fb_post.py text --message "Hello World!"

  # Đăng ảnh + caption
  python fb_post.py photo --message "Caption đây" --images photo.jpg

  # Carousel (nhiều ảnh)
  python fb_post.py photo --message "Caption" --images a.jpg b.jpg c.jpg

  # Video/Reels
  python fb_post.py video --message "Caption" --video clip.mp4 --reel

  # Story ảnh
  python fb_post.py story --type photo --media story.jpg

  # Story video
  python fb_post.py story --type video --media story.mp4

  # Hẹn giờ đăng
  python fb_post.py text --message "Bài hẹn giờ" --schedule "2024-12-25 08:00"

  # Xem danh sách scheduled
  python fb_post.py list-scheduled

  # Xóa bài
  python fb_post.py delete --post-id 123456789

  # Đổi giờ đăng
  python fb_post.py reschedule --post-id 123456789 --schedule "2024-12-26 09:00"
        """
    )

    sub = parser.add_subparsers(dest="cmd")

    # text
    p_text = sub.add_parser("text", help="Đăng bài text")
    p_text.add_argument("--message", required=True)
    p_text.add_argument("--schedule", help="Hẹn giờ: 'YYYY-MM-DD HH:MM'")

    # photo / carousel
    p_photo = sub.add_parser("photo", help="Đăng ảnh / carousel")
    p_photo.add_argument("--message", required=True)
    p_photo.add_argument("--images", nargs="+", required=True)
    p_photo.add_argument("--schedule", help="Hẹn giờ: 'YYYY-MM-DD HH:MM'")

    # video
    p_video = sub.add_parser("video", help="Đăng video / Reels")
    p_video.add_argument("--message", required=True)
    p_video.add_argument("--video", required=True)
    p_video.add_argument("--reel", action="store_true", help="Upload dạng Reels")
    p_video.add_argument("--schedule", help="Hẹn giờ: 'YYYY-MM-DD HH:MM'")

    # story
    p_story = sub.add_parser("story", help="Đăng Story ảnh hoặc video")
    p_story.add_argument("--type", choices=["photo", "video"], required=True)
    p_story.add_argument("--media", required=True, help="Đường dẫn file")

    # list-scheduled
    sub.add_parser("list-scheduled", help="Xem danh sách bài hẹn giờ")

    # delete
    p_del = sub.add_parser("delete", help="Xóa bài")
    p_del.add_argument("--post-id", required=True)

    # reschedule
    p_re = sub.add_parser("reschedule", help="Đổi giờ đăng")
    p_re.add_argument("--post-id", required=True)
    p_re.add_argument("--schedule", required=True, help="'YYYY-MM-DD HH:MM'")

    args = parser.parse_args()

    if not args.cmd:
        parser.print_help()
        sys.exit(0)

    cfg = get_config()
    page_id = cfg.get("page_id", "")
    if not cfg.get("access_token"):
        print("❌ Chưa có Access Token! Xem references/get-token.md để lấy token.")
        sys.exit(1)

    # ── Dispatch ──────────────────────────────────────────────────────────────

    if args.cmd == "text":
        ts = parse_schedule(args.schedule) if args.schedule else None
        result = post_text(page_id, args.message, ts)
        label = "Bài hẹn giờ" if ts else "Bài đã đăng"
        print(f"✅ {label}! ID: {result.get('id')}")

    elif args.cmd == "photo":
        ts = parse_schedule(args.schedule) if args.schedule else None
        result = post_photo(page_id, args.message, args.images, ts)
        label = "Carousel hẹn giờ" if len(args.images) > 1 else "Ảnh đã đăng"
        if ts:
            label += " (scheduled)"
        print(f"✅ {label}! ID: {result.get('id') or result.get('post_id')}")

    elif args.cmd == "video":
        ts = parse_schedule(args.schedule) if args.schedule else None
        result = post_video(page_id, args.message, args.video, ts, args.reel)
        label = "Reels" if args.reel else "Video"
        print(f"✅ {label} đã upload! ID: {result.get('id')}")

    elif args.cmd == "story":
        if args.type == "photo":
            result = post_story_photo(page_id, args.media)
        else:
            result = post_story_video(page_id, args.media)
        print(f"✅ Story đã đăng! ID: {result.get('id')}")

    elif args.cmd == "list-scheduled":
        list_scheduled(page_id)

    elif args.cmd == "delete":
        result = delete_post(args.post_id)
        print(f"✅ Đã xóa bài {args.post_id}: {result}")

    elif args.cmd == "reschedule":
        ts = parse_schedule(args.schedule)
        result = reschedule_post(args.post_id, ts)
        print(f"✅ Đã đổi lịch bài {args.post_id}!")


if __name__ == "__main__":
    main()



Security scan verdicts — ClawScan: suspicious | static analysis: suspicious | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)