feat: 支持返回登录二维码与 Docker 部署 (#155)
* feat: 支持返回登录二维码与 Docker 部署 * feat: 完善扫码登录功能 * fix: 修复当存在已经登录的情况,上层还会启动 goroutine的问题,并把 mcp 的返回增加为图片格式
This commit is contained in:
76
service.go
76
service.go
@@ -2,14 +2,18 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/go-rod/rod"
|
||||
"github.com/mattn/go-runewidth"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/xpzouying/headless_browser"
|
||||
"github.com/xpzouying/xiaohongshu-mcp/browser"
|
||||
"github.com/xpzouying/xiaohongshu-mcp/configs"
|
||||
"github.com/xpzouying/xiaohongshu-mcp/cookies"
|
||||
"github.com/xpzouying/xiaohongshu-mcp/pkg/downloader"
|
||||
"github.com/xpzouying/xiaohongshu-mcp/xiaohongshu"
|
||||
"time"
|
||||
)
|
||||
|
||||
// XiaohongshuService 小红书业务服务
|
||||
@@ -34,6 +38,13 @@ type LoginStatusResponse struct {
|
||||
Username string `json:"username,omitempty"`
|
||||
}
|
||||
|
||||
// LoginQrcodeResponse 登录扫码二维码
|
||||
type LoginQrcodeResponse struct {
|
||||
Timeout string `json:"timeout"`
|
||||
IsLoggedIn bool `json:"is_logged_in"`
|
||||
Img string `json:"img,omitempty"`
|
||||
}
|
||||
|
||||
// PublishResponse 发布响应
|
||||
type PublishResponse struct {
|
||||
Title string `json:"title"`
|
||||
@@ -79,6 +90,54 @@ func (s *XiaohongshuService) CheckLoginStatus(ctx context.Context) (*LoginStatus
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// GetLoginQrcode 获取登录的扫码二维码
|
||||
func (s *XiaohongshuService) GetLoginQrcode(ctx context.Context) (*LoginQrcodeResponse, error) {
|
||||
b := newBrowser()
|
||||
page := b.NewPage()
|
||||
|
||||
deferFunc := func() {
|
||||
_ = page.Close()
|
||||
b.Close()
|
||||
}
|
||||
|
||||
loginAction := xiaohongshu.NewLogin(page)
|
||||
|
||||
img, loggedIn, err := loginAction.FetchQrcodeImage(ctx)
|
||||
if err != nil || loggedIn {
|
||||
defer deferFunc()
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
timeout := 4 * time.Minute
|
||||
|
||||
if !loggedIn {
|
||||
go func() {
|
||||
ctxTimeout, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
defer deferFunc()
|
||||
|
||||
if loginAction.WaitForLogin(ctxTimeout) {
|
||||
if er := saveCookies(page); er != nil {
|
||||
logrus.Errorf("failed to save cookies: %v", er)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
return &LoginQrcodeResponse{
|
||||
Timeout: func() string {
|
||||
if loggedIn {
|
||||
return "0s"
|
||||
}
|
||||
return timeout.String()
|
||||
}(),
|
||||
Img: img,
|
||||
IsLoggedIn: loggedIn,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// PublishContent 发布内容
|
||||
func (s *XiaohongshuService) PublishContent(ctx context.Context, req *PublishRequest) (*PublishResponse, error) {
|
||||
// 验证标题长度
|
||||
@@ -266,3 +325,18 @@ func (s *XiaohongshuService) PostCommentToFeed(ctx context.Context, feedID, xsec
|
||||
func newBrowser() *headless_browser.Browser {
|
||||
return browser.NewBrowser(configs.IsHeadless(), browser.WithBinPath(configs.GetBinPath()))
|
||||
}
|
||||
|
||||
func saveCookies(page *rod.Page) error {
|
||||
cks, err := page.Browser().GetCookies()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
data, err := json.Marshal(cks)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cookieLoader := cookies.NewLoadCookie(cookies.GetCookiesFilePath())
|
||||
return cookieLoader.SaveCookies(data)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user