63 lines
2.0 KiB
Go
63 lines
2.0 KiB
Go
// douyin 抖音执行器(CDP:creator.douyin.com)。选择器参考 dreammis/social-auto-upload(2026-06 版)。
|
||
package douyin
|
||
|
||
import (
|
||
"context"
|
||
"time"
|
||
|
||
"everypublish/agentcore/internal/exec"
|
||
"everypublish/agentcore/internal/exec/cdnbase"
|
||
"everypublish/agentcore/internal/exec/cdp"
|
||
"everypublish/agentcore/internal/vault"
|
||
"everypublish/shared/proto"
|
||
)
|
||
|
||
// Executor 抖音发布执行器
|
||
type Executor struct {
|
||
base *cdnbase.Platform
|
||
}
|
||
|
||
// New 构造执行器(rootDir=浏览器档案根目录,proxy=账号固定IP代理)
|
||
func New(v *vault.Vault, rootDir, proxy, chromePath string, headless bool) *Executor {
|
||
p := &cdnbase.Platform{
|
||
Vault: v,
|
||
RootDir: rootDir,
|
||
Proxy: proxy,
|
||
ChromePath: chromePath,
|
||
Headless: headless,
|
||
ReceiptDir: rootDir + "/receipts",
|
||
Name: "douyin",
|
||
LoginDomain: ".douyin.com",
|
||
PublishCfg: cdp.PublishConfig{
|
||
UploadURL: "https://creator.douyin.com/creator-micro/content/upload",
|
||
SuccessMarker: "creator-micro/content/manage",
|
||
FileInputSel: "input[type=\"file\"]",
|
||
TitleSel: "input[placeholder*=\"填写作品标题\"]",
|
||
DescSel: "div.zone-container[contenteditable=\"true\"]",
|
||
PublishBtnSel: "button:has-text(\"发布\")",
|
||
FormWait: 180 * time.Second, // 视频转码渲染表单较慢
|
||
SuccessWait: 120 * time.Second,
|
||
},
|
||
LoginCfg: cdp.QRLoginConfig{
|
||
LoginURL: "https://creator.douyin.com/",
|
||
LoginPathMarker: "creator.douyin.com/?",
|
||
QRSelector: ".qrcode-v2 img, .qrcode img, img[src*=qrcode]",
|
||
SuccessWait: 3 * time.Minute,
|
||
},
|
||
}
|
||
return &Executor{base: p}
|
||
}
|
||
|
||
// Platform 平台标识
|
||
func (e *Executor) Platform() string { return "douyin" }
|
||
|
||
// Execute 发布
|
||
func (e *Executor) Execute(ctx context.Context, task exec.Task) exec.Result {
|
||
return e.base.Publish(ctx, task)
|
||
}
|
||
|
||
// SolveChallenge 扫码登录(QR 截图经 onQR 展示)
|
||
func (e *Executor) SolveChallenge(ctx context.Context, ch proto.Challenge, onQR func(qrToken, qrURL string)) (bool, string) {
|
||
return e.base.SolveChallenge(ctx, ch, onQR)
|
||
}
|