117 lines
3.3 KiB
Go
117 lines
3.3 KiB
Go
// cdnbase 三平台执行器公共底座:保险库 + 浏览器档案目录 + 代理 + 执行入口。
|
|
package cdnbase
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"path/filepath"
|
|
|
|
"everypublish/agentcore/internal/exec"
|
|
"everypublish/agentcore/internal/exec/cdp"
|
|
"everypublish/agentcore/internal/vault"
|
|
"everypublish/shared/proto"
|
|
)
|
|
|
|
// Platform 三平台执行器公共底座
|
|
type Platform struct {
|
|
Vault *vault.Vault
|
|
RootDir string // 浏览器档案根目录(每账号子目录)
|
|
Proxy string // 账号固定 IP 代理
|
|
ChromePath string
|
|
Headless bool
|
|
ReceiptDir string // 截图回执目录
|
|
Name string // 平台名(日志)
|
|
PublishCfg cdp.PublishConfig
|
|
LoginCfg cdp.QRLoginConfig
|
|
LoginDomain string // 登录 cookie 域名
|
|
}
|
|
|
|
// credentials 保险库凭据
|
|
type credentials struct {
|
|
Cookies string `json:"cookies"`
|
|
}
|
|
|
|
// loadCookies 读账号 cookie(无则空,触发扫码)
|
|
func (p *Platform) loadCookies(accountID string) string {
|
|
raw, err := p.Vault.Load(accountID)
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
var c credentials
|
|
if json.Unmarshal(raw, &c) != nil {
|
|
return ""
|
|
}
|
|
return c.Cookies
|
|
}
|
|
|
|
// profileDir 账号独立档案目录
|
|
func (p *Platform) profileDir(accountID string) string {
|
|
return filepath.Join(p.RootDir, p.Name, accountID)
|
|
}
|
|
|
|
// Publish 通用发布入口(下载素材 → 启动浏览器 → 发布 → 回传)
|
|
func (p *Platform) Publish(ctx context.Context, task exec.Task) exec.Result {
|
|
fail := func(err string) exec.Result {
|
|
return exec.Result{TaskID: task.TaskID, Status: "failed", Error: err}
|
|
}
|
|
cookies := p.loadCookies(task.AccountID)
|
|
if len(task.MaterialURLs) == 0 {
|
|
return fail("任务缺少素材")
|
|
}
|
|
videoPath, cleanup, err := cdp.DownloadFile(ctx, task.MaterialURLs[0])
|
|
if err != nil {
|
|
return fail("素材下载失败: " + err.Error())
|
|
}
|
|
defer cleanup()
|
|
|
|
br, err := cdp.Launch(ctx, cdp.Options{
|
|
UserDataDir: p.profileDir(task.AccountID),
|
|
Proxy: p.Proxy,
|
|
Headless: p.Headless,
|
|
ChromePath: p.ChromePath,
|
|
})
|
|
if err != nil {
|
|
return fail("浏览器启动失败: " + err.Error())
|
|
}
|
|
defer br.Close()
|
|
|
|
cfg := p.PublishCfg
|
|
cfg.Platform = p.Name
|
|
cfg.ReceiptDir = p.ReceiptDir
|
|
res, err := br.Publish(ctx, cfg, videoPath, task.Title, task.Content, task.Tags, cookies, p.LoginDomain)
|
|
if err != nil {
|
|
return fail("发布失败: " + err.Error())
|
|
}
|
|
return exec.Result{
|
|
TaskID: task.TaskID,
|
|
Status: "success",
|
|
PublishedURL: res.URL,
|
|
Receipts: res.Receipts,
|
|
}
|
|
}
|
|
|
|
// SolveChallenge CDP 扫码登录:二维码截图经 onQR 展示 → 轮询登录 → 保存 cookie
|
|
func (p *Platform) SolveChallenge(ctx context.Context, ch proto.Challenge, onQR func(qrToken, qrURL string)) (bool, string) {
|
|
br, err := cdp.Launch(ctx, cdp.Options{
|
|
UserDataDir: p.profileDir(ch.AccountID),
|
|
Proxy: p.Proxy,
|
|
Headless: p.Headless,
|
|
ChromePath: p.ChromePath,
|
|
})
|
|
if err != nil {
|
|
cdp.Log("%s: 扫码浏览器启动失败: %v", p.Name, err)
|
|
return false, ""
|
|
}
|
|
defer br.Close()
|
|
cookies, err := br.QRLogin(ctx, p.LoginCfg, onQR)
|
|
if err != nil {
|
|
cdp.Log("%s: 扫码登录失败: %v", p.Name, err)
|
|
return false, ""
|
|
}
|
|
if cookies == "" {
|
|
return false, ""
|
|
}
|
|
_ = p.Vault.Save(ch.AccountID, []byte(`{"cookies":"`+cdp.EscapeJSON(cookies)+`"}`))
|
|
return true, "confirmed"
|
|
}
|