375 lines
13 KiB
Python
375 lines
13 KiB
Python
|
|
"""
|
|||
|
|
抖音发布示例
|
|||
|
|
演示抖音平台的各种发布场景。
|
|||
|
|
"""
|
|||
|
|
import asyncio
|
|||
|
|
import sys
|
|||
|
|
from pathlib import Path
|
|||
|
|
|
|||
|
|
# 添加项目根目录到Python路径
|
|||
|
|
project_root = Path(__file__).parent.parent
|
|||
|
|
sys.path.insert(0, str(project_root))
|
|||
|
|
|
|||
|
|
from core.publisher import Publisher
|
|||
|
|
from core.models import VideoContent, PlatformType, AccountInfo
|
|||
|
|
from utils.logger import setup_logger, get_logger
|
|||
|
|
|
|||
|
|
# 设置日志
|
|||
|
|
setup_logger(level="INFO")
|
|||
|
|
logger = get_logger(__name__)
|
|||
|
|
|
|||
|
|
|
|||
|
|
async def douyin_video_publish_example():
|
|||
|
|
"""抖音视频发布示例"""
|
|||
|
|
print("=" * 60)
|
|||
|
|
print("抖音视频发布示例")
|
|||
|
|
print("=" * 60)
|
|||
|
|
|
|||
|
|
async with Publisher(headless=False) as publisher:
|
|||
|
|
# 设置账号
|
|||
|
|
account_name = "your_douyin_account" # 替换为实际账号名
|
|||
|
|
print(f"1. 设置抖音账号: {account_name}")
|
|||
|
|
|
|||
|
|
success = await publisher.setup_platform("douyin", account_name)
|
|||
|
|
if not success:
|
|||
|
|
print("❌ 账号设置失败,请检查网络和账号信息")
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
print("✅ 账号设置成功")
|
|||
|
|
|
|||
|
|
# 创建多种类型的视频内容
|
|||
|
|
videos = [
|
|||
|
|
# 娱乐搞笑视频
|
|||
|
|
VideoContent(
|
|||
|
|
title="😂 今日最佳搞笑时刻",
|
|||
|
|
description="收集了一些超级搞笑的瞬间,保证让你笑出声!记得点赞关注哦~ #搞笑 #日常 #娱乐",
|
|||
|
|
video_path="media/videos/funny_moments.mp4", # 替换为实际视频路径
|
|||
|
|
tags=["搞笑", "日常", "娱乐", "短视频"]
|
|||
|
|
),
|
|||
|
|
|
|||
|
|
# 生活技巧视频
|
|||
|
|
VideoContent(
|
|||
|
|
title="🔥 超实用生活技巧分享",
|
|||
|
|
description="分享5个超级实用的生活小技巧,让你的生活更加便利。学会了记得分享给朋友哦!#生活技巧 #实用 #分享",
|
|||
|
|
video_path="media/videos/life_hacks.mp4", # 替换为实际视频路径
|
|||
|
|
tags=["生活技巧", "实用", "分享", "教程"]
|
|||
|
|
),
|
|||
|
|
|
|||
|
|
# 美食制作视频
|
|||
|
|
VideoContent(
|
|||
|
|
title="🍜 10分钟搞定一碗美味面条",
|
|||
|
|
description="忙碌工作日也能吃到美食!今天分享一个超简单的面条做法,10分钟就能搞定,味道还不错哦!#美食 #教程 #快手菜",
|
|||
|
|
video_path="media/videos/quick_noodles.mp4", # 替换为实际视频路径
|
|||
|
|
tags=["美食", "教程", "快手菜", "面条"]
|
|||
|
|
),
|
|||
|
|
|
|||
|
|
# 健身运动视频
|
|||
|
|
VideoContent(
|
|||
|
|
title="💪 居家健身5分钟燃脂训练",
|
|||
|
|
description="不需要任何器械,在家就能做的燃脂训练!每天坚持5分钟,让你拥有好身材。#健身 #燃脂 #运动",
|
|||
|
|
video_path="media/videos/home_workout.mp4", # 替换为实际视频路径
|
|||
|
|
tags=["健身", "燃脂", "运动", "居家"]
|
|||
|
|
)
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
# 发布视频
|
|||
|
|
for i, video in enumerate(videos, 1):
|
|||
|
|
print(f"\n{i}. 发布视频: {video.title}")
|
|||
|
|
try:
|
|||
|
|
result = await publisher.publish("douyin", video, account_name)
|
|||
|
|
|
|||
|
|
if result.success:
|
|||
|
|
print(f"✅ 发布成功!")
|
|||
|
|
print(f" 任务ID: {result.task_id}")
|
|||
|
|
print(f" 耗时: {result.duration:.2f}秒")
|
|||
|
|
if result.published_url:
|
|||
|
|
print(f" 链接: {result.published_url}")
|
|||
|
|
else:
|
|||
|
|
print(f"❌ 发布失败: {result.message}")
|
|||
|
|
if result.error_details:
|
|||
|
|
print(f" 错误详情: {result.error_details}")
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"❌ 发布异常: {e}")
|
|||
|
|
|
|||
|
|
# 发布间隔(避免频繁操作)
|
|||
|
|
if i < len(videos):
|
|||
|
|
wait_time = 15 + (i * 5) # 递增等待时间
|
|||
|
|
print(f"⏳ 等待{wait_time}秒后发布下一个视频...")
|
|||
|
|
await asyncio.sleep(wait_time)
|
|||
|
|
|
|||
|
|
|
|||
|
|
async def douyin_batch_upload_example():
|
|||
|
|
"""抖音批量上传示例"""
|
|||
|
|
print("=" * 60)
|
|||
|
|
print("抖音批量上传示例")
|
|||
|
|
print("=" * 60)
|
|||
|
|
|
|||
|
|
# 批量准备视频内容
|
|||
|
|
video_contents = [
|
|||
|
|
VideoContent(
|
|||
|
|
title=f"批量测试视频 {i+1}",
|
|||
|
|
description=f"这是第{i+1}个批量上传的测试视频,内容为{i+1}。",
|
|||
|
|
video_path=f"media/videos/batch_test_{i+1}.mp4", # 替换为实际视频路径
|
|||
|
|
tags=[f"批量测试{i+1}", "自动化", "测试"]
|
|||
|
|
)
|
|||
|
|
for i in range(3)
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
async with Publisher(headless=False) as publisher:
|
|||
|
|
# 设置账号
|
|||
|
|
account_name = "your_douyin_account" # 替换为实际账号名
|
|||
|
|
success = await publisher.setup_platform("douyin", account_name)
|
|||
|
|
|
|||
|
|
if not success:
|
|||
|
|
print("❌ 账号设置失败")
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
print("✅ 账号设置成功")
|
|||
|
|
print(f"开始批量上传 {len(video_contents)} 个视频...")
|
|||
|
|
|
|||
|
|
# 创建发布任务
|
|||
|
|
from core.models import PublishTask
|
|||
|
|
tasks = []
|
|||
|
|
for i, content in enumerate(video_contents):
|
|||
|
|
task = PublishTask(
|
|||
|
|
id=f"douyin_batch_{i+1}",
|
|||
|
|
platform=PlatformType.DOUYIN,
|
|||
|
|
account=AccountInfo(
|
|||
|
|
platform=PlatformType.DOUYIN,
|
|||
|
|
username=account_name,
|
|||
|
|
cookie_file=f"{account_name}.json"
|
|||
|
|
),
|
|||
|
|
content=content,
|
|||
|
|
max_retries=2 # 设置重试次数
|
|||
|
|
)
|
|||
|
|
tasks.append(task)
|
|||
|
|
|
|||
|
|
# 执行批量上传
|
|||
|
|
try:
|
|||
|
|
results = await publisher.batch_publish(tasks)
|
|||
|
|
|
|||
|
|
# 统计结果
|
|||
|
|
success_count = sum(1 for r in results if r.success)
|
|||
|
|
print(f"\n📊 批量上传完成:")
|
|||
|
|
print(f" 成功: {success_count}/{len(results)}")
|
|||
|
|
print(f" 失败: {len(results) - success_count}/{len(results)}")
|
|||
|
|
|
|||
|
|
# 详细结果
|
|||
|
|
for result in results:
|
|||
|
|
status = "✅" if result.success else "❌"
|
|||
|
|
duration = f" ({result.duration:.1f}s)" if result.duration else ""
|
|||
|
|
print(f" {status} {result.task_id}: {result.message}{duration}")
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"❌ 批量上传异常: {e}")
|
|||
|
|
|
|||
|
|
|
|||
|
|
async def douyin_upload_with_progress_example():
|
|||
|
|
"""抖音上传进度监控示例"""
|
|||
|
|
print("=" * 60)
|
|||
|
|
print("抖音上传进度监控示例")
|
|||
|
|
print("=" * 60)
|
|||
|
|
|
|||
|
|
async with Publisher(headless=False) as publisher:
|
|||
|
|
# 设置账号
|
|||
|
|
account_name = "your_douyin_account" # 替换为实际账号名
|
|||
|
|
success = await publisher.setup_platform("douyin", account_name)
|
|||
|
|
|
|||
|
|
if not success:
|
|||
|
|
print("❌ 账号设置失败")
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
print("✅ 账号设置成功")
|
|||
|
|
|
|||
|
|
# 创建一个较大的视频文件用于测试进度监控
|
|||
|
|
video = VideoContent(
|
|||
|
|
title="上传进度测试视频 📊",
|
|||
|
|
description="这是一个用于测试上传进度监控功能的视频,文件比较大,可以清楚地看到上传进度。",
|
|||
|
|
video_path="media/videos/large_video.mp4", # 替换为实际的大视频路径
|
|||
|
|
tags=["测试", "上传", "进度监控"]
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
print(f"\n开始上传视频: {video.title}")
|
|||
|
|
print("注意:这会打开浏览器窗口,你可以看到实际的上传过程")
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
result = await publisher.publish("douyin", video, account_name)
|
|||
|
|
|
|||
|
|
if result.success:
|
|||
|
|
print(f"✅ 视频上传成功!")
|
|||
|
|
print(f" 任务ID: {result.task_id}")
|
|||
|
|
print(f" 总耗时: {result.duration:.2f}秒")
|
|||
|
|
else:
|
|||
|
|
print(f"❌ 视频上传失败: {result.message}")
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"❌ 上传异常: {e}")
|
|||
|
|
|
|||
|
|
|
|||
|
|
async def douyin_content_validation_example():
|
|||
|
|
"""抖音内容验证示例"""
|
|||
|
|
print("=" * 60)
|
|||
|
|
print("抖音内容验证示例")
|
|||
|
|
print("=" * 60)
|
|||
|
|
|
|||
|
|
async with Publisher() as publisher:
|
|||
|
|
# 测试各种内容验证场景
|
|||
|
|
test_cases = [
|
|||
|
|
# 有效内容
|
|||
|
|
{
|
|||
|
|
"name": "有效的视频内容",
|
|||
|
|
"content": VideoContent(
|
|||
|
|
title="有效标题",
|
|||
|
|
description="有效描述",
|
|||
|
|
video_path="test.mp4"
|
|||
|
|
),
|
|||
|
|
"expected": True
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
# 无效内容 - 空标题
|
|||
|
|
{
|
|||
|
|
"name": "空标题",
|
|||
|
|
"content": VideoContent(
|
|||
|
|
title="",
|
|||
|
|
description="有效描述",
|
|||
|
|
video_path="test.mp4"
|
|||
|
|
),
|
|||
|
|
"expected": False
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
# 无效内容 - 空描述
|
|||
|
|
{
|
|||
|
|
"name": "空描述",
|
|||
|
|
"content": VideoContent(
|
|||
|
|
title="有效标题",
|
|||
|
|
description="",
|
|||
|
|
video_path="test.mp4"
|
|||
|
|
),
|
|||
|
|
"expected": False
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
# 无效内容 - 不支持的格式
|
|||
|
|
{
|
|||
|
|
"name": "不支持的文件格式",
|
|||
|
|
"content": VideoContent(
|
|||
|
|
title="有效标题",
|
|||
|
|
description="有效描述",
|
|||
|
|
video_path="test.avi" # 假设不支持avi格式
|
|||
|
|
),
|
|||
|
|
"expected": False
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
# 无效内容 - 视频时长过长
|
|||
|
|
{
|
|||
|
|
"name": "视频时长过长",
|
|||
|
|
"content": VideoContent(
|
|||
|
|
title="有效标题",
|
|||
|
|
description="有效描述",
|
|||
|
|
video_path="test.mp4",
|
|||
|
|
duration=1200 # 20分钟,假设平台限制为10分钟
|
|||
|
|
),
|
|||
|
|
"expected": False
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
print("开始内容验证测试...")
|
|||
|
|
for i, test_case in enumerate(test_cases, 1):
|
|||
|
|
print(f"\n{i}. 测试: {test_case['name']}")
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
is_valid, error_msg = await publisher.validate_content(
|
|||
|
|
"douyin",
|
|||
|
|
test_case['content']
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
if is_valid == test_case['expected']:
|
|||
|
|
print(f" ✅ 验证结果符合预期")
|
|||
|
|
else:
|
|||
|
|
print(f" ❌ 验证结果不符合预期")
|
|||
|
|
print(f" 期望: {test_case['expected']}")
|
|||
|
|
print(f" 实际: {is_valid}")
|
|||
|
|
|
|||
|
|
if not is_valid:
|
|||
|
|
print(f" 错误信息: {error_msg}")
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f" ❌ 验证异常: {e}")
|
|||
|
|
|
|||
|
|
|
|||
|
|
async def douyin_quick_publish_example():
|
|||
|
|
"""抖音快速发布示例"""
|
|||
|
|
print("=" * 60)
|
|||
|
|
print("抖音快速发布示例")
|
|||
|
|
print("=" * 60)
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
from core.publisher import publish_to_douyin
|
|||
|
|
|
|||
|
|
# 快速发布单个视频
|
|||
|
|
print("1. 使用快速发布功能...")
|
|||
|
|
result = await publish_to_douyin(
|
|||
|
|
title="🎬 快速发布测试视频",
|
|||
|
|
description="这是使用快速发布功能上传的测试视频,简单方便!#快速发布 #测试 #自动化",
|
|||
|
|
video_path="media/videos/quick_test.mp4", # 替换为实际视频路径
|
|||
|
|
tags=["快速发布", "测试", "自动化"],
|
|||
|
|
account_name="your_douyin_account", # 替换为实际账号名
|
|||
|
|
headless=False
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
if result.success:
|
|||
|
|
print(f"✅ 快速发布成功!")
|
|||
|
|
print(f" 任务ID: {result.task_id}")
|
|||
|
|
print(f" 耗时: {result.duration:.2f}秒")
|
|||
|
|
else:
|
|||
|
|
print(f"❌ 快速发布失败: {result.message}")
|
|||
|
|
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"❌ 快速发布异常: {e}")
|
|||
|
|
|
|||
|
|
|
|||
|
|
async def main():
|
|||
|
|
"""主函数"""
|
|||
|
|
print("🚀 抖音发布示例")
|
|||
|
|
print("=" * 60)
|
|||
|
|
print("请确保:")
|
|||
|
|
print("1. 替换示例中的账号名称")
|
|||
|
|
print("2. 准备好视频文件")
|
|||
|
|
print("3. 确保网络连接正常")
|
|||
|
|
print("4. 视频文件格式符合要求(mp4、mov等)")
|
|||
|
|
print("=" * 60)
|
|||
|
|
|
|||
|
|
try:
|
|||
|
|
# 运行示例
|
|||
|
|
print("选择要运行的示例:")
|
|||
|
|
print("1. 视频发布")
|
|||
|
|
print("2. 批量上传")
|
|||
|
|
print("3. 上传进度监控")
|
|||
|
|
print("4. 内容验证")
|
|||
|
|
print("5. 快速发布")
|
|||
|
|
|
|||
|
|
choice = input("\n请输入选择 (1-5): ").strip()
|
|||
|
|
|
|||
|
|
if choice == "1":
|
|||
|
|
await douyin_video_publish_example()
|
|||
|
|
elif choice == "2":
|
|||
|
|
await douyin_batch_upload_example()
|
|||
|
|
elif choice == "3":
|
|||
|
|
await douyin_upload_with_progress_example()
|
|||
|
|
elif choice == "4":
|
|||
|
|
await douyin_content_validation_example()
|
|||
|
|
elif choice == "5":
|
|||
|
|
await douyin_quick_publish_example()
|
|||
|
|
else:
|
|||
|
|
print("❌ 无效选择")
|
|||
|
|
|
|||
|
|
except KeyboardInterrupt:
|
|||
|
|
print("\n⏹️ 用户中断")
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f"\n❌ 运行异常: {e}")
|
|||
|
|
import traceback
|
|||
|
|
traceback.print_exc()
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
asyncio.run(main())
|