// 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" }