mirror of
https://github.com/Mrs4s/go-cqhttp.git
synced 2025-05-08 04:55:55 +08:00
feat CQ:video
This commit is contained in:
parent
f501b31152
commit
b717e23626
@ -837,7 +837,7 @@ func (bot *CQBot) CQCanSendRecord() MSG {
|
||||
}
|
||||
|
||||
func (bot *CQBot) CQOcrImage(imageId string) MSG {
|
||||
img, err := bot.makeImageElem(map[string]string{"file": imageId}, true)
|
||||
img, err := bot.makeImageOrVideoElem(map[string]string{"file": imageId}, false, true)
|
||||
if err != nil {
|
||||
log.Warnf("load image error: %v", err)
|
||||
return Failed(100, "LOAD_FILE_ERROR", err.Error())
|
||||
|
11
coolq/bot.go
11
coolq/bot.go
@ -158,6 +158,15 @@ func (bot *CQBot) SendGroupMessage(groupId int64, m *message.SendingMessage) int
|
||||
newElem = append(newElem, gv)
|
||||
continue
|
||||
}
|
||||
if i, ok := elem.(*LocalVideoElement); ok { // todo:cache & multiThread
|
||||
gv, err := bot.Client.UploadGroupShortVideo(groupId, i.video, i.thumb)
|
||||
if err != nil {
|
||||
log.Warnf("警告: 群 %v 消息短视频上传失败: %v", groupId, err)
|
||||
continue
|
||||
}
|
||||
newElem = append(newElem, gv)
|
||||
continue
|
||||
}
|
||||
if i, ok := elem.(*PokeElement); ok {
|
||||
if group := bot.Client.FindGroup(groupId); group != nil {
|
||||
if mem := group.FindMember(i.Target); mem != nil {
|
||||
@ -272,7 +281,7 @@ func (bot *CQBot) SendPrivateMessage(target int64, m *message.SendingMessage) in
|
||||
if i, ok := elem.(*message.VoiceElement); ok {
|
||||
fv, err := bot.Client.UploadPrivatePtt(target, i.Data)
|
||||
if err != nil {
|
||||
log.Warnf("警告: 好友 %v 消息语音上传失败: %v", target, err)
|
||||
log.Warnf("警告: 群 %v 消息语音上传失败: %v", target, err)
|
||||
continue
|
||||
}
|
||||
newElem = append(newElem, fv)
|
||||
|
129
coolq/cqcode.go
129
coolq/cqcode.go
@ -21,6 +21,7 @@ import (
|
||||
|
||||
"github.com/Mrs4s/MiraiGo/binary"
|
||||
"github.com/Mrs4s/MiraiGo/message"
|
||||
"github.com/Mrs4s/MiraiGo/utils"
|
||||
"github.com/Mrs4s/go-cqhttp/global"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/tidwall/gjson"
|
||||
@ -36,6 +37,7 @@ var IgnoreInvalidCQCode = false
|
||||
var SplitUrl = false
|
||||
|
||||
const maxImageSize = 1024 * 1024 * 30 // 30MB
|
||||
const maxVideoSize = 1024 * 1024 * 100 // 100MB
|
||||
|
||||
type PokeElement struct {
|
||||
Target int64
|
||||
@ -77,6 +79,13 @@ type LocalVoiceElement struct {
|
||||
Stream io.ReadSeeker
|
||||
}
|
||||
|
||||
type LocalVideoElement struct {
|
||||
message.ShortVideoElement
|
||||
File string
|
||||
video io.ReadSeeker
|
||||
thumb io.ReadSeeker
|
||||
}
|
||||
|
||||
func (e *GiftElement) Type() message.ElementType {
|
||||
return message.At
|
||||
}
|
||||
@ -426,7 +435,7 @@ func (bot *CQBot) ConvertStringMessage(msg string, group bool) (r []message.IMes
|
||||
}
|
||||
elem, err := bot.ToElement(t, params, group)
|
||||
if err != nil {
|
||||
org := "[" + string(cqCode) + "]"
|
||||
org := "[CQ:" + string(cqCode) + "]"
|
||||
if !IgnoreInvalidCQCode {
|
||||
log.Warnf("转换CQ码 %v 时出现错误: %v 将原样发送.", org, err)
|
||||
r = append(r, message.NewText(org))
|
||||
@ -547,7 +556,7 @@ func (bot *CQBot) ToElement(t string, d map[string]string, group bool) (m interf
|
||||
}
|
||||
return message.NewText(d["text"]), nil
|
||||
case "image":
|
||||
img, err := bot.makeImageElem(d, group)
|
||||
img, err := bot.makeImageOrVideoElem(d, false, group)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -769,11 +778,55 @@ func (bot *CQBot) ToElement(t string, d map[string]string, group bool) (m interf
|
||||
if maxHeight == 0 {
|
||||
maxHeight = 1000
|
||||
}
|
||||
img, err := bot.makeImageElem(d, group)
|
||||
img, err := bot.makeImageOrVideoElem(d, false, group)
|
||||
if err != nil {
|
||||
return nil, errors.New("send cardimage faild")
|
||||
}
|
||||
return bot.makeShowPic(img, source, icon, minWidth, minHeight, maxWidth, maxHeight, group)
|
||||
case "video":
|
||||
if !group {
|
||||
return nil, errors.New("unsupported private short video")
|
||||
}
|
||||
cache := d["cache"]
|
||||
if cache == "" {
|
||||
cache = "1"
|
||||
}
|
||||
file, err := bot.makeImageOrVideoElem(d, true, group)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
v := file.(*LocalVideoElement)
|
||||
if cover, ok := d["cover"]; ok {
|
||||
data, _ := global.FindFile(cover, cache, global.IMAGE_PATH)
|
||||
v.thumb = bytes.NewReader(data)
|
||||
}
|
||||
if v.thumb == nil {
|
||||
_ = global.ExtractCover(v.File, v.File+".jpg")
|
||||
v.thumb, _ = os.Open(v.File + ".jpg")
|
||||
}
|
||||
v.video, _ = os.Open(v.File)
|
||||
_, err = v.video.Seek(4, io.SeekStart)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var header = make([]byte, 4)
|
||||
_, err = v.video.Read(header)
|
||||
if !bytes.Equal(header, []byte{0x66, 0x74, 0x79, 0x70}) { // ftyp
|
||||
_, _ = v.video.Seek(0, io.SeekStart)
|
||||
hash, _ := utils.GetMd5AndLength(v.video)
|
||||
cacheFile := path.Join(global.CACHE_PATH, hex.EncodeToString(hash[:])+".mp4")
|
||||
if global.PathExists(cacheFile) {
|
||||
goto ok
|
||||
}
|
||||
err = global.EncodeMP4(v.File, cacheFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ok:
|
||||
v.video, _ = os.Open(cacheFile)
|
||||
}
|
||||
_, _ = v.video.Seek(0, io.SeekStart)
|
||||
return v, nil
|
||||
default:
|
||||
return nil, errors.New("unsupported cq code: " + t)
|
||||
}
|
||||
@ -815,7 +868,7 @@ func CQCodeUnescapeValue(content string) string {
|
||||
}
|
||||
|
||||
// 图片 elem 生成器,单独拎出来,用于公用
|
||||
func (bot *CQBot) makeImageElem(d map[string]string, group bool) (message.IMessageElement, error) {
|
||||
func (bot *CQBot) makeImageOrVideoElem(d map[string]string, video, group bool) (message.IMessageElement, error) {
|
||||
f := d["file"]
|
||||
if strings.HasPrefix(f, "http") || strings.HasPrefix(f, "https") {
|
||||
cache := d["cache"]
|
||||
@ -832,18 +885,22 @@ func (bot *CQBot) makeImageElem(d map[string]string, group bool) (message.IMessa
|
||||
_ = os.Remove(cacheFile)
|
||||
}
|
||||
thread, _ := strconv.Atoi(c)
|
||||
if err := global.DownloadFileMultiThreading(f, cacheFile, maxImageSize, thread, nil); err != nil {
|
||||
var maxSize = func() int64 {
|
||||
if video {
|
||||
return maxVideoSize
|
||||
}
|
||||
return maxImageSize
|
||||
}()
|
||||
if err := global.DownloadFileMultiThreading(f, cacheFile, maxSize, thread, nil); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if video {
|
||||
return &LocalVideoElement{
|
||||
File: cacheFile,
|
||||
}, nil
|
||||
}
|
||||
return &LocalImageElement{File: cacheFile}, nil
|
||||
}
|
||||
if strings.HasPrefix(f, "base64") {
|
||||
b, err := base64.StdEncoding.DecodeString(strings.ReplaceAll(f, "base64://", ""))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &LocalImageElement{Stream: bytes.NewReader(b)}, nil
|
||||
}
|
||||
if strings.HasPrefix(f, "file") {
|
||||
fu, err := url.Parse(f)
|
||||
if err != nil {
|
||||
@ -856,10 +913,28 @@ func (bot *CQBot) makeImageElem(d map[string]string, group bool) (message.IMessa
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if video {
|
||||
goto videos
|
||||
}
|
||||
if info.Size() == 0 || info.Size() >= maxImageSize {
|
||||
return nil, errors.New("invalid image size")
|
||||
}
|
||||
return &LocalImageElement{File: fu.Path}, nil
|
||||
videos:
|
||||
if info.Size() == 0 || info.Size() >= maxVideoSize {
|
||||
return nil, errors.New("invalid video size")
|
||||
}
|
||||
return &LocalVideoElement{File: fu.Path}, nil
|
||||
}
|
||||
if video { // 短视频视频只支持以上两种
|
||||
return nil, errors.New("invalid video")
|
||||
}
|
||||
if strings.HasPrefix(f, "base64") {
|
||||
b, err := base64.StdEncoding.DecodeString(strings.ReplaceAll(f, "base64://", ""))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &LocalImageElement{Stream: bytes.NewReader(b)}, nil
|
||||
}
|
||||
rawPath := path.Join(global.IMAGE_PATH, f)
|
||||
if !global.PathExists(rawPath) && global.PathExists(path.Join(global.IMAGE_PATH_OLD, f)) {
|
||||
@ -869,7 +944,7 @@ func (bot *CQBot) makeImageElem(d map[string]string, group bool) (message.IMessa
|
||||
rawPath += ".cqimg"
|
||||
}
|
||||
if !global.PathExists(rawPath) && d["url"] != "" {
|
||||
return bot.makeImageElem(map[string]string{"file": d["url"]}, group)
|
||||
return bot.makeImageOrVideoElem(map[string]string{"file": d["url"]}, false, group)
|
||||
}
|
||||
if global.PathExists(rawPath) {
|
||||
file, err := os.Open(rawPath)
|
||||
@ -886,9 +961,11 @@ func (bot *CQBot) makeImageElem(d map[string]string, group bool) (message.IMessa
|
||||
if len(b) < 20 {
|
||||
return nil, errors.New("invalid local file")
|
||||
}
|
||||
var size int32
|
||||
var hash []byte
|
||||
var url string
|
||||
var (
|
||||
size int32
|
||||
hash []byte
|
||||
url string
|
||||
)
|
||||
if path.Ext(rawPath) == ".cqimg" {
|
||||
for _, line := range strings.Split(global.ReadAllText(rawPath), "\n") {
|
||||
kv := strings.SplitN(line, "=", 2)
|
||||
@ -909,27 +986,23 @@ func (bot *CQBot) makeImageElem(d map[string]string, group bool) (message.IMessa
|
||||
}
|
||||
if size == 0 {
|
||||
if url != "" {
|
||||
return bot.makeImageElem(map[string]string{"file": url}, group)
|
||||
return bot.makeImageOrVideoElem(map[string]string{"file": url}, false, group)
|
||||
}
|
||||
return nil, errors.New("img size is 0")
|
||||
}
|
||||
if len(hash) != 16 {
|
||||
return nil, errors.New("invalid hash")
|
||||
}
|
||||
var rsp message.IMessageElement
|
||||
if group {
|
||||
rsp, err := bot.Client.QueryGroupImage(int64(rand.Uint32()), hash, size)
|
||||
rsp, err = bot.Client.QueryGroupImage(int64(rand.Uint32()), hash, size)
|
||||
goto ok
|
||||
}
|
||||
rsp, err = bot.Client.QueryFriendImage(int64(rand.Uint32()), hash, size)
|
||||
ok:
|
||||
if err != nil {
|
||||
if url != "" {
|
||||
return bot.makeImageElem(map[string]string{"file": url}, group)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return rsp, nil
|
||||
}
|
||||
rsp, err := bot.Client.QueryFriendImage(int64(rand.Uint32()), hash, size)
|
||||
if err != nil {
|
||||
if url != "" {
|
||||
return bot.makeImageElem(map[string]string{"file": url}, group)
|
||||
return bot.makeImageOrVideoElem(map[string]string{"file": url}, false, group)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ func EncoderSilk(data []byte) ([]byte, error) {
|
||||
}
|
||||
|
||||
func EncodeMP4(src string, dst string) error {
|
||||
cmd := exec.Command("ffmpeg", "-i", src, "-c", "copy", "-map", "0", dst)
|
||||
cmd := exec.Command("ffmpeg", "-i", src, "-y", "-c", "copy", "-map", "0", dst)
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
|
2
go.mod
2
go.mod
@ -3,7 +3,7 @@ module github.com/Mrs4s/go-cqhttp
|
||||
go 1.15
|
||||
|
||||
require (
|
||||
github.com/Mrs4s/MiraiGo v0.0.0-20210105173234-72521dec9b56
|
||||
github.com/Mrs4s/MiraiGo v0.0.0-20210107163750-ce4834c2ba71
|
||||
github.com/dustin/go-humanize v1.0.0
|
||||
github.com/gin-contrib/pprof v1.3.0
|
||||
github.com/gin-gonic/gin v1.6.3
|
||||
|
2
go.sum
2
go.sum
@ -2,6 +2,8 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMT
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/Mrs4s/MiraiGo v0.0.0-20210105173234-72521dec9b56 h1:U7kObHDk3RfaD81+1hA29gxHf3PfRGpX7dqR2UPNO0c=
|
||||
github.com/Mrs4s/MiraiGo v0.0.0-20210105173234-72521dec9b56/go.mod h1:HW2e375lCQiRwtuA/LV6ZVTsi7co1TRfBn+L5Ow77Bo=
|
||||
github.com/Mrs4s/MiraiGo v0.0.0-20210107163750-ce4834c2ba71 h1:WAVoBY4G2BC5Dyw1A45r/sVua65hsBVYcncR42hEGrk=
|
||||
github.com/Mrs4s/MiraiGo v0.0.0-20210107163750-ce4834c2ba71/go.mod h1:HW2e375lCQiRwtuA/LV6ZVTsi7co1TRfBn+L5Ow77Bo=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
|
Loading…
x
Reference in New Issue
Block a user