-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
210 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
package oidb | ||
|
||
import ( | ||
"encoding/hex" | ||
"errors" | ||
"fmt" | ||
"github.com/LagrangeDev/LagrangeGo/packets/pb/service/oidb" | ||
"github.com/LagrangeDev/LagrangeGo/utils" | ||
"io" | ||
"math/rand/v2" | ||
) | ||
|
||
func BuildGroupImageUploadReq(groupUin uint32, stream io.Reader) (*OidbPacket, error) { | ||
// OidbSvcTrpcTcp.0x11c4_100 | ||
data, err := io.ReadAll(stream) | ||
if err != nil { | ||
return nil, err | ||
} | ||
md5Hash := utils.Md5Digest(data) | ||
sha1Hash := utils.Sha1Digest(data) | ||
format, size, err := utils.ImageResolve(data) | ||
if err != nil { | ||
return nil, err | ||
} | ||
imageExt := utils.GetImageExt(format) | ||
|
||
hexString := "0800180020004a00500062009201009a0100aa010c080012001800200028003a00" | ||
bytesPbReserveTroop, err := hex.DecodeString(hexString) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
body := &oidb.NTV2RichMediaReq{ | ||
ReqHead: &oidb.MultiMediaReqHead{ | ||
Common: &oidb.CommonHead{ | ||
RequestId: 1, | ||
Command: 100, | ||
}, | ||
Scene: &oidb.SceneInfo{ | ||
RequestType: 2, | ||
BusinessType: 1, | ||
SceneType: 2, | ||
Group: &oidb.NTGroupInfo{ | ||
GroupUin: groupUin, | ||
}, | ||
}, | ||
Client: &oidb.ClientMeta{ | ||
AgentType: 2, | ||
}, | ||
}, | ||
Upload: &oidb.UploadReq{ | ||
UploadInfo: []*oidb.UploadInfo{ | ||
{ | ||
FileInfo: &oidb.FileInfo{ | ||
FileSize: uint32(len(data)), | ||
FileHash: fmt.Sprintf("%x", md5Hash), | ||
FileSha1: fmt.Sprintf("%x", sha1Hash), | ||
FileName: fmt.Sprintf("%x.%s", md5Hash, imageExt), | ||
Type: &oidb.FileType{ | ||
Type: 1, | ||
PicFormat: uint32(format), | ||
VideoFormat: 0, | ||
VoiceFormat: 0, | ||
}, | ||
Width: size.X, | ||
Height: size.Y, | ||
Time: 0, | ||
Original: 1, | ||
}, | ||
SubFileType: 0, | ||
}, | ||
}, | ||
TryFastUploadCompleted: true, | ||
SrvSendMsg: false, | ||
ClientRandomId: rand.Uint64(), | ||
CompatQMsgSceneType: 2, | ||
ExtBizInfo: &oidb.ExtBizInfo{ | ||
Pic: &oidb.PicExtBizInfo{ | ||
BytesPbReserveTroop: bytesPbReserveTroop, | ||
}, | ||
Video: &oidb.VideoExtBizInfo{ | ||
BytesPbReserve: []byte{}, | ||
}, | ||
Ptt: &oidb.PttExtBizInfo{ | ||
BytesReserve: []byte{}, | ||
BytesPbReserve: []byte{}, | ||
BytesGeneralFlags: []byte{}, | ||
}, | ||
}, | ||
ClientSeq: 0, | ||
NoNeedCompatMsg: false, | ||
}, | ||
} | ||
return BuildOidbPacket(0x11c4, 100, body, false, true) | ||
} | ||
|
||
func ParseGroupImageUploadResp(data []byte) (*oidb.NTV2RichMediaResp, error) { // TODO: return proper response | ||
var resp oidb.NTV2RichMediaResp | ||
baseResp, err := ParseOidbPacket(data, &resp) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if baseResp.ErrorCode != 0 { | ||
return nil, errors.New(baseResp.ErrorMsg) | ||
} | ||
|
||
return &resp, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package utils | ||
|
||
import ( | ||
"bytes" | ||
"encoding/binary" | ||
"errors" | ||
) | ||
|
||
// Vector2 二维向量 | ||
type Vector2 struct { | ||
X uint32 | ||
Y uint32 | ||
} | ||
|
||
type ImageFormat uint32 | ||
|
||
const ( | ||
Unknown ImageFormat = iota | ||
Jpeg ImageFormat = 1000 | ||
Png ImageFormat = 1001 | ||
Gif ImageFormat = 2000 | ||
Webp ImageFormat = 1002 | ||
Bmp ImageFormat = 1005 | ||
Tiff ImageFormat = 1006 | ||
) | ||
|
||
func GetImageExt(format ImageFormat) string { | ||
switch format { | ||
case Jpeg: | ||
return "jpg" | ||
case Png: | ||
return "png" | ||
case Gif: | ||
return "gif" | ||
case Webp: | ||
return "webp" | ||
case Bmp: | ||
return "bmp" | ||
case Tiff: | ||
return "tiff" | ||
default: | ||
return "unknown" | ||
} | ||
} | ||
|
||
func ImageResolve(image []byte) (ImageFormat, Vector2, error) { | ||
if len(image) < 10 { // 最小长度检查 | ||
return Unknown, Vector2{}, errors.New("image data is too short") | ||
} | ||
|
||
size := Vector2{} | ||
format := Unknown | ||
|
||
switch { | ||
case bytes.Equal(image[:6], []byte{0x47, 0x49, 0x46, 0x38, 0x39, 0x61}) || bytes.Equal(image[:6], []byte{0x47, 0x49, 0x46, 0x38, 0x37, 0x61}): // GIF | ||
size = Vector2{X: uint32(binary.LittleEndian.Uint16(image[6:8])), Y: uint32(binary.LittleEndian.Uint16(image[8:10]))} | ||
format = Gif | ||
|
||
case bytes.Equal(image[:2], []byte{0xFF, 0xD8}): // JPEG | ||
for i := 2; i < len(image)-10; i++ { | ||
if binary.LittleEndian.Uint16(image[i:i+2])&0xFCFF == 0xC0FF { // SOF0 ~ SOF3 | ||
size = Vector2{X: uint32(binary.BigEndian.Uint16(image[i+7 : i+9])), Y: uint32(binary.BigEndian.Uint16(image[i+5 : i+7]))} | ||
break | ||
} | ||
} | ||
format = Jpeg | ||
|
||
case bytes.Equal(image[:8], []byte{0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A}): // PNG | ||
size = Vector2{X: binary.BigEndian.Uint32(image[16:20]), Y: binary.BigEndian.Uint32(image[20:24])} | ||
format = Png | ||
|
||
case bytes.Equal(image[:4], []byte{0x52, 0x49, 0x46, 0x46}) && bytes.Equal(image[8:12], []byte{0x57, 0x45, 0x42, 0x50}): // WEBP | ||
if bytes.Equal(image[12:16], []byte{0x56, 0x50, 0x38, 0x58}) { // VP8X | ||
size = Vector2{X: uint32(binary.LittleEndian.Uint16(image[24:27]) + 1), Y: uint32(binary.LittleEndian.Uint16(image[27:30]) + 1)} | ||
} else if bytes.Equal(image[12:16], []byte{0x56, 0x50, 0x38, 0x4C}) { // VP8L | ||
size = Vector2{X: uint32(int32(binary.LittleEndian.Uint32(image[21:25]))&0x3FFF) + 1, Y: uint32(int32(binary.LittleEndian.Uint32(image[20:22])&0xFFFC000)>>0x0E) + 1} | ||
} else { | ||
size = Vector2{X: uint32(binary.LittleEndian.Uint16(image[26:28])), Y: uint32(binary.LittleEndian.Uint16(image[28:30]))} | ||
} | ||
format = Webp | ||
|
||
case bytes.Equal(image[:2], []byte{0x42, 0x4D}): // BMP | ||
size = Vector2{X: binary.LittleEndian.Uint32(image[18:22]), Y: binary.LittleEndian.Uint32(image[22:26])} | ||
format = Bmp | ||
|
||
case bytes.Equal(image[:2], []byte{0x49, 0x49}) || bytes.Equal(image[:2], []byte{0x4D, 0x4D}): // TIFF | ||
size = Vector2{X: uint32(binary.LittleEndian.Uint16(image[18:20])), Y: uint32(binary.LittleEndian.Uint16(image[30:32]))} | ||
format = Tiff | ||
|
||
default: | ||
return Unknown, Vector2{}, nil | ||
} | ||
|
||
return format, size, nil | ||
} |