geoGo/internal/publisher/js.go

318 lines
7.2 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package publisher
import (
"context"
"fmt"
"geo/internal/config"
"log"
"strings"
"time"
"github.com/go-rod/rod"
"github.com/go-rod/rod/lib/proto"
)
type JianshuPublisher struct {
*BasePublisher
}
func NewJianshuPublisher(ctx context.Context, task *TaskParams, cfg *config.Config, logger *log.Logger) PublisherInerface {
return &JianshuPublisher{NewBasePublisher(ctx, task, cfg, logger)}
}
func (p *JianshuPublisher) CheckLoginStatus() bool {
currentURL := p.GetCurrentURL()
if strings.Contains(currentURL, p.LoginURL) {
return false
}
return true
}
func (p *JianshuPublisher) WaitLogin() (bool, string) {
p.LogInfo("开始等待登录...")
if err := p.SetupDriver(); err != nil {
return false, fmt.Sprintf("浏览器启动失败: %v", err)
}
defer p.Close()
p.Page.MustNavigate(p.EditorURL)
p.Sleep(10)
if p.CheckLoginStatus() {
p.SaveCookies()
return true, "already_logged_in"
}
startTime := time.Now()
timeout := 240
for time.Since(startTime) < time.Duration(timeout)*time.Second {
if p.CheckLoginStatus() {
p.SaveCookies()
return true, "login_success"
}
p.SleepMs(1000)
}
return false, "登录超时,请检查网络或账号状态"
}
func (p *JianshuPublisher) waitForEditorReady() error {
p.LogInfo("等待编辑器加载...")
plusIcon, err := p.WaitForElementVisible(".fa-plus-circle", 10)
if err == nil && plusIcon != nil {
p.JSClick(plusIcon)
p.LogInfo("已点击新建文章按钮")
p.Sleep(2)
} else {
return fmt.Errorf("未找到新建文章按钮")
}
startTime := time.Now()
for time.Since(startTime) < time.Duration(60)*time.Second {
editor, _ := p.WaitForElementVisible("#arthur-editor", 2)
if editor != nil {
p.LogInfo("编辑器加载完成")
return nil
}
p.SleepMs(1000)
}
p.LogInfo("编辑器加载超时")
return nil
}
func (p *JianshuPublisher) inputTitle() error {
p.LogInfo("输入文章标题...")
today := time.Now().Format("2006-01-02")
selector := fmt.Sprintf("input[value='%s']", today)
titleInput, err := p.WaitForElementVisible(selector, 5)
if err != nil {
return fmt.Errorf("未找到标题输入框")
}
p.LogInfo("找到标题输入框")
p.ClearInput(titleInput)
p.SleepMs(300)
titleInput.Input("")
p.SleepMs(300)
titleInput.Input(p.Title)
return nil
}
func (p *JianshuPublisher) inputContent() error {
p.LogInfo("输入文章正文...")
if p.Content == "" {
p.LogInfo("内容为空")
return fmt.Errorf("内容为空")
}
textArea, err := p.WaitForElementVisible("#arthur-editor", 10)
if err != nil {
return fmt.Errorf("未找到文本输入框: %v", err)
}
p.LogInfo("找到文本输入框")
p.JSClick(textArea)
p.SleepMs(500)
textArea.Input(p.Content)
p.SleepMs(2000)
p.LogInfo(fmt.Sprintf("内容已输入,长度: %d", len(p.Content)))
return nil
}
func (p *JianshuPublisher) clickPublish() error {
p.LogInfo("点击发布按钮...")
publishSelectors := []string{
"a[data-action='publicize']",
".publish-btn",
".submit-btn",
"button:contains('发布')",
".btn-publish",
"[class*='publish'] button",
"a:contains('发布文章')",
}
var publishBtn *rod.Element
for _, selector := range publishSelectors {
publishBtn, _ = p.WaitForElementClickable(selector, 5)
if publishBtn != nil {
visible, _ := publishBtn.Visible()
if visible {
p.LogInfo(fmt.Sprintf("找到发布按钮: %s", selector))
break
}
}
}
if publishBtn == nil {
links, _ := p.Page.Elements("a")
for _, link := range links {
text, _ := link.Text()
if strings.Contains(text, "发布文章") || strings.Contains(text, "发布") {
publishBtn = link
p.LogInfo("通过遍历链接找到发布按钮")
break
}
}
}
if publishBtn == nil {
return fmt.Errorf("未找到发布按钮")
}
if err := publishBtn.Click(proto.InputMouseButtonLeft, 1); err != nil {
if err := p.JSClick(publishBtn); err != nil {
return fmt.Errorf("点击发布按钮失败: %v", err)
}
}
p.LogInfo("已点击发布按钮")
p.Sleep(3)
return nil
}
func (p *JianshuPublisher) handlePublishDialog() error {
p.LogInfo("处理发布弹窗...")
dialogSelectors := []string{
".ant-modal",
".el-dialog",
".publish-dialog",
"[class*='dialog']",
"[role='dialog']",
}
var dialog *rod.Element
for _, selector := range dialogSelectors {
dialog, _ = p.WaitForElementVisible(selector, 5)
if dialog != nil {
p.LogInfo(fmt.Sprintf("找到发布弹窗: %s", selector))
break
}
}
if dialog == nil {
p.LogInfo("未发现发布弹窗")
return nil
}
confirmSelectors := []string{
"button:contains('确认发布')",
"button:contains('确定')",
"button:contains('发布')",
".confirm-btn",
".ok-btn",
}
for _, selector := range confirmSelectors {
confirmBtn, err := p.WaitForElementClickable(selector, 3)
if err == nil && confirmBtn != nil {
p.JSClick(confirmBtn)
p.LogInfo("已确认发布")
p.Sleep(2)
return nil
}
}
closeSelectors := []string{
".ant-modal-close",
".el-dialog__close",
".close-btn",
}
for _, selector := range closeSelectors {
closeBtn, err := p.WaitForElementClickable(selector, 2)
if err == nil && closeBtn != nil {
p.JSClick(closeBtn)
p.LogInfo("关闭发布弹窗")
p.SleepMs(1000)
break
}
}
return nil
}
func (p *JianshuPublisher) waitForPublishResult(timeout int) (bool, string) {
p.LogInfo("等待发布结果...")
startTime := time.Now()
for time.Since(startTime) < time.Duration(timeout)*time.Second {
currentURL := p.GetCurrentURL()
successKeywords := []string{"notes", "articles", "success", "published"}
for _, keyword := range successKeywords {
if strings.Contains(strings.ToLower(currentURL), keyword) {
p.LogInfo(fmt.Sprintf("发布成功URL: %s", currentURL))
return true, "发布成功"
}
}
successSelectors := []string{
".ant-message-success",
".el-message--success",
".toast-success",
"[class*='success']",
}
for _, selector := range successSelectors {
elems, _ := p.Page.Elements(selector)
for _, elem := range elems {
visible, _ := elem.Visible()
if visible {
text, _ := elem.Text()
if strings.Contains(text, "成功") || strings.Contains(strings.ToLower(text), "success") || strings.Contains(text, "已发布") {
p.LogInfo(fmt.Sprintf("发布成功: %s", text))
return true, text
}
}
}
}
p.SleepMs(1000)
}
return false, "发布结果未知(超时)"
}
func (p *JianshuPublisher) PublishNote() (bool, string) {
p.StartNote()
if err := p.SetupDriver(); err != nil {
return false, fmt.Sprintf("浏览器启动失败: %v", err)
}
defer p.Close()
steps := []struct {
name string
fn func() error
}{
{"初始化页面", p.InitPage},
{"创建编辑器", p.waitForEditorReady},
{"输入标题", p.inputTitle},
{"导入内容", p.inputContent},
{"点击发布", p.clickPublish},
}
for _, step := range steps {
if err := step.fn(); err != nil {
p.LogStep(step.name, false, err.Error())
return false, fmt.Sprintf("%s失败: %v", step.name, err)
}
p.LogStep(step.name, true, "")
}
success, message := p.waitForPublishResult(60)
if success {
p.LogInfo(fmt.Sprintf("🎉 发布成功!%s", message))
return true, message
}
p.LogError(fmt.Sprintf("发布失败: %s", message))
return false, message
}