Skill: x-jihua/vidu-video-publisher (version 1.0.1)

--- name: video-publisher description: 通用视频发布工具。支持将视频发布到小红书、抖音、视频号、快手等主流平台。自动根据平台调性生成标题和标签。Use when: (1) 用户需要发布视频到社交媒体, (2) 批量发布视频到多平台, (3) 需要自动生成平台适配的标题和标签。 --- # Video Publisher 通用视频发布工具，一站式发布到主流社交平台。 ## 支持平台 | 平台 | 状态 | 发布方式 | 视频限制 | |------|------|----------|----------| | 小红书 | ✅ | 浏览器自动化 | 15分钟，竖屏9:16 | | 抖音 | ✅ | 浏览器自动化 | 15分钟，竖屏9:16 | | 视频号 | ✅ | 浏览器自动化 | 30分钟，支持横竖屏 | | 快手 | ✅ | 浏览器自动化 | 10分钟，竖屏9:16 | | B站 | ⏳ | API (计划中) | 无限制 | ## 使用流程 ### Step 1: 提供基础信息 请告诉我以下信息： ``` 📹 视频文件: [视频路径或URL] 🎯 目标平台: [小红书/抖音/视频号/快手，可多选] 📝 视频主题: [简述视频内容，如"中东局势分析"] ``` **示例：** ``` 视频文件: ~/Videos/news_001.mp4 目标平台: 小红书、抖音 视频主题: 伊朗战舰被击沉的新闻 ``` ### Step 2: 自动生成标题和标签 我会根据视频主题和平台调性，自动生成： **小红书风格：** - 标题：震惊！伊朗战舰遭美军击沉🔥中东局势升级 - 标签：#国际新闻 #中东局势 #军事动态 #热点追踪 - 风格：情绪化、emoji、吸引眼球 **抖音风格：** - 标题：伊朗战舰被击沉！中东局势最新分析 - 标签：#国际局势 #中东 #军事 - 风格：简洁、热点导向 **视频号风格：** - 标题：美军击沉伊朗战舰，中东局势再度紧张 - 标签：#国际新闻 #军事 #热点 - 风格：正式、新闻感 ### Step 3: 确认发布 我会展示生成的标题和标签，你可以： - ✅ 直接发布 - ✏️ 修改后再发布 - ❌ 取消发布 ### Step 4: 执行发布 我会自动打开浏览器，登录平台，上传视频，填写标题和标签，完成发布。 ## 平台调性指南 ### 小红书 📱 **标题特点：** - 长度：15-20字最佳 - 必须有情绪词：震惊、必看、干货、收藏、干货满满 - Emoji使用：🔥 💥 ⚠️ 📌 ✨ - 疑问句/感叹句效果更好 **标签策略：** - 3-5个标签 - 包含热门话题标签 - 内容相关+情感标签组合 **封面要求：** - 竖屏 3:4 或 9:16 - 文字居中，大字体 - 高对比度配色 ### 抖音 🎵 **标题特点：** - 长度：10-30字 - 直接、简洁 - 可用疑问句引导互动 - 避免过于标题党 **标签策略：** - 2-3个标签 - 参与热门话题 - 使用平台推荐标签 **封面要求：** - 竖屏 9:16 - 关键帧截图 - 简洁文字说明 ### 视频号 📹 **标题特点：** - 长度：20-40字 - 正式、新闻感 - 客观描述为主 - 可适当加入观点 **标签策略：** - 2-4个标签 - 行业标签+热点标签 - 避免过于娱乐化 **封面要求：** - 支持 16:9 和 9:16 - 专业感封面 - 清晰的主题文字 ### 快手 ⚡ **标题特点：** - 长度：15-25字 - 亲切、接地气 - 可用方言或网络用语 - 强调"老铁"、"家人们" **标签策略：** - 3-5个标签 - 热门话题+地域标签 - 互动型标签 ## 快速开始 ### 单平台发布 ``` 帮我发布视频： - 视频：~/Videos/news_001.mp4 - 平台：小红书 - 主题：中东局势最新动态 ``` ### 多平台发布 ``` 帮我发布视频到小红书和抖音： - 视频：~/Videos/news_001.mp4 - 主题：伊朗战舰事件 ``` ### 批量发布 ``` 帮我批量发布这些视频： - 视频列表：~/Videos/news_*.mp4 - 平台：小红书、抖音、视频号 - 主题：国际新闻合集 ``` ## 注意事项 ⚠️ **发布前准备：** 1. 确保已登录目标平台账号（浏览器会复用登录状态） 2. 视频格式符合平台要求 3. 网络连接稳定 ⚠️ **发布限制：** - 小红书：每日限发5条 - 抖音：无明确限制 - 视频号：每日限发10条 - 快手：无明确限制 ⚠️ **内容审核：** - 平台会自动审核内容 - 敏感内容可能被限流或删除 - 建议发布后检查审核状态 ## 错误处理 | 错误 | 原因 | 解决方案 | |------|------|----------| | LOGIN_REQUIRED | 未登录账号 | 手动登录浏览器 | | VIDEO_TOO_LONG | 视频超时长 | 压缩或剪辑视频 | | FORMAT_ERROR | 格式不支持 | 转换视频格式 | | UPLOAD_FAILED | 上传失败 | 检查网络，重试 | | PUBLISH_LIMIT | 发布次数超限 | 等待明日重试 | ## 相关 Skills - `news-video-pipeline` - 新闻视频制作流水线 - `xiaohongshu-helper` - 小红书浏览助手 - `write-xiaohongshu` - 小红书内容写作 --- **现在就试试吧！** 告诉我你的视频文件路径和目标平台，我来帮你发布！

path: README.md
content: # Video Publisher

通用视频发布工具，支持小红书、抖音、视频号、快手等主流平台。

## 快速开始

### 方式一：对话式引导

直接告诉我：

```
帮我发布视频：
- 视频：~/Videos/news_001.mp4
- 平台：小红书、抖音
- 主题：伊朗战舰事件
```

我会自动：
1. ✅ 根据平台调性生成标题和标签
2. ✅ 展示预览让你确认
3. ✅ 打开浏览器自动发布

### 方式二：命令行

```bash
cd ~/.openclaw/workspace/skills/video-publisher/scripts

# 交互式引导
python3 interactive_publish.py

# 直接发布
python3 publish.py \
  --video ~/Videos/news_001.mp4 \
  --platforms xiaohongshu,douyin \
  --topic "伊朗战舰事件" \
  --category news
```

## 需要提供的信息

### 必需信息

| 信息 | 说明 | 示例 |
|------|------|------|
| 📹 视频文件 | 本地视频路径 | `~/Videos/news_001.mp4` |
| 🎯 目标平台 | 发布平台（可多选） | 小红书、抖音 |
| 📝 视频主题 | 简述内容 | 伊朗战舰被击沉的新闻 |

### 可选信息

| 信息 | 说明 | 默认值 |
|------|------|--------|
| 📂 内容类别 | 内容类型 | news |
| ✏️ 自定义标题 | 指定标题 | 自动生成 |
| 🏷️ 自定义标签 | 指定标签 | 自动生成 |

### 内容类别选项

```
1. news     - 新闻资讯
2. military - 军事国际
3. economy  - 经济财经
4. tech     - 科技创新
5. lifestyle - 生活方式
```

## 示例

### 发布新闻视频

```
视频：~/Videos/middle_east_news.mp4
平台：小红书、抖音、视频号
主题：中东局势最新动态
类别：news（默认）
```

**自动生成：**

小红书：
- 标题：震惊！中东局势再度升级🔥最新动态
- 标签：#热点追踪 #国际新闻 #今日必看

抖音：
- 标题：中东局势最新动态！局势再度紧张
- 标签：#热点 #国际 #最新

视频号：
- 标题：中东局势最新动态：局势再度紧张
- 标签：#国际新闻 #军事动态

### 发布科技视频

```
视频：~/Videos/ai_breakthrough.mp4
平台：小红书
主题：AI技术重大突破
类别：tech
```

**自动生成：**

小红书：
- 标题：震惊！AI技术重大突破📌科技前沿
- 标签：#科技前沿 #黑科技 #创新突破

## 注意事项

⚠️ **首次使用需要登录**

发布时会打开浏览器，如果未登录目标平台，需要手动登录一次。登录状态会被保存，下次无需重复登录。

⚠️ **视频格式要求**

- 小红书：15分钟内，竖屏9:16最佳
- 抖音：15分钟内，竖屏9:16
- 视频号：30分钟内，支持横竖屏
- 快手：10分钟内，竖屏9:16

⚠️ **发布限制**

- 小红书：每日5条
- 抖音：无明确限制
- 视频号：每日10条
- 快手：无明确限制

## 文件结构

```
video-publisher/
├── SKILL.md                      # 本文档
├── scripts/
│   ├── publish.py                # 主发布脚本
│   ├── interactive_publish.py    # 交互式引导
│   └── browser_publisher.py      # 浏览器自动化
└── references/
    └── platform_styles.md        # 平台调性指南
```


path: scripts/browser_publisher.py
content: #!/usr/bin/env python3
"""
浏览器自动化发布脚本
使用 Playwright 控制浏览器发布视频
"""

import asyncio
import argparse
import os
from typing import Dict, List, Optional
from playwright.async_api import async_playwright, Page, Browser


class VideoPublisher:
    """视频发布器"""
    
    def __init__(self, headless: bool = False):
        self.headless = headless
        self.browser: Optional[Browser] = None
        self.page: Optional[Page] = None
    
    async def init_browser(self):
        """初始化浏览器"""
        playwright = await async_playwright().start()
        self.browser = await playwright.chromium.launch(
            headless=self.headless,
            args=["--start-maximized"]
        )
        context = await self.browser.new_context(
            viewport={"width": 1920, "height": 1080},
            storage_state="browser_state.json"  # 保存登录状态
        )
        self.page = await context.new_page()
    
    async def close_browser(self):
        """关闭浏览器"""
        if self.browser:
            await self.browser.close()
    
    async def publish_to_xiaohongshu(
        self, 
        video_path: str, 
        title: str, 
        tags: List[str],
        description: str = ""
    ) -> Dict:
        """
        发布到小红书
        
        Args:
            video_path: 视频文件路径
            title: 标题
            tags: 标签列表
            description: 描述
        
        Returns:
            发布结果
        """
        print("\n📱 发布到小红书...")
        
        try:
            # 打开小红书创作者中心
            await self.page.goto("https://creator.xiaohongshu.com/publish/publish")
            await self.page.wait_for_load_state("networkidle")
            
            # 检查是否需要登录
            if "login" in self.page.url:
                print("⚠️  需要登录小红书，请在浏览器中完成登录")
                await self.page.wait_for_url("**/publish/publish", timeout=300000)
            
            # 点击上传视频
            upload_btn = await self.page.query_selector('text="上传视频"')
            if upload_btn:
                await upload_btn.click()
            
            # 上传视频文件
            file_input = await self.page.query_selector('input[type="file"]')
            if file_input:
                await file_input.set_input_files(video_path)
            
            # 等待上传完成
            print("⏳ 上传视频中...")
            await asyncio.sleep(5)  # 简单等待，实际应该监控上传进度
            
            # 填写标题
            title_input = await self.page.query_selector('input[placeholder*="标题"]')
            if title_input:
                await title_input.fill(title)
            
            # 填写描述
            if description:
                desc_input = await self.page.query_selector('textarea[placeholder*="描述"]')
                if desc_input:
                    await desc_input.fill(description)
            
            # 添加标签
            for tag in tags:
                tag_input = await self.page.query_selector('input[placeholder*="标签"]')
                if tag_input:
                    await tag_input.fill(tag)
                    await tag_input.press("Enter")
                    await asyncio.sleep(0.5)
            
            # 点击发布
            publish_btn = await self.page.query_selector('button:has-text("发布")')
            if publish_btn:
                await publish_btn.click()
            
            # 等待发布完成
            await asyncio.sleep(3)
            
            print("✅ 小红书发布成功")
            return {
                "platform": "xiaohongshu",
                "status": "success",
                "title": title,
                "tags": tags
            }
            
        except Exception as e:
            print(f"❌ 小红书发布失败: {e}")
            return {
                "platform": "xiaohongshu",
                "status": "failed",
                "error": str(e)
            }
    
    async def publish_to_douyin(
        self, 
        video_path: str, 
        title: str, 
        tags: List[str]
    ) -> Dict:
        """
        发布到抖音
        """
        print("\n🎵 发布到抖音...")
        
        try:
            # 打开抖音创作者中心
            await self.page.goto("https://creator.douyin.com/creator-micro/content/upload")
            await self.page.wait_for_load_state("networkidle")
            
            # 检查登录
            if "login" in self.page.url:
                print("⚠️  需要登录抖音，请在浏览器中完成登录")
                await self.page.wait_for_url("**/content/upload", timeout=300000)
            
            # 上传视频
            file_input = await self.page.query_selector('input[type="file"]')
            if file_input:
                await file_input.set_input_files(video_path)
            
            print("⏳ 上传视频中...")
            await asyncio.sleep(5)
            
            # 填写标题
            title_input = await self.page.query_selector('input[placeholder*="标题"]')
            if title_input:
                await title_input.fill(title)
            
            # 添加标签
            for tag in tags:
                tag_input = await self.page.query_selector('input[placeholder*="话题"]')
                if tag_input:
                    await tag_input.fill(tag)
                    await tag_input.press("Enter")
                    await asyncio.sleep(0.5)
            
            # 发布
            publish_btn = await self.page.query_selector('button:has-text("发布")')
            if publish_btn:
                await publish_btn.click()
            
            await asyncio.sleep(3)
            
            print("✅ 抖音发布成功")
            return {
                "platform": "douyin",
                "status": "success",
                "title": title,
                "tags": tags
            }
            
        except Exception as e:
            print(f"❌ 抖音发布失败: {e}")
            return {
                "platform": "douyin",
                "status": "failed",
                "error": str(e)
            }
    
    async def publish_to_shipinhao(
        self, 
        video_path: str, 
        title: str, 
        tags: List[str]
    ) -> Dict:
        """
        发布到视频号
        """
        print("\n📹 发布到视频号...")
        
        try:
            # 视频号需要通过微信网页版
            await self.page.goto("https://channels.weixin.qq.com/")
            await self.page.wait_for_load_state("networkidle")
            
            print("⚠️  视频号需要扫码登录微信")
            print("   请在浏览器中扫码登录，然后手动上传视频")
            
            # 视频号发布较复杂，暂时只打开页面
            return {
                "platform": "shipinhao",
                "status": "manual",
                "message": "请手动完成发布"
            }
            
        except Exception as e:
            print(f"❌ 视频号发布失败: {e}")
            return {
                "platform": "shipinhao",
                "status": "failed",
                "error": str(e)
            }
    
    async def publish_to_kuaishou(
        self, 
        video_path: str, 
        title: str, 
        tags: List[str]
    ) -> Dict:
        """
        发布到快手
        """
        print("\n⚡ 发布到快手...")
        
        try:
            await self.page.goto("https://cp.kuaishou.com/article/publish/video")
            await self.page.wait_for_load_state("networkidle")
            
            if "login" in self.page.url:
                print("⚠️  需要登录快手，请在浏览器中完成登录")
                await self.page.wait_for_url("**/publish/video", timeout=300000)
            
            # 上传视频
            file_input = await self.page.query_selector('input[type="file"]')
            if file_input:
                await file_input.set_input_files(video_path)
            
            print("⏳ 上传视频中...")
            await asyncio.sleep(5)
            
            # 填写标题
            title_input = await self.page.query_selector('input[placeholder*="标题"]')
            if title_input:
                await title_input.fill(title)
            
            # 添加标签
            for tag in tags:
                tag_input = await self.page.query_selector('input[placeholder*="标签"]')
                if tag_input:
                    await tag_input.fill(tag)
                    await tag_input.press("Enter")
                    await asyncio.sleep(0.5)
            
            # 发布
            publish_btn = await self.page.query_selector('button:has-text("发布")')
            if publish_btn:
                await publish_btn.click()
            
            await asyncio.sleep(3)
            
            print("✅ 快手发布成功")
            return {
                "platform": "kuaishou",
                "status": "success",
                "title": title,
                "tags": tags
            }
            
        except Exception as e:
            print(f"❌ 快手发布失败: {e}")
            return {
                "platform": "kuaishou",
                "status": "failed",
                "error": str(e)
            }


async def main():
    parser = argparse.ArgumentParser(description="浏览器自动化发布")
    parser.add_argument("--video", type=str, required=True)
    parser.add_argument("--platform", type=str, required=True)
    parser.add_argument("--title", type=str, required=True)
    parser.add_argument("--tags", type=str, required=True)
    parser.add_argument("--description", type=str, default="")
    parser.add_argument("--headless", action="store_true", help="无头模式")
    
    args = parser.parse_args()
    
    publisher = VideoPublisher(headless=args.headless)
    
    try:
        await publisher.init_browser()
        
        tags = [t.strip() for t in args.tags.split(",")]
        
        if args.platform == "xiaohongshu":
            result = await publisher.publish_to_xiaohongshu(
                args.video, args.title, tags, args.description
            )
        elif args.platform == "douyin":
            result = await publisher.publish_to_douyin(
                args.video, args.title, tags
            )
        elif args.platform == "shipinhao":
            result = await publisher.publish_to_shipinhao(
                args.video, args.title, tags
            )
        elif args.platform == "kuaishou":
            result = await publisher.publish_to_kuaishou(
                args.video, args.title, tags
            )
        else:
            print(f"❌ 不支持的平台: {args.platform}")
            return
        
        print(f"\n📋 发布结果: {result}")
        
    finally:
        await publisher.close_browser()


if __name__ == "__main__":
    asyncio.run(main())


path: scripts/interactive_publish.py
content: #!/usr/bin/env python3
"""
交互式视频发布工具
引导用户提供必要信息
"""

import argparse
import json
import os
from datetime import datetime
from typing import Dict, List


def interactive_guide():
    """交互式引导"""
    print("\n" + "="*60)
    print("🎬 视频发布向导")
    print("="*60)
    
    # Step 1: 视频文件
    print("\n📹 Step 1: 视频文件")
    print("   请提供视频文件路径")
    video_path = input("   路径: ").strip()
    
    if not os.path.exists(video_path):
        print(f"   ❌ 文件不存在: {video_path}")
        return
    
    # Step 2: 目标平台
    print("\n🎯 Step 2: 目标平台")
    print("   支持的平台:")
    print("   1. 小红书 (xiaohongshu)")
    print("   2. 抖音 (douyin)")
    print("   3. 视频号 (shipinhao)")
    print("   4. 快手 (kuaishou)")
    print("   可多选，用逗号分隔，如: 1,2,3")
    
    platform_input = input("   选择: ").strip()
    
    platform_map = {
        "1": "xiaohongshu",
        "2": "douyin",
        "3": "shipinhao",
        "4": "kuaishou"
    }
    
    platforms = []
    for p in platform_input.split(","):
        p = p.strip()
        if p in platform_map:
            platforms.append(platform_map[p])
        elif p in platform_map.values():
            platforms.append(p)
    
    if not platforms:
        print("   ❌ 未选择有效平台")
        return
    
    print(f"   ✅ 已选择: {', '.join(platforms)}")
    
    # Step 3: 视频主题
    print("\n📝 Step 3: 视频主题")
    print("   请简述视频内容（用于生成标题和标签）")
    topic = input("   主题: ").strip()
    
    if not topic:
        print("   ❌ 主题不能为空")
        return
    
    # Step 4: 内容类别
    print("\n📂 Step 4: 内容类别")
    print("   选择内容类别:")
    print("   1. 新闻资讯 (news)")
    print("   2. 军事国际 (military)")
    print("   3. 经济财经 (economy)")
    print("   4. 科技创新 (tech)")
    print("   5. 生活方式 (lifestyle)")
    
    category_input = input("   选择 (默认1): ").strip() or "1"
    
    category_map = {
        "1": "news",
        "2": "military",
        "3": "economy",
        "4": "tech",
        "5": "lifestyle"
    }
    
    category = category_map.get(category_input, "news")
    print(f"   ✅ 类别: {category}")
    
    # Step 5: 生成标题和标签预览
    print("\n🎨 Step 5: 标题和标签预览")
    print("   正在根据平台调性生成...")
    
    # 导入生成函数
    from publish import generate_title, generate_tags, PLATFORMS
    
    preview = {}
    for platform in platforms:
        config = PLATFORMS.get(platform)
        if not config:
            continue
        
        title = generate_title(topic, platform, category)
        tags = generate_tags(topic, platform, category)
        
        preview[platform] = {
            "platform_name": config.name,
            "title": title,
            "tags": tags
        }
        
        print(f"\n   【{config.name}】")
        print(f"   标题: {title}")
        print(f"   标签: {' '.join(tags)}")
    
    # Step 6: 确认发布
    print("\n✅ Step 6: 确认发布")
    print("   选项:")
    print("   1. 直接发布")
    print("   2. 修改标题/标签后发布")
    print("   3. 取消发布")
    
    choice = input("   选择: ").strip()
    
    if choice == "1":
        # 执行发布
        print("\n🚀 开始发布...")
        
        # 调用发布脚本
        import subprocess
        
        platforms_str = ",".join(platforms)
        cmd = [
            "python3", "publish.py",
            "--video", video_path,
            "--platforms", platforms_str,
            "--topic", topic,
            "--category", category
        ]
        
        subprocess.run(cmd)
        
    elif choice == "2":
        # 修改模式
        print("\n   ✏️  自定义模式")
        custom_title = input("   输入自定义标题（留空使用自动生成）: ").strip()
        custom_tags = input("   输入自定义标签（逗号分隔，留空使用自动生成）: ").strip()
        
        # 使用自定义内容发布
        cmd = [
            "python3", "publish.py",
            "--video", video_path,
            "--platforms", ",".join(platforms),
            "--topic", topic,
            "--category", category
        ]
        
        if custom_title:
            cmd.extend(["--title", custom_title])
        if custom_tags:
            cmd.extend(["--tags", custom_tags])
        
        subprocess.run(cmd)
        
    else:
        print("\n   ❌ 已取消发布")
        return
    
    print("\n" + "="*60)
    print("✅ 发布流程完成")
    print("="*60)


def main():
    parser = argparse.ArgumentParser(description="交互式视频发布")
    parser.add_argument("--auto", action="store_true", help="自动模式（使用默认值）")
    
    args = parser.parse_args()
    
    if args.auto:
        # 自动模式：从配置文件读取
        print("🤖 自动模式")
        # TODO: 从配置文件读取参数
    else:
        interactive_guide()


if __name__ == "__main__":
    main()


path: scripts/publish.py
content: #!/usr/bin/env python3
"""
视频发布主脚本
支持多平台视频发布，自动生成标题和标签
"""

import argparse
import json
import os
import time
from datetime import datetime
from typing import Dict, List, Optional
from dataclasses import dataclass


@dataclass
class PlatformConfig:
    """平台配置"""
    name: str
    max_duration: int  # 秒
    aspect_ratio: str
    max_title_length: int
    tag_count: tuple  # (min, max)
    emoji_support: bool
    style: str


# 平台配置
PLATFORMS = {
    "xiaohongshu": PlatformConfig(
        name="小红书",
        max_duration=900,  # 15分钟
        aspect_ratio="9:16",
        max_title_length=20,
        tag_count=(3, 5),
        emoji_support=True,
        style="emotional"
    ),
    "douyin": PlatformConfig(
        name="抖音",
        max_duration=900,
        aspect_ratio="9:16",
        max_title_length=30,
        tag_count=(2, 3),
        emoji_support=True,
        style="concise"
    ),
    "shipinhao": PlatformConfig(
        name="视频号",
        max_duration=1800,
        aspect_ratio="16:9,9:16",
        max_title_length=40,
        tag_count=(2, 4),
        emoji_support=False,
        style="formal"
    ),
    "kuaishou": PlatformConfig(
        name="快手",
        max_duration=600,
        aspect_ratio="9:16",
        max_title_length=25,
        tag_count=(3, 5),
        emoji_support=True,
        style="casual"
    )
}

# 平台调性模板
STYLE_TEMPLATES = {
    "emotional": {
        "title_prefixes": ["震惊！", "必看！", "收藏！", "干货满满！", "太重要了！"],
        "title_suffixes": ["🔥", "💥", "⚠️", "📌", "✨"],
        "tag_styles": {
            "news": ["#热点追踪", "#最新消息", "#重磅新闻", "#今日热点"],
            "military": ["#军事动态", "#国际局势", "#国防军事"],
            "economy": ["#经济观察", "#财经热点", "#投资理财"],
            "tech": ["#科技前沿", "#黑科技", "#创新突破"],
            "lifestyle": ["#生活技巧", "#实用干货", "#好物推荐"]
        }
    },
    "concise": {
        "title_prefixes": ["最新！", "突发！", "快讯！"],
        "title_suffixes": [],
        "tag_styles": {
            "news": ["#热点", "#新闻", "#最新"],
            "military": ["#军事", "#国际"],
            "economy": ["#财经", "#经济"],
            "tech": ["#科技", "#创新"],
            "lifestyle": ["#生活", "#实用"]
        }
    },
    "formal": {
        "title_prefixes": [],
        "title_suffixes": [],
        "tag_styles": {
            "news": ["#国际新闻", "#时事热点"],
            "military": ["#军事新闻", "#国防动态"],
            "economy": ["#财经新闻", "#经济动态"],
            "tech": ["#科技新闻", "#创新前沿"],
            "lifestyle": ["#生活分享", "#实用知识"]
        }
    },
    "casual": {
        "title_prefixes": ["老铁们！", "家人们！", "兄弟们！"],
        "title_suffixes": ["👍", "💪", "🔥"],
        "tag_styles": {
            "news": ["#热点事件", "#大家都在看", "#今日热点"],
            "military": ["#军事那些事", "#国际大事"],
            "economy": ["#搞钱必看", "#财经热点"],
            "tech": ["#黑科技来了", "#科技好物"],
            "lifestyle": ["#生活小妙招", "#实用好物"]
        }
    }
}


def generate_title(topic: str, platform: str, category: str = "news") -> str:
    """
    根据平台调性生成标题
    
    Args:
        topic: 视频主题
        platform: 平台ID
        category: 内容类别
    
    Returns:
        生成的标题
    """
    config = PLATFORMS.get(platform)
    if not config:
        return topic
    
    style = STYLE_TEMPLATES.get(config.style, STYLE_TEMPLATES["concise"])
    
    # 选择前缀
    prefix = ""
    if style["title_prefixes"]:
        import random
        prefix = random.choice(style["title_prefixes"])
    
    # 选择后缀（emoji）
    suffix = ""
    if config.emoji_support and style["title_suffixes"]:
        import random
        suffix = random.choice(style["title_suffixes"])
    
    # 组合标题
    title = f"{prefix}{topic}{suffix}"
    
    # 截断到最大长度
    if len(title) > config.max_title_length:
        title = title[:config.max_title_length - 3] + "..."
    
    return title


def generate_tags(topic: str, platform: str, category: str = "news") -> List[str]:
    """
    根据平台调性生成标签
    
    Args:
        topic: 视频主题
        platform: 平台ID
        category: 内容类别
    
    Returns:
        标签列表
    """
    config = PLATFORMS.get(platform)
    if not config:
        return [f"#{topic}"]
    
    style = STYLE_TEMPLATES.get(config.style, STYLE_TEMPLATES["concise"])
    tag_styles = style.get("tag_styles", {})
    
    # 获取类别标签
    category_tags = tag_styles.get(category, [f"#{topic}"])
    
    # 确定标签数量
    min_tags, max_tags = config.tag_count
    import random
    tag_count = random.randint(min_tags, max_tags)
    
    # 选择标签
    tags = []
    if len(category_tags) >= tag_count:
        tags = random.sample(category_tags, tag_count)
    else:
        tags = category_tags.copy()
        # 添加通用标签
        general_tags = ["#原创", "#热门", "#推荐"]
        remaining = tag_count - len(tags)
        if remaining > 0:
            tags.extend(random.sample(general_tags, min(remaining, len(general_tags))))
    
    return tags[:max_tags]


def check_video(video_path: str, platform: str) -> Dict:
    """
    检查视频是否符合平台要求
    
    Returns:
        检查结果
    """
    config = PLATFORMS.get(platform)
    result = {
        "valid": True,
        "errors": [],
        "warnings": []
    }
    
    # 检查文件是否存在
    if not os.path.exists(video_path):
        result["valid"] = False
        result["errors"].append(f"视频文件不存在: {video_path}")
        return result
    
    # 检查文件大小
    file_size = os.path.getsize(video_path)
    if file_size > 500 * 1024 * 1024:  # 500MB
        result["warnings"].append(f"视频文件较大 ({file_size / 1024 / 1024:.1f}MB)，上传可能较慢")
    
    # TODO: 检查视频时长和分辨率
    # 需要使用 ffmpeg 或 moviepy
    
    return result


def publish_to_xiaohongshu(video_path: str, title: str, tags: List[str]) -> Dict:
    """
    发布到小红书
    
    Returns:
        发布结果
    """
    # TODO: 使用浏览器自动化
    # 可以调用 xiaohongshu-helper skill
    
    print(f"\n📱 发布到小红书")
    print(f"   标题: {title}")
    print(f"   标签: {' '.join(tags)}")
    print(f"   视频: {video_path}")
    
    # 模拟发布过程
    return {
        "platform": "xiaohongshu",
        "status": "pending_browser",
        "message": "需要打开浏览器完成发布"
    }


def publish_to_douyin(video_path: str, title: str, tags: List[str]) -> Dict:
    """
    发布到抖音
    """
    print(f"\n🎵 发布到抖音")
    print(f"   标题: {title}")
    print(f"   标签: {' '.join(tags)}")
    print(f"   视频: {video_path}")
    
    return {
        "platform": "douyin",
        "status": "pending_browser",
        "message": "需要打开浏览器完成发布"
    }


def publish_to_shipinhao(video_path: str, title: str, tags: List[str]) -> Dict:
    """
    发布到视频号
    """
    print(f"\n📹 发布到视频号")
    print(f"   标题: {title}")
    print(f"   标签: {' '.join(tags)}")
    print(f"   视频: {video_path}")
    
    return {
        "platform": "shipinhao",
        "status": "pending_browser",
        "message": "需要打开浏览器完成发布"
    }


def publish_to_kuaishou(video_path: str, title: str, tags: List[str]) -> Dict:
    """
    发布到快手
    """
    print(f"\n⚡ 发布到快手")
    print(f"   标题: {title}")
    print(f"   标签: {' '.join(tags)}")
    print(f"   视频: {video_path}")
    
    return {
        "platform": "kuaishou",
        "status": "pending_browser",
        "message": "需要打开浏览器完成发布"
    }


# 发布函数映射
PUBLISH_FUNCTIONS = {
    "xiaohongshu": publish_to_xiaohongshu,
    "douyin": publish_to_douyin,
    "shipinhao": publish_to_shipinhao,
    "kuaishou": publish_to_kuaishou
}


def main():
    parser = argparse.ArgumentParser(description="视频发布工具")
    parser.add_argument("--video", type=str, required=True, help="视频文件路径")
    parser.add_argument("--platforms", type=str, required=True, help="目标平台，逗号分隔")
    parser.add_argument("--topic", type=str, required=True, help="视频主题")
    parser.add_argument("--category", type=str, default="news", help="内容类别")
    parser.add_argument("--title", type=str, default="", help="自定义标题（可选）")
    parser.add_argument("--tags", type=str, default="", help="自定义标签，逗号分隔（可选）")
    parser.add_argument("--output", type=str, default="publish_report.json", help="报告输出文件")
    
    args = parser.parse_args()
    
    # 解析平台列表
    target_platforms = [p.strip() for p in args.platforms.split(",")]
    
    print("\n" + "="*60)
    print("🚀 视频发布工具")
    print("="*60)
    print(f"📹 视频: {args.video}")
    print(f"🎯 平台: {', '.join(target_platforms)}")
    print(f"📝 主题: {args.topic}")
    print(f"📂 类别: {args.category}")
    
    # 发布结果
    results = []
    
    for platform in target_platforms:
        if platform not in PLATFORMS:
            print(f"\n⚠️  不支持的平台: {platform}")
            continue
        
        # 检查视频
        check_result = check_video(args.video, platform)
        if not check_result["valid"]:
            print(f"\n❌ 视频检查失败: {check_result['errors']}")
            results.append({
                "platform": platform,
                "status": "failed",
                "errors": check_result["errors"]
            })
            continue
        
        # 生成或使用自定义标题
        if args.title:
            title = args.title
        else:
            title = generate_title(args.topic, platform, args.category)
        
        # 生成或使用自定义标签
        if args.tags:
            tags = [f"#{t.strip()}" for t in args.tags.split(",")]
        else:
            tags = generate_tags(args.topic, platform, args.category)
        
        # 执行发布
        publish_func = PUBLISH_FUNCTIONS.get(platform)
        if publish_func:
            result = publish_func(args.video, title, tags)
            results.append(result)
        else:
            print(f"\n⚠️  平台 {platform} 的发布功能尚未实现")
            results.append({
                "platform": platform,
                "status": "not_implemented"
            })
    
    # 保存报告
    report = {
        "timestamp": datetime.now().isoformat(),
        "video": args.video,
        "topic": args.topic,
        "category": args.category,
        "platforms": target_platforms,
        "results": results
    }
    
    with open(args.output, "w", encoding="utf-8") as f:
        json.dump(report, f, ensure_ascii=False, indent=2)
    
    print("\n" + "="*60)
    print(f"📋 发布报告已保存: {args.output}")
    print("="*60)


if __name__ == "__main__":
    main()


path: references/platform_styles.md
content: # 平台调性指南

## 小红书 📱

### 用户画像
- 年龄：18-35岁，女性用户占比约70%
- 特点：注重生活品质、喜欢分享、追求美感
- 活跃时间：12:00-14:00, 20:00-23:00

### 内容特点

**标题风格：**
```
✅ 推荐：
- "震惊！XX竟然..." - 引起好奇心
- "必看！XX干货分享🔥" - 强调价值
- "收藏！XX完整攻略📌" - 引导收藏
- "最新！XX重磅消息⚠️" - 时效性

❌ 避免：
- 过于严肃的标题
- 没有emoji的纯文字
- 过长的标题（>20字）
```

**标签策略：**
- 3-5个标签最佳
- 组合：热门标签 + 内容标签 + 情感标签
- 示例：`#热点追踪 #国际新闻 #今日必看`

**封面要求：**
- 竖屏 3:4 或 9:16
- 文字居中，大字体（建议48pt以上）
- 高对比度配色
- 可添加emoji增加视觉吸引力

### 内容禁忌
- 禁止医疗美容、减肥药等敏感内容
- 禁止过度营销、刷屏行为
- 避免低俗、夸张的标题党

---

## 抖音 🎵

### 用户画像
- 年龄：16-35岁，用户分布广泛
- 特点：喜欢娱乐、短视频消费、追求热点
- 活跃时间：12:00-14:00, 18:00-22:00

### 内容特点

**标题风格：**
```
✅ 推荐：
- "XX最新消息！" - 简洁直接
- "这件事你怎么看？" - 引导互动
- "终于等到了！" - 情绪共鸣

❌ 避免：
- 过于标题党
- 超过30字的标题
- 复杂的专业术语
```

**标签策略：**
- 2-3个标签
- 参与热门话题挑战
- 使用平台推荐标签
- 示例：`#热点 #最新消息`

**封面要求：**
- 竖屏 9:16
- 视频关键帧截图
- 简洁的文字说明

### 内容禁忌
- 禁止涉政、涉黄、涉暴内容
- 禁止虚假宣传、诈骗信息
- 避免低质、重复内容

---

## 视频号 📹

### 用户画像
- 年龄：25-50岁，中年用户较多
- 特点：微信生态、社交分享、追求专业感
- 活跃时间：8:00-10:00, 20:00-22:00

### 内容特点

**标题风格：**
```
✅ 推荐：
- "XX事件最新进展" - 客观描述
- "专家解读：XX" - 专业视角
- "深度分析：XX" - 内容价值

❌ 避免：
- 过于娱乐化的表达
- 夸张的标题党
- emoji过度使用
```

**标签策略：**
- 2-4个标签
- 行业标签 + 热点标签
- 示例：`#国际新闻 #军事动态`

**封面要求：**
- 支持 16:9 和 9:16
- 专业感封面设计
- 清晰的主题文字

### 内容禁忌
- 禁止违反微信社区规范
- 禁止诱导分享、虚假宣传
- 避免低俗、夸张内容

---

## 快手 ⚡

### 用户画像
- 年龄：18-40岁，下沉市场用户多
- 特点：接地气、真实、注重互动
- 活跃时间：12:00-14:00, 19:00-23:00

### 内容特点

**标题风格：**
```
✅ 推荐：
- "老铁们！XX来了" - 亲切感
- "家人们看看这个" - 社区感
- "这个太真实了" - 情感共鸣

❌ 避免：
- 过于书面化
- 高冷、不接地气
- 复杂的专业术语
```

**标签策略：**
- 3-5个标签
- 热门话题 + 地域标签
- 互动型标签
- 示例：`#热点事件 #大家都在看`

**封面要求：**
- 竖屏 9:16
- 真实、接地气的画面
- 简洁的文字说明

### 内容禁忌
- 禁止低俗、暴力内容
- 禁止虚假宣传
- 避免过于浮夸的表演

---

## 平台对比总结

| 维度 | 小红书 | 抖音 | 视频号 | 快手 |
|------|--------|------|--------|------|
| 调性 | 精致生活 | 娱乐热点 | 专业正式 | 接地气 |
| 标题 | 情绪化+emoji | 简洁直接 | 客观描述 | 亲切互动 |
| 标签数 | 3-5个 | 2-3个 | 2-4个 | 3-5个 |
| 封面 | 精致设计 | 关键帧 | 专业感 | 真实感 |
| 适合内容 | 生活方式、干货 | 娱乐、热点 | 新闻、知识 | 生活、搞笑 |


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