fonchain-fiee/pkg/service/import/publish.go
2025-08-11 13:29:49 +08:00

341 lines
10 KiB
Go

package imports
import (
"context"
"fmt"
"fonchain-fiee/api/accountFiee"
apiCast "fonchain-fiee/api/cast"
"fonchain-fiee/api/files"
"fonchain-fiee/pkg/config"
"fonchain-fiee/pkg/model"
modelCast "fonchain-fiee/pkg/model/cast"
"fonchain-fiee/pkg/service"
"fonchain-fiee/pkg/service/cast"
"fonchain-fiee/pkg/service/upload"
"log"
"os"
"path/filepath"
"strconv"
"strings"
"time"
"github.com/gin-gonic/gin"
"github.com/mholt/archiver"
"github.com/xuri/excelize/v2"
)
func ImportPublish(c *gin.Context) {
// 1. 上传画家短视频详情文件
excelFile, err := c.FormFile("excel")
if err != nil {
c.JSON(400, gin.H{"error": "缺少 Excel 文件 excel"})
return
}
zipFile, err := c.FormFile("zip")
if err != nil {
c.JSON(400, gin.H{"error": "缺少 ZIP 文件"})
return
}
// 2. 保存临时文件
tempDir := "tmp"
os.MkdirAll(tempDir, 0755)
excelPath := filepath.Join(tempDir, "artists.xlsx")
zipPath := filepath.Join(tempDir, "archive.zip")
if err = c.SaveUploadedFile(excelFile, excelPath); err != nil {
c.JSON(500, gin.H{"error": "保存 Excel 失败"})
return
}
if err = c.SaveUploadedFile(zipFile, zipPath); err != nil {
c.JSON(500, gin.H{"error": "保存 ZIP 文件失败"})
return
}
// 3. 解压 ZIP
unzipPath := filepath.Join(tempDir, "unzipped")
if _, err = os.Stat(unzipPath); err == nil {
// 路径已存在,删除
if removeErr := os.RemoveAll(unzipPath); removeErr != nil {
c.JSON(500, gin.H{"error": "清理已存在解压目录失败: " + removeErr.Error()})
return
}
}
os.MkdirAll(unzipPath, 0755)
if err = archiver.Unarchive(zipPath, unzipPath); err != nil {
c.JSON(500, gin.H{"error": "解压 ZIP 失败: " + err.Error()})
return
}
entries, err := os.ReadDir(unzipPath)
if err != nil || len(entries) == 0 {
c.JSON(500, gin.H{"error": "读取解压目录失败或目录为空"})
return
}
if len(entries) == 1 && entries[0].IsDir() {
// 说明解压后多了一层目录,把它设为新的 unzipPath
unzipPath = filepath.Join(unzipPath, entries[0].Name())
}
defer os.RemoveAll(tempDir)
// 4. 读取 Excel 画家名单, 匹配视频和图片
artists, err := readArtistVideoInfo(excelPath, unzipPath)
if err != nil {
c.JSON(500, gin.H{"error": "读取 Excel 失败"})
return
}
// 5.发布视频
var failedRecords []failedRecord
for _, artist := range artists {
var infoResp *accountFiee.UserInfoResponse
var err error
list, err := service.AccountFieeProvider.UserList(context.Background(), &accountFiee.UserListRequest{
Name: artist.Name,
})
if err != nil {
failedRecords = append(failedRecords, failedRecord{
name: artist.Name,
msg: fmt.Sprintf("获取用户信息失败: %s", err.Error()),
})
log.Printf(fmt.Sprintf("获取用户信息失败: %s", err.Error()))
continue
}
if list != nil && len(list.UserList) > 0 {
infoResp, err = service.AccountFieeProvider.Info(context.Background(), &accountFiee.InfoRequest{
ID: list.UserList[0].Id,
Domain: "app",
})
if err != nil {
failedRecords = append(failedRecords, failedRecord{
name: artist.Name,
msg: fmt.Sprintf("获取用户信息失败: %s", err.Error()),
})
log.Printf(fmt.Sprintf("获取用户信息失败: %s", err.Error()))
continue
}
}
if err = cast.CheckUserBundleBalance(int32(list.UserList[0].Id), modelCast.BalanceTypeAccountValue); err != nil {
failedRecords = append(failedRecords, failedRecord{
name: artist.Name,
msg: fmt.Sprintf("检查用户账户数量: %s", err.Error()),
})
log.Printf(fmt.Sprintf("检查用户账户数量: %s", err.Error()))
continue
}
//自媒体账号
accountList, err := service.CastProvider.MediaUserList(c, &apiCast.MediaUserListReq{
ArtistUuid: strconv.FormatUint(list.UserList[0].Id, 10),
})
if err != nil || accountList == nil {
failedRecords = append(failedRecords, failedRecord{
name: artist.Name,
msg: fmt.Sprintf("自媒体账号数量获取失败: %s,账号数量:%d", err.Error(), len(accountList.Data)),
})
log.Printf(fmt.Sprintf("自媒体账号数量获取失败: %s,账号数量:%d", err.Error(), len(accountList.Data)))
continue
}
mediaAccountUuids := []string{}
mediaAccountNames := []string{}
platformIDs := []apiCast.PlatformIDENUM{}
for _, info := range accountList.Data {
mediaAccountUuids = append(mediaAccountUuids, info.MediaAccountUuid)
mediaAccountNames = append(mediaAccountNames, info.PlatformUserName)
platformIDs = append(platformIDs, apiCast.PlatformIDENUM(info.PlatformID))
}
newCtx := cast.NewCtxWithUserInfo(c)
_, err = service.CastProvider.UpdateWorkVideo(newCtx, &apiCast.UpdateWorkVideoReq{
Title: artist.Title,
Content: artist.Title,
VideoUrl: artist.Video,
CoverUrl: artist.Img,
MediaAccountUuids: mediaAccountUuids,
MediaAccountNames: mediaAccountNames,
PlatformIDs: platformIDs,
PublishConfig1: &apiCast.PublishConfig{
CanComment: 1,
CanJoin: 1,
CanQuote: 1,
ForbidComment: 2,
IsAI: 1,
PublicType: 1,
},
PublishConfig2: &apiCast.PublishConfig{
CanComment: 1,
CanJoin: 1,
CanQuote: 1,
ForbidComment: 2,
IsAI: 1,
PublicType: 1,
},
PublishConfig3: &apiCast.PublishConfig{
CanComment: 1,
CanJoin: 1,
CanQuote: 1,
ForbidComment: 1,
IsAI: 1,
PublicType: 1,
},
Action: "submit",
ArtistUuid: strconv.FormatUint(list.UserList[0].Id, 10),
ArtistName: infoResp.Name,
ArtistPhone: infoResp.TelNum,
ArtistPhoneAreaCode: infoResp.TelAreaCode,
Source: 2,
})
if err != nil {
failedRecords = append(failedRecords, failedRecord{
name: artist.Name,
msg: fmt.Sprintf("发布"+artist.Name+"视频"+artist.Title+"失败: %s", err.Error()),
})
log.Printf(fmt.Sprintf("发布"+artist.Name+"视频"+artist.Title+"失败: %s", err.Error()))
continue
}
}
// 6. 返回结果
service.Success(c, failedRecords)
}
func readArtistVideoInfo(excelPath, unzipPath string) ([]ArtistMedia, error) {
log.Println(unzipPath)
f, err := excelize.OpenFile(excelPath)
if err != nil {
return nil, err
}
defer f.Close()
sheetName := f.GetSheetName(0)
rows, err := f.GetRows(sheetName)
if err != nil {
return nil, err
}
log.Println("start read excel")
var artists []ArtistMedia
for i, row := range rows {
if i == 0 || i == 1 || len(row) < 2 {
continue
}
if i == 165 {
break
}
id, _ := f.GetCellValue(sheetName, fmt.Sprintf("A%d", i+1))
if id != "" {
id = strings.TrimSpace(id)
}
artistName, _ := f.GetCellValue(sheetName, fmt.Sprintf("B%d", i+1))
if artistName != "" {
artistName = strings.TrimSpace(artistName)
}
title, _ := f.GetCellValue(sheetName, fmt.Sprintf("C%d", i+1))
if title != "" {
title = strings.TrimSpace(title)
}
artists = append(artists, ArtistMedia{
Id: id,
Name: artistName,
Title: title,
})
}
artists, err = matchArtistMedia(artists, unzipPath)
return artists, nil
}
func matchArtistMedia(artists []ArtistMedia, unzipPath string) ([]ArtistMedia, error) {
var err error
var res []ArtistMedia
for _, artist := range artists {
oldImgPath := fmt.Sprintf("%s/%s/%s.jpg", unzipPath, artist.Name, artist.Id)
oldVideoPath := fmt.Sprintf("%s/%s/%s.mp4", unzipPath, artist.Name, artist.Id)
// 检查源文件是否存在
if _, err = os.Stat(oldImgPath); os.IsNotExist(err) {
continue
}
if _, err = os.Stat(oldVideoPath); os.IsNotExist(err) {
continue
}
baseDir := filepath.Join(unzipPath, artist.Name)
if err = os.MkdirAll(baseDir, 0755); err != nil {
log.Println("创建目录失败:", err)
return nil, err
}
log.Println("创建目录成功:", baseDir)
// 重命名
now := time.Now().Unix()
imgPath := fmt.Sprintf("%s/%s/%s_%d.jpg", unzipPath, artist.Name, artist.Id, now)
videoPath := fmt.Sprintf("%s/%s/%s_%d.mp4", unzipPath, artist.Name, artist.Id, now)
if err = os.Rename(oldImgPath, imgPath); err != nil {
log.Println("图片:"+oldImgPath+"重命名失败:", err)
return nil, err
}
if err = os.Rename(oldVideoPath, videoPath); err != nil {
log.Println("视频:"+oldVideoPath+"重命名失败:", err)
return nil, err
}
//转为url
content, err := os.ReadFile(videoPath)
if err != nil {
return nil, err
}
if err = UploadToAnotherService(context.Background(), content, filepath.Base(videoPath)); err != nil {
log.Println("上传视频失败:", err)
return nil, err
}
var httpType string
if config.IsHttps {
url := "saas.fiee.com"
httpType = fmt.Sprintf("%s%s", model.HttpsType, url)
} else {
url := "114.218.158.24:9020"
httpType = fmt.Sprintf("%s%s", model.HttpType, url)
}
baseUrl := fmt.Sprintf("%s/api/fiee/resource/raw/", httpType)
videoUrl := baseUrl + filepath.Base(videoPath)
imgUrl, err := upload.PutBos(filepath.ToSlash(imgPath), "image", false)
if err != nil {
log.Println("上传图片失败:", err)
return nil, err
}
tmp := artist
tmp.Id = artist.Id
tmp.Name = artist.Name
tmp.Title = artist.Title
tmp.Img = imgUrl
//tmp.Video = filepath.ToSlash(videoPath)
tmp.Video = videoUrl
res = append(res, tmp)
}
return res, nil
}
func UploadToAnotherService(ctx context.Context, fileData []byte, path string) error {
const chunkSize = 4*1024*1024 - 100
_, err := service.FilesProvider.TusCreate(ctx, &files.TusCreateReq{
Path: path,
UserSpacePath: "",
Override: true,
})
if err != nil {
return err
}
log.Println("create success ......**********")
offset := int64(0)
totalSize := int64(len(fileData))
for offset < totalSize {
end := offset + chunkSize
if end > totalSize {
end = totalSize
}
chunk := fileData[offset:end]
_, err = service.FilesProvider.TusUpload(ctx, &files.TusUploadReq{
Path: path,
UploadOffset: offset,
Content: chunk,
UserSpacePath: "",
})
if err != nil {
return fmt.Errorf("上传 offset=%d chunk 失败: %w", offset, err)
}
log.Printf("upload chunk: %d - %d success\n", offset, end)
offset = end
}
return nil
}