Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test4 #54

Merged
merged 107 commits into from
Nov 8, 2023
Merged
Changes from 1 commit
Commits
Show all changes
107 commits
Select commit Hold shift + click to select a range
fad0d50
Compiled main.go and pushed changes
Hoshinonyaruko Oct 23, 2023
fda2572
test
Hoshinonyaruko Oct 23, 2023
34cfac1
适配了频道私聊,用bolt数据库取代ini
Hoshinonyaruko Oct 23, 2023
7fc1f10
适配了nonebot2
Hoshinonyaruko Oct 24, 2023
28f9a73
Merge branch 'main' of https://github.com/Hoshinonyaruko/Gensokyo
Hoshinonyaruko Oct 24, 2023
9fadda4
适配私域
Hoshinonyaruko Oct 24, 2023
1336c6a
add license
Hoshinonyaruko Oct 24, 2023
b094949
add a lot
Hoshinonyaruko Oct 25, 2023
f4787f5
Resolved merge conflicts
Hoshinonyaruko Oct 25, 2023
86698c6
trss support
Hoshinonyaruko Oct 26, 2023
045f3e9
fix
Hoshinonyaruko Oct 26, 2023
618561c
add action
Hoshinonyaruko Oct 26, 2023
7e803aa
add action
Hoshinonyaruko Oct 26, 2023
ece4cef
add action
Hoshinonyaruko Oct 26, 2023
f864a50
fixbug
Hoshinonyaruko Oct 26, 2023
4564731
add wss
Hoshinonyaruko Oct 26, 2023
070e4df
merge
Hoshinonyaruko Oct 26, 2023
84e8fe9
bugfix
Hoshinonyaruko Oct 26, 2023
0e4fd50
fix action
Hoshinonyaruko Oct 26, 2023
fe2234a
fix action again
Hoshinonyaruko Oct 26, 2023
cf67a11
fix action againnn
Hoshinonyaruko Oct 26, 2023
0875837
fa
Hoshinonyaruko Oct 26, 2023
3a3c33f
fix
Hoshinonyaruko Oct 26, 2023
8789fa8
add a lot
Hoshinonyaruko Oct 27, 2023
7943466
add ws server token
Hoshinonyaruko Oct 28, 2023
4660983
merge
Hoshinonyaruko Oct 28, 2023
2a1026a
bugifx
Hoshinonyaruko Oct 28, 2023
4186970
fix
Hoshinonyaruko Oct 28, 2023
2f26828
fixat
Hoshinonyaruko Oct 28, 2023
007e1af
bugfix
Hoshinonyaruko Oct 28, 2023
c41fd77
bugfix
Hoshinonyaruko Oct 28, 2023
d8354b7
test
Hoshinonyaruko Oct 28, 2023
6e3c63c
test
Hoshinonyaruko Oct 28, 2023
f08d9d7
test2
Hoshinonyaruko Oct 28, 2023
4dd6e15
add url service
Hoshinonyaruko Oct 31, 2023
1f8c174
add url service
Hoshinonyaruko Oct 31, 2023
240f569
add url service
Hoshinonyaruko Oct 31, 2023
b191cb7
bugfix
Hoshinonyaruko Oct 31, 2023
42daab3
merge
Hoshinonyaruko Oct 31, 2023
8fec03f
fix
Hoshinonyaruko Oct 31, 2023
cca528b
fix
Hoshinonyaruko Oct 31, 2023
463a182
fix
Hoshinonyaruko Oct 31, 2023
e9187a1
bug fix
Hoshinonyaruko Nov 1, 2023
5ba2815
fix
Hoshinonyaruko Nov 1, 2023
c16e1af
fix
Hoshinonyaruko Nov 1, 2023
ec7863d
test
Hoshinonyaruko Nov 2, 2023
e8a7e73
ok
Hoshinonyaruko Nov 2, 2023
122d17d
add webui
Hoshinonyaruko Nov 2, 2023
4e9c209
merge
Hoshinonyaruko Nov 2, 2023
b502d61
add image_compress
Hoshinonyaruko Nov 3, 2023
3519e3e
merge
Hoshinonyaruko Nov 3, 2023
530ff96
bug fix
Hoshinonyaruko Nov 3, 2023
155a701
fix cq code
Hoshinonyaruko Nov 3, 2023
2f5ee4a
fixbug
Hoshinonyaruko Nov 3, 2023
afa03e3
bugfix
Hoshinonyaruko Nov 3, 2023
fdd1a73
merge
Hoshinonyaruko Nov 3, 2023
fe39cd2
bugfix
Hoshinonyaruko Nov 3, 2023
be08cbe
bugfix
Hoshinonyaruko Nov 3, 2023
931dfef
merge
Hoshinonyaruko Nov 3, 2023
73819c8
bugfix
Hoshinonyaruko Nov 3, 2023
b27f062
bugfix
Hoshinonyaruko Nov 3, 2023
1a94197
bugfix
Hoshinonyaruko Nov 3, 2023
745b28e
bugfix
Hoshinonyaruko Nov 3, 2023
1212c9a
bugfix
Hoshinonyaruko Nov 4, 2023
44d8669
bugfix
Hoshinonyaruko Nov 4, 2023
564aba5
add new feature
Hoshinonyaruko Nov 5, 2023
d7345c1
bugfix
Hoshinonyaruko Nov 5, 2023
472a224
bugfix
Hoshinonyaruko Nov 5, 2023
e22b58b
bugfix
Hoshinonyaruko Nov 5, 2023
22cb473
bugfix
Hoshinonyaruko Nov 5, 2023
e563929
bugfix
Hoshinonyaruko Nov 5, 2023
829b5d7
merge
Hoshinonyaruko Nov 5, 2023
b496ac1
bugfix
Hoshinonyaruko Nov 5, 2023
13e7700
bugfix
Hoshinonyaruko Nov 5, 2023
eb7e630
bugfix
Hoshinonyaruko Nov 5, 2023
32d490f
test
Hoshinonyaruko Nov 5, 2023
9815e3a
test
Hoshinonyaruko Nov 5, 2023
7747de6
test
Hoshinonyaruko Nov 5, 2023
fe2e4be
test
Hoshinonyaruko Nov 5, 2023
ec9e797
test
Hoshinonyaruko Nov 5, 2023
3548108
test
Hoshinonyaruko Nov 5, 2023
1e50a7c
test
Hoshinonyaruko Nov 5, 2023
812e6ea
test
Hoshinonyaruko Nov 5, 2023
76363a6
test
Hoshinonyaruko Nov 5, 2023
d8b05cd
test
Hoshinonyaruko Nov 5, 2023
c2e2b20
test
Hoshinonyaruko Nov 5, 2023
cefac16
test
Hoshinonyaruko Nov 5, 2023
273db15
test
Hoshinonyaruko Nov 5, 2023
5379f7d
test
Hoshinonyaruko Nov 5, 2023
56e2429
test
Hoshinonyaruko Nov 5, 2023
4466f30
test
Hoshinonyaruko Nov 6, 2023
a32a124
test
Hoshinonyaruko Nov 6, 2023
246d9c4
test
Hoshinonyaruko Nov 6, 2023
c91d9e2
test
Hoshinonyaruko Nov 6, 2023
6007979
bugfix
Hoshinonyaruko Nov 6, 2023
af64c33
bugfix
Hoshinonyaruko Nov 6, 2023
f5cfda3
Remove dist directory from tracking
Hoshinonyaruko Nov 6, 2023
53b6e5d
test
Hoshinonyaruko Nov 6, 2023
3991193
test
Hoshinonyaruko Nov 7, 2023
7af6759
bugfix2
Hoshinonyaruko Nov 7, 2023
fdec4ca
bugfix3
Hoshinonyaruko Nov 7, 2023
849c638
bugfix4
Hoshinonyaruko Nov 7, 2023
f268f3d
bugfix5
Hoshinonyaruko Nov 7, 2023
7ada595
bugfix5
Hoshinonyaruko Nov 8, 2023
76376a0
bugfix6
Hoshinonyaruko Nov 8, 2023
8332932
bugfix7
Hoshinonyaruko Nov 8, 2023
ac05d43
bugfix8
Hoshinonyaruko Nov 8, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
add image_compress
Hoshinonyaruko committed Nov 3, 2023
commit b502d615ce3825534cf50a0f9a7ab2ea638646dd
14 changes: 14 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
@@ -46,6 +46,7 @@ type Settings struct {
DeveloperLog bool `yaml:"developer_log"`
Username string `yaml:"server_user_name"`
Password string `yaml:"server_user_password"`
ImageLimit int `yaml:"image_sizelimit"`
}

// LoadConfig 从文件中加载配置并初始化单例配置
@@ -367,3 +368,16 @@ func GetServerUserPassword() string {
}
return instance.Settings.Password
}

// GetImageLimit 返回 ImageLimit 的值
func GetImageLimit() int {
mu.Lock()
defer mu.Unlock()

if instance == nil {
mylog.Println("Warning: instance is nil when trying to get image limit value.")
return 0 // 或者返回一个默认的 ImageLimit 值
}

return instance.Settings.ImageLimit
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -15,6 +15,7 @@ require (
github.com/google/uuid v1.4.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mvdan/xurls v1.1.0 // indirect
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
)

replace github.com/tencent-connect/botgo => ./botgo
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -84,6 +84,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/mvdan/xurls v1.1.0 h1:OpuDelGQ1R1ueQ6sSryzi6P+1RtBpfQHM8fJwlE45ww=
github.com/mvdan/xurls v1.1.0/go.mod h1:tQlNn3BED8bE/15hnSL2HLkDeLWpNPAwtw7wkEq44oU=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
98 changes: 98 additions & 0 deletions handlers/get_group_member_info.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package handlers

import (
"github.com/hoshinonyaruko/gensokyo/callapi"
"github.com/hoshinonyaruko/gensokyo/mylog"
"github.com/tencent-connect/botgo/openapi"
)

// 初始化handler,在程序启动时会被调用
func init() {
callapi.RegisterHandler("get_group_member_info", getGroupMemberInfo)
}

// 成员信息的结构定义
type MemberInfo struct {
UserID int64 `json:"user_id"`
GroupID int64 `json:"group_id"`
Nickname string `json:"nickname"`
Card string `json:"card"`
Sex string `json:"sex"`
Age int32 `json:"age"`
Area string `json:"area"`
JoinTime int32 `json:"join_time"`
LastSentTime int32 `json:"last_sent_time"`
Level string `json:"level"`
Role string `json:"role"`
Unfriendly bool `json:"unfriendly"`
Title string `json:"title"`
TitleExpireTime int64 `json:"title_expire_time"`
CardChangeable bool `json:"card_changeable"`
ShutUpTimestamp int64 `json:"shut_up_timestamp"`
}

// 构建单个成员的响应数据
func buildResponseForSingleMember(memberInfo *MemberInfo, echoValue interface{}) map[string]interface{} {
// 构建成员数据的映射
memberMap := map[string]interface{}{
"group_id": memberInfo.GroupID,
"user_id": memberInfo.UserID,
"nickname": memberInfo.Nickname,
"card": memberInfo.Card,
"sex": memberInfo.Sex,
"age": memberInfo.Age,
"area": memberInfo.Area,
"join_time": memberInfo.JoinTime,
"last_sent_time": memberInfo.LastSentTime,
"level": memberInfo.Level,
"role": memberInfo.Role,
"unfriendly": memberInfo.Unfriendly,
"title": memberInfo.Title,
"title_expire_time": memberInfo.TitleExpireTime,
"card_changeable": memberInfo.CardChangeable,
"shut_up_timestamp": memberInfo.ShutUpTimestamp,
}

// 构建完整的响应映射
response := map[string]interface{}{
"retcode": 0,
"status": "ok",
"data": memberMap,
"echo": echoValue,
}

return response
}

// getGroupMemberInfo是处理获取群成员信息的函数
func getGroupMemberInfo(client callapi.Client, api openapi.OpenAPI, apiv2 openapi.OpenAPI, message callapi.ActionMessage) {
// 使用虚拟数据构造 MemberInfo
memberInfo := &MemberInfo{
UserID: 123456789, // 虚拟的 QQ 号
GroupID: 987654321, // 虚拟的群号
Nickname: "主人", // 虚拟昵称
Card: "主人",
Sex: "unknown", // 性别未知
Age: 20, // 虚拟年龄
Area: "虚拟地区",
JoinTime: 1630416000, // 虚拟加群时间戳
LastSentTime: 1630502400, // 虚拟最后发言时间戳
Level: "1", // 虚拟成员等级
Role: "member", // 角色为普通成员
Unfriendly: false, // 没有不良记录
Title: "虚拟头衔",
TitleExpireTime: 1630598800, // 虚拟头衔过期时间
CardChangeable: true, // 允许修改群名片
ShutUpTimestamp: 0, // 不在禁言中
}

// 构建响应JSON
responseJSON := buildResponseForSingleMember(memberInfo, message.Echo)
mylog.Printf("get_group_member_info: %s\n", responseJSON)

// 发送响应回去
err := client.SendMessage(responseJSON)
if err != nil {
mylog.Printf("发送消息时出错: %v", err)
}
}
24 changes: 22 additions & 2 deletions handlers/send_group_msg.go
Original file line number Diff line number Diff line change
@@ -158,9 +158,19 @@ func generateGroupMessage(id string, foundItems map[string][]string, messageText
MsgType: 0, // 默认文本类型
}
}
// 首先压缩图片 默认不压缩
compressedData, err := images.CompressSingleImage(imageData)
if err != nil {
mylog.Printf("Error compressing image: %v", err)
return &dto.MessageToCreate{
Content: "错误: 压缩图片失败",
MsgID: id,
MsgType: 0, // 默认文本类型
}
}

// base64编码
base64Encoded := base64.StdEncoding.EncodeToString(imageData)
base64Encoded := base64.StdEncoding.EncodeToString(compressedData)

// 上传base64编码的图片并获取其URL
imageURL, err := images.UploadBase64ImageToServer(base64Encoded)
@@ -204,8 +214,18 @@ func generateGroupMessage(id string, foundItems map[string][]string, messageText
mylog.Printf("failed to decode base64 image: %v", err)
return nil
}
// 首先压缩图片 默认不压缩
compressedData, err := images.CompressSingleImage(fileImageData)
if err != nil {
mylog.Printf("Error compressing image: %v", err)
return &dto.MessageToCreate{
Content: "错误: 压缩图片失败",
MsgID: id,
MsgType: 0, // 默认文本类型
}
}
// 将解码的图片数据转换回base64格式并上传
imageURL, err := images.UploadBase64ImageToServer(base64.StdEncoding.EncodeToString(fileImageData))
imageURL, err := images.UploadBase64ImageToServer(base64.StdEncoding.EncodeToString(compressedData))
if err != nil {
mylog.Printf("failed to upload base64 image: %v", err)
return nil
14 changes: 12 additions & 2 deletions handlers/send_guild_channel_msg.go
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@ import (
"github.com/hoshinonyaruko/gensokyo/callapi"
"github.com/hoshinonyaruko/gensokyo/config"
"github.com/hoshinonyaruko/gensokyo/idmap"
"github.com/hoshinonyaruko/gensokyo/images"
"github.com/hoshinonyaruko/gensokyo/mylog"

"github.com/hoshinonyaruko/gensokyo/echo"
@@ -143,9 +144,18 @@ func generateReplyMessage(id string, foundItems map[string][]string, messageText
}
return &reply, false
}

// 首先压缩图片
compressedData, err := images.CompressSingleImage(imageData)
if err != nil {
mylog.Printf("Error compressing image: %v", err)
return &dto.MessageToCreate{
Content: "错误: 压缩图片失败",
MsgID: id,
MsgType: 0, // 默认文本类型
}, false
}
//base64编码
base64Encoded := base64.StdEncoding.EncodeToString(imageData)
base64Encoded := base64.StdEncoding.EncodeToString(compressedData)

// 当作base64图来处理
reply = dto.MessageToCreate{
6 changes: 4 additions & 2 deletions handlers/send_private_msg.go
Original file line number Diff line number Diff line change
@@ -73,7 +73,7 @@ func handleSendPrivateMsg(client callapi.Client, api openapi.OpenAPI, apiv2 open

// 优先发送文本信息
if messageText != "" {
groupReply := generatePrivateMessage(messageID, nil, messageText)
groupReply := generateGroupMessage(messageID, nil, messageText)

// 进行类型断言
groupMessage, ok := groupReply.(*dto.MessageToCreate)
@@ -96,7 +96,8 @@ func handleSendPrivateMsg(client callapi.Client, api openapi.OpenAPI, apiv2 open
var singleItem = make(map[string][]string)
singleItem[key] = urls

groupReply := generatePrivateMessage(messageID, singleItem, "")
//先试试用群里一样的处理逻辑,看看能跑不
groupReply := generateGroupMessage(messageID, singleItem, "")

// 进行类型断言
richMediaMessage, ok := groupReply.(*dto.RichMediaMessage)
@@ -119,6 +120,7 @@ func handleSendPrivateMsg(client callapi.Client, api openapi.OpenAPI, apiv2 open
}
}

// 这里是只有群私聊会用到
func generatePrivateMessage(id string, foundItems map[string][]string, messageText string) interface{} {
if imageURLs, ok := foundItems["local_image"]; ok && len(imageURLs) > 0 {
// 本地发图逻辑 todo 适配base64图片
207 changes: 207 additions & 0 deletions images/Compress.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
package images

import (
"bytes"
"fmt"
"image"
"image/color"
"image/draw"
"image/gif"
"image/jpeg"
"image/png"
"io"
"sync"
)

type Compressor struct {
QualityStep int // Quality adjustment step
MinQuality int // Minimum quality
MaxQuality int // Maximum quality
ThresholdKB int // Size threshold in KB
}

func NewCompressor(thresholdKB, qualityStep, minQuality, maxQuality int) *Compressor {
return &Compressor{
QualityStep: qualityStep,
MinQuality: minQuality,
MaxQuality: maxQuality,
ThresholdKB: thresholdKB,
}
}

// CompressImage handles image compression based on format.
func (c *Compressor) CompressImage(imageData io.Reader) ([]byte, error) {
if c.ThresholdKB == 0 {
return io.ReadAll(imageData)
}

// Create a buffer to copy the imageData and determine the image format.
buffer := bytes.NewBuffer(nil)
tee := io.TeeReader(imageData, buffer)

// Decode image using the buffer so we don't lose the initial bytes.
img, format, err := image.Decode(tee)
if err != nil {
return nil, fmt.Errorf("decoding image failed: %w", err)
}

// For GIFs, use the buffer which contains all bytes read from the original imageData.
if format == "gif" {
return c.handleGIF(buffer)
}

// For non-GIFs, check the initial size using a fresh buffer.
buf := &bytes.Buffer{}
switch format {
case "jpeg":
err = jpeg.Encode(buf, img, nil)
case "png":
err = png.Encode(buf, img)
default:
return nil, fmt.Errorf("unsupported image format: %s", format)
}

if err != nil {
return nil, fmt.Errorf("encoding image failed: %w", err)
}

if buf.Len() <= c.ThresholdKB*1024 {
// If the image is already below the threshold, return the original encoded bytes.
return buf.Bytes(), nil
}

// Apply format-specific compression.
switch format {
case "jpeg":
return c.compressJPEG(img)
case "png":
return c.compressPNG(img)
}

return nil, fmt.Errorf("unsupported image format: %s", format)
}

// handleGIF decodes and processes a GIF image.
func (c *Compressor) handleGIF(imageData io.Reader) ([]byte, error) {
gifImg, err := gif.DecodeAll(imageData)
if err != nil {
return nil, fmt.Errorf("decoding GIF image failed: %w", err)
}
return c.compressGIF(gifImg)
}

func (c *Compressor) compressJPEG(img image.Image) ([]byte, error) {
quality := c.MaxQuality
buf := &bytes.Buffer{}

for {
opts := jpeg.Options{Quality: quality}
buf.Reset()
err := jpeg.Encode(buf, img, &opts)
if err != nil {
return nil, fmt.Errorf("JPEG encoding failed at quality %d: %w", quality, err)
}

if buf.Len() <= c.ThresholdKB*1024 || quality <= c.MinQuality {
break
}

quality -= c.QualityStep
if quality < c.MinQuality {
quality = c.MinQuality
}
}

return buf.Bytes(), nil
}

func (c *Compressor) compressPNG(img image.Image) ([]byte, error) {
// Convert PNG to JPEG with a white background
b := img.Bounds()
whiteBg := image.NewRGBA(b)
draw.Draw(whiteBg, b, image.NewUniform(color.White), image.Point{}, draw.Src)
draw.Draw(whiteBg, b, img, b.Min, draw.Over)
return c.compressJPEG(whiteBg)
}

func (c *Compressor) compressGIF(originalGIF *gif.GIF) ([]byte, error) {
// Create a new GIF to hold the compressed frames
var compressedGIF gif.GIF
compressedGIF.LoopCount = originalGIF.LoopCount
compressedGIF.Disposal = originalGIF.Disposal
compressedGIF.Config = originalGIF.Config
compressedGIF.BackgroundIndex = originalGIF.BackgroundIndex

for i, srcFrame := range originalGIF.Image {
// Convert frame to RGBA to avoid paletted color issues
b := srcFrame.Bounds()
frame := image.NewRGBA(b)
draw.Draw(frame, b, srcFrame, b.Min, draw.Over)

// Create a white image same size of the frame
whiteImage := image.NewRGBA(b)
draw.Draw(whiteImage, b, &image.Uniform{color.White}, image.ZP, draw.Src)

// Draw the frame onto the white image to remove transparency
draw.Draw(whiteImage, b, frame, b.Min, draw.Over)

// Compress the frame
compressedFrame, err := c.compressJPEG(whiteImage)
if err != nil {
return nil, fmt.Errorf("compressing GIF frame failed: %w", err)
}

// Decode the compressed frame back to image
jpgFrame, _, err := image.Decode(bytes.NewReader(compressedFrame))
if err != nil {
return nil, fmt.Errorf("decoding JPEG frame failed: %w", err)
}

// Convert back to paletted image for GIF
palettedFrame := image.NewPaletted(b, srcFrame.Palette)
draw.FloydSteinberg.Draw(palettedFrame, b, jpgFrame, b.Min)

compressedGIF.Image = append(compressedGIF.Image, palettedFrame)
compressedGIF.Delay = append(compressedGIF.Delay, originalGIF.Delay[i])
}

var buf bytes.Buffer
if err := gif.EncodeAll(&buf, &compressedGIF); err != nil {
return nil, fmt.Errorf("encoding compressed GIF failed: %w", err)
}

return buf.Bytes(), nil
}

func ProcessImages(imageData []io.Reader, compressor *Compressor) ([][]byte, error) {
var wg sync.WaitGroup
mu := &sync.Mutex{}
compressedImages := make([][]byte, len(imageData))
errChan := make(chan error, len(imageData)) // 错误通道,缓冲以避免阻塞

wg.Add(len(imageData))
for i, data := range imageData {
go func(idx int, imgData io.Reader) {
defer wg.Done()
compressed, err := compressor.CompressImage(imgData)
mu.Lock()
compressedImages[idx] = compressed
mu.Unlock()
if err != nil {
errChan <- fmt.Errorf("compressing image at index %d failed: %w", idx, err)
}
}(i, data)
}

wg.Wait()
close(errChan) // 处理完所有goroutine后关闭错误通道

// 检查错误通道中是否有错误
for err := range errChan {
if err != nil {
return nil, err // 可以返回第一个错误或累积所有错误
}
}

return compressedImages, nil
}
39 changes: 39 additions & 0 deletions images/easycompress.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package images

import (
"bytes"

"github.com/hoshinonyaruko/gensokyo/config"
)

// 默认压缩参数
const (
defaultQualityStep = 10
defaultMinQuality = 25
defaultMaxQuality = 75
)

// CompressSingleImage 接收一个图片的 []byte 数据,并根据设定阈值返回压缩后的数据或原始数据。
func CompressSingleImage(imageBytes []byte) ([]byte, error) {
// 获取压缩阈值
thresholdKB := config.GetImageLimit()

// 如果阈值为0,则直接返回原始图片数据,不进行压缩
if thresholdKB == 0 {
return imageBytes, nil
}

// 创建压缩器实例
compressor := NewCompressor(thresholdKB, defaultQualityStep, defaultMinQuality, defaultMaxQuality)

// 创建一个读取器来读取 imageBytes 数据
reader := bytes.NewReader(imageBytes)

// 调用 CompressImage 方法来压缩图片
compressedImage, err := compressor.CompressImage(reader)
if err != nil {
return nil, err // 压缩出错时返回错误
}

return compressedImage, nil // 返回压缩后的图片数据
}
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
@@ -186,7 +186,7 @@ func main() {
// 确保所有wsClients都已初始化
if len(wsClients) != len(conf.Settings.WsAddress) {
log.Println("Error: Not all wsClients are initialized!")
log.Fatalln("Failed to initialize all WebSocketClients.")
//log.Fatalln("Failed to initialize all WebSocketClients.")
} else {
log.Println("All wsClients are successfully initialized.")
p = Processor.NewProcessor(api, apiV2, &conf.Settings, wsClients)
1 change: 1 addition & 0 deletions template/config_template.go
Original file line number Diff line number Diff line change
@@ -47,6 +47,7 @@ settings:
developer_log : false #开启开发者日志 默认关闭
server_user_name : "useradmin" #默认网页面板用户名
server_user_password : "admin" #默认网页面板密码
image_sizelimit : 0 #代表kb 腾讯api要求图片1500ms完成传输 如果图片发不出 请提升上行或设置此值 默认为0 不压缩
`
const Logo = `
'
3 changes: 2 additions & 1 deletion template/config_template.yml
Original file line number Diff line number Diff line change
@@ -38,4 +38,5 @@ settings:
key: "" #密钥路径 Apache(crt文件、key文件)示例: "C:\\123.key" \需要双写成\\
developer_log : true #开启开发者日志
server_user_name : "useradmin" #默认网页面板用户名
server_user_password : "admin" #默认网页面板密码
server_user_password : "admin" #默认网页面板密码
image_sizelimit : 0 #代表kb 腾讯api要求图片1500ms完成传输 如果图片发不出 请提升上行或设置此值 默认为0 不压缩
26 changes: 22 additions & 4 deletions wsclient/ws.go
Original file line number Diff line number Diff line change
@@ -134,18 +134,36 @@ func (c *WebSocketClient) sendHeartbeat(ctx context.Context, botID uint64) {
return
case <-time.After(10 * time.Second):
message := map[string]interface{}{
"meta_event_type": "heartbeat",
"post_type": "meta_event",
"self_id": botID,
"status": "ok",
"meta_event_type": "heartbeat",
"time": int(time.Now().Unix()),
"self_id": botID,
"status": map[string]interface{}{
"app_enabled": true,
"app_good": true,
"app_initialized": true,
"good": true,
"online": true,
"plugins_good": nil,
"stat": map[string]int{
"packet_received": 34933,
"packet_sent": 8513,
"packet_lost": 0,
"message_received": 24674,
"message_sent": 1663,
"disconnect_times": 0,
"lost_times": 0,
"last_message_time": int(time.Now().Unix()) - 10, // 假设最后一条消息是10秒前收到的
},
},
"interval": 10000, // 以毫秒为单位
}
c.SendMessage(message)
}
}
}

const maxRetryAttempts = 5
const maxRetryAttempts = 30

// NewWebSocketClient 创建 WebSocketClient 实例,接受 WebSocket URL、botID 和 openapi.OpenAPI 实例
func NewWebSocketClient(urlStr string, botID uint64, api openapi.OpenAPI, apiv2 openapi.OpenAPI) (*WebSocketClient, error) {