feat: add manual Docker release workflow (#187)
- 新增 docker-release.yml workflow,支持手动触发 Docker 镜像构建 - 从 release.yml 中移除自动 Docker 构建,避免镜像膨胀 - 使用语义化版本号策略(如 v1.0.0) - 支持多平台构建(linux/amd64, linux/arm64) - 硬编码公开信息,只需配置 DOCKERHUB_TOKEN secret - 自动标记版本号和 latest 标签 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
106
service.go
106
service.go
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"github.com/go-rod/rod"
|
||||
"github.com/mattn/go-runewidth"
|
||||
"github.com/sirupsen/logrus"
|
||||
@@ -14,6 +13,7 @@ import (
|
||||
"github.com/xpzouying/xiaohongshu-mcp/cookies"
|
||||
"github.com/xpzouying/xiaohongshu-mcp/pkg/downloader"
|
||||
"github.com/xpzouying/xiaohongshu-mcp/xiaohongshu"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -48,28 +48,28 @@ type LoginQrcodeResponse struct {
|
||||
|
||||
// PublishResponse 发布响应
|
||||
type PublishResponse struct {
|
||||
Title string `json:"title"`
|
||||
Content string `json:"content"`
|
||||
Images int `json:"images"`
|
||||
Status string `json:"status"`
|
||||
PostID string `json:"post_id,omitempty"`
|
||||
Title string `json:"title"`
|
||||
Content string `json:"content"`
|
||||
Images int `json:"images"`
|
||||
Status string `json:"status"`
|
||||
PostID string `json:"post_id,omitempty"`
|
||||
}
|
||||
|
||||
// PublishVideoRequest 发布视频请求(仅支持本地单个视频文件)
|
||||
type PublishVideoRequest struct {
|
||||
Title string `json:"title" binding:"required"`
|
||||
Content string `json:"content" binding:"required"`
|
||||
Video string `json:"video" binding:"required"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
Title string `json:"title" binding:"required"`
|
||||
Content string `json:"content" binding:"required"`
|
||||
Video string `json:"video" binding:"required"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
}
|
||||
|
||||
// PublishVideoResponse 发布视频响应
|
||||
type PublishVideoResponse struct {
|
||||
Title string `json:"title"`
|
||||
Content string `json:"content"`
|
||||
Video string `json:"video"`
|
||||
Status string `json:"status"`
|
||||
PostID string `json:"post_id,omitempty"`
|
||||
Title string `json:"title"`
|
||||
Content string `json:"content"`
|
||||
Video string `json:"video"`
|
||||
Status string `json:"status"`
|
||||
PostID string `json:"post_id,omitempty"`
|
||||
}
|
||||
|
||||
// FeedsListResponse Feeds列表响应
|
||||
@@ -219,55 +219,55 @@ func (s *XiaohongshuService) publishContent(ctx context.Context, content xiaohon
|
||||
|
||||
// PublishVideo 发布视频(本地文件)
|
||||
func (s *XiaohongshuService) PublishVideo(ctx context.Context, req *PublishVideoRequest) (*PublishVideoResponse, error) {
|
||||
// 标题长度校验
|
||||
if titleWidth := runewidth.StringWidth(req.Title); titleWidth > 40 {
|
||||
return nil, fmt.Errorf("标题长度超过限制")
|
||||
}
|
||||
// 标题长度校验
|
||||
if titleWidth := runewidth.StringWidth(req.Title); titleWidth > 40 {
|
||||
return nil, fmt.Errorf("标题长度超过限制")
|
||||
}
|
||||
|
||||
// 本地视频文件校验
|
||||
if req.Video == "" {
|
||||
return nil, fmt.Errorf("必须提供本地视频文件")
|
||||
}
|
||||
if _, err := os.Stat(req.Video); err != nil {
|
||||
return nil, fmt.Errorf("视频文件不存在或不可访问: %v", err)
|
||||
}
|
||||
// 本地视频文件校验
|
||||
if req.Video == "" {
|
||||
return nil, fmt.Errorf("必须提供本地视频文件")
|
||||
}
|
||||
if _, err := os.Stat(req.Video); err != nil {
|
||||
return nil, fmt.Errorf("视频文件不存在或不可访问: %v", err)
|
||||
}
|
||||
|
||||
// 构建发布内容
|
||||
content := xiaohongshu.PublishVideoContent{
|
||||
Title: req.Title,
|
||||
Content: req.Content,
|
||||
Tags: req.Tags,
|
||||
VideoPath: req.Video,
|
||||
}
|
||||
// 构建发布内容
|
||||
content := xiaohongshu.PublishVideoContent{
|
||||
Title: req.Title,
|
||||
Content: req.Content,
|
||||
Tags: req.Tags,
|
||||
VideoPath: req.Video,
|
||||
}
|
||||
|
||||
// 执行发布
|
||||
if err := s.publishVideo(ctx, content); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// 执行发布
|
||||
if err := s.publishVideo(ctx, content); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp := &PublishVideoResponse{
|
||||
Title: req.Title,
|
||||
Content: req.Content,
|
||||
Video: req.Video,
|
||||
Status: "发布完成",
|
||||
}
|
||||
return resp, nil
|
||||
resp := &PublishVideoResponse{
|
||||
Title: req.Title,
|
||||
Content: req.Content,
|
||||
Video: req.Video,
|
||||
Status: "发布完成",
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// publishVideo 执行视频发布
|
||||
func (s *XiaohongshuService) publishVideo(ctx context.Context, content xiaohongshu.PublishVideoContent) error {
|
||||
b := newBrowser()
|
||||
defer b.Close()
|
||||
b := newBrowser()
|
||||
defer b.Close()
|
||||
|
||||
page := b.NewPage()
|
||||
defer page.Close()
|
||||
page := b.NewPage()
|
||||
defer page.Close()
|
||||
|
||||
action, err := xiaohongshu.NewPublishVideoAction(page)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
action, err := xiaohongshu.NewPublishVideoAction(page)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return action.PublishVideo(ctx, content)
|
||||
return action.PublishVideo(ctx, content)
|
||||
}
|
||||
|
||||
// ListFeeds 获取Feeds列表
|
||||
|
||||
Reference in New Issue
Block a user