Files

244 lines
7.6 KiB
Go

package mpeg4gif
import (
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"strings"
"trbot/plugins/sticker_download/convert"
"trbot/plugins/sticker_download/lock"
"trbot/utils"
"trbot/utils/configs"
"trbot/utils/flaterr"
"trbot/utils/handler_params"
"github.com/go-telegram/bot"
"github.com/go-telegram/bot/models"
"github.com/rs/zerolog"
)
var MP4Cache_path string = filepath.Join(configs.CacheDir, "mp4/")
var GIFCache_path string = filepath.Join(configs.CacheDir, "mp4_GIF/")
func ConvertMP4ToGifHandler(opts *handler_params.Message) error {
if opts.Message == nil || opts.Message.Animation == nil {
return nil
}
logger := zerolog.Ctx(opts.Ctx).
With().
Str("pluginName", "StickerDownload").
Str(utils.GetCurrentFuncName()).
Dict(utils.GetUserDict(opts.Message.From)).
Logger()
var handlerErr flaterr.MultErr
if lock.Download.TryLock() {
// 成功获取到锁,直接继续下载不发送提示信息
defer lock.Download.Unlock()
} else {
_, err := opts.Thebot.SendMessage(opts.Ctx, &bot.SendMessageParams{
ChatID: opts.Message.From.ID,
Text: "已加入下载队列,请稍候...",
ReplyParameters: &models.ReplyParameters{ MessageID: opts.Message.ID },
})
if err != nil {
logger.Error().
Err(err).
Str("content", "gif download in progress notice").
Msg(flaterr.SendMessage.Str())
handlerErr.Addt(flaterr.SendMessage, "gif download in progress notice", err)
}
// 发送信息提示等待后,阻断等待锁
lock.Download.Lock()
defer lock.Download.Unlock()
}
logger.Info().
Msg("Start download GIF")
GIFFile, err := downloadGifHandler(opts)
if err != nil {
logger.Error().
Err(err).
Msg("Error when downloading MP4")
handlerErr.Addf("error when downloading MP4: %w", err)
_, err = opts.Thebot.SendMessage(opts.Ctx, &bot.SendMessageParams{
ChatID: opts.Message.From.ID,
Text: fmt.Sprintf("下载 GIF 时发生了一些错误\n<blockquote expandable>Failed to download MP4: %s</blockquote>", utils.IgnoreHTMLTags(err.Error())),
ParseMode: models.ParseModeHTML,
})
if err != nil {
logger.Error().
Err(err).
Str("content", "MP4 download error").
Msg(flaterr.SendMessage.Str())
handlerErr.Addt(flaterr.SendMessage, "MP4 download error", err)
}
} else {
_, err = opts.Thebot.SendDocument(opts.Ctx, &bot.SendDocumentParams{
ChatID: opts.Message.From.ID,
Caption: fmt.Sprintf("视频长度 %d 秒\n分辨率 %d*%dpx", opts.Message.Animation.Duration, opts.Message.Animation.Width, opts.Message.Animation.Height),
Document: &models.InputFileUpload{Filename: strings.Split(opts.Message.Animation.FileName, ".")[0] + ".GIF", Data: GIFFile},
ParseMode: models.ParseModeHTML,
ReplyParameters: &models.ReplyParameters{MessageID: opts.Message.ID},
DisableNotification: true,
DisableContentTypeDetection: true, // Prevent the server convert GIF to MP4
})
if err != nil {
logger.Error().
Err(err).
Str("content", "GIF file").
Msg(flaterr.SendDocument.Str())
handlerErr.Addt(flaterr.SendDocument, "GIF file", err)
}
}
return handlerErr.Flat()
}
func downloadGifHandler(opts *handler_params.Message) (io.Reader, error) {
logger := zerolog.Ctx(opts.Ctx).
With().
Str("pluginName", "StickerDownload").
Str(utils.GetCurrentFuncName()).
Logger()
var originFullPath string = filepath.Join(MP4Cache_path, opts.Message.Animation.FileID+".MP4")
var toGifFullPath string = filepath.Join(GIFCache_path, opts.Message.Animation.FileID+".GIF")
_, err := os.Stat(originFullPath) // 检查是否已缓存
if err != nil {
// 如果文件不存在,进行下载,否则返回错误
if os.IsNotExist(err) {
// 日志提示该文件没被缓存,正在下载
logger.Debug().
Str("originFullPath", originFullPath).
Msg("GIF file not cached, downloading")
// 从服务器获取文件信息
fileinfo, err := opts.Thebot.GetFile(opts.Ctx, &bot.GetFileParams{FileID: opts.Message.Animation.FileID})
if err != nil {
logger.Error().
Err(err).
Str("fileID", opts.Message.Animation.FileID).
Msg(flaterr.GetFile.Str())
return nil, fmt.Errorf(flaterr.GetFile.Fmt(), opts.Message.Animation.FileID, err)
}
// 组合链接下载贴纸源文件
resp, err := http.Get(opts.Thebot.FileDownloadLink(fileinfo))
if err != nil {
logger.Error().
Err(err).
Str("filePath", fileinfo.FilePath).
Msg("Failed to download GIF file")
return nil, fmt.Errorf("failed to download GIF file [%s]: %w", fileinfo.FilePath, err)
}
defer resp.Body.Close()
// 创建保存贴纸的目录
err = os.MkdirAll(MP4Cache_path, 0755)
if err != nil {
logger.Error().
Err(err).
Str("directory", MP4Cache_path).
Msg("Failed to create GIF directory to save GIF")
return nil, fmt.Errorf("failed to create directory [%s] to save GIF: %w", MP4Cache_path, err)
}
// 创建贴纸空文件
downloadedGif, err := os.Create(originFullPath)
if err != nil {
logger.Error().
Err(err).
Str("originFullPath", originFullPath).
Msg("Failed to create GIF file")
return nil, fmt.Errorf("failed to create GIF file [%s]: %w", originFullPath, err)
}
defer downloadedGif.Close()
// 将下载的原贴纸写入空文件
_, err = io.Copy(downloadedGif, resp.Body)
if err != nil {
logger.Error().
Err(err).
Str("originFullPath", originFullPath).
Msg("Failed to writing GIF data to file")
return nil, fmt.Errorf("failed to writing GIF data to file [%s]: %w", originFullPath, err)
}
} else {
logger.Error().
Err(err).
Str("originFullPath", originFullPath).
Msg("Failed to read cached GIF file info")
return nil, fmt.Errorf("failed to read cached GIF file [%s] info: %w", originFullPath, err)
}
} else {
// 文件已存在,跳过下载
logger.Debug().
Str("originFullPath", originFullPath).
Msg("MP4 file already cached")
}
_, err = os.Stat(toGifFullPath) // 使用目录提前检查一下是否已经转换过
if err != nil {
// 如果提示不存在,进行转换
if os.IsNotExist(err) {
// 日志提示该文件没转换,正在转换
logger.Debug().
Str("toGifFullPath", toGifFullPath).
Msg("MP4 file does not convert, converting")
// 创建保存贴纸的目录
err = os.MkdirAll(GIFCache_path, 0755)
if err != nil {
logger.Error().
Err(err).
Str("GIFCache_path", GIFCache_path).
Msg("Failed to create directory to convert GIF")
return nil, fmt.Errorf("failed to create directory [%s] to convert GIF: %w", GIFCache_path, err)
}
// 读取原贴纸文件,转码后存储到 png 格式贴纸的完整目录
err = convert.MP4ToGif(originFullPath, toGifFullPath)
if err != nil {
logger.Error().
Err(err).
Str("originFullPath", originFullPath).
Msg("Failed to convert MP4 to GIF")
return nil, fmt.Errorf("failed to convert MP4 [%s] to GIF: %w", originFullPath, err)
}
} else {
// 其他错误
logger.Error().
Err(err).
Str("toGifFullPath", toGifFullPath).
Msg("Failed to read converted GIF file info")
return nil, fmt.Errorf("failed to read converted GIF file [%s] info : %w", toGifFullPath, err)
}
} else {
// 文件存在,跳过转换
logger.Debug().
Str("toGifFullPath", toGifFullPath).
Msg("MP4 file already converted to GIF")
}
data, err := os.Open(toGifFullPath)
if err != nil {
logger.Error().
Err(err).
Str("toGifFullPath", toGifFullPath).
Msg("Failed to open converted GIF file")
return nil, fmt.Errorf("failed to open converted GIF file [%s]: %w", toGifFullPath, err)
}
return data, nil
}