From e55faeb9241adeec2410910d482cc078b34fac98 Mon Sep 17 00:00:00 2001 From: _oah <57302072@qq.com> Date: Tue, 23 Jul 2024 23:28:02 +0800 Subject: [PATCH] add stream_upload_source --- officialaccount/material/material.go | 21 ++++++++----- officialaccount/material/media.go | 8 +++-- util/http.go | 45 ++++++++++++++++++++++++---- work/material/media.go | 17 ++++++++--- 4 files changed, 72 insertions(+), 19 deletions(-) diff --git a/officialaccount/material/material.go b/officialaccount/material/material.go index d8a43b94a..439cf8688 100644 --- a/officialaccount/material/material.go +++ b/officialaccount/material/material.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "os" + "path" "github.com/silenceper/wechat/v2/officialaccount/context" "github.com/silenceper/wechat/v2/util" @@ -163,7 +164,7 @@ type resAddMaterial struct { } // AddMaterialFromReader 上传永久性素材(处理视频需要单独上传),从 io.Reader 中读取 -func (material *Material) AddMaterialFromReader(mediaType MediaType, filename string, reader io.Reader) (mediaID string, url string, err error) { +func (material *Material) AddMaterialFromReader(mediaType MediaType, directory string, reader io.Reader) (mediaID string, url string, err error) { if mediaType == MediaTypeVideo { err = errors.New("永久视频素材上传使用 AddVideo 方法") return @@ -175,8 +176,10 @@ func (material *Material) AddMaterialFromReader(mediaType MediaType, filename st } uri := fmt.Sprintf("%s?access_token=%s&type=%s", addMaterialURL, accessToken, mediaType) + // 获取文件名 + filename := path.Base(directory) var response []byte - response, err = util.PostFileFromReader("media", filename, uri, reader) + response, err = util.PostFileFromReader("media", directory, filename, uri, reader) if err != nil { return } @@ -211,7 +214,7 @@ type reqVideo struct { } // AddVideoFromReader 永久视频素材文件上传,从 io.Reader 中读取 -func (material *Material) AddVideoFromReader(filename, title, introduction string, reader io.Reader) (mediaID string, url string, err error) { +func (material *Material) AddVideoFromReader(directory, title, introduction string, reader io.Reader) (mediaID string, url string, err error) { var accessToken string accessToken, err = material.GetAccessToken() if err != nil { @@ -229,17 +232,19 @@ func (material *Material) AddVideoFromReader(filename, title, introduction strin if err != nil { return } - + fileName := path.Base(directory) fields := []util.MultipartFormField{ { IsFile: true, Fieldname: "media", - Filename: filename, + Directory: directory, + Filename: fileName, FileReader: reader, }, { IsFile: false, Fieldname: "description", + Filename: fileName, Value: fieldValue, }, } @@ -265,14 +270,14 @@ func (material *Material) AddVideoFromReader(filename, title, introduction strin } // AddVideo 永久视频素材文件上传 -func (material *Material) AddVideo(filename, title, introduction string) (mediaID string, url string, err error) { - f, err := os.Open(filename) +func (material *Material) AddVideo(directory, title, introduction string) (mediaID string, url string, err error) { + f, err := os.Open(directory) if err != nil { return "", "", err } defer func() { _ = f.Close() }() - return material.AddVideoFromReader(filename, title, introduction, f) + return material.AddVideoFromReader(directory, title, introduction, f) } type reqDeleteMaterial struct { diff --git a/officialaccount/material/media.go b/officialaccount/material/media.go index 316758fb4..9dd504c98 100644 --- a/officialaccount/material/media.go +++ b/officialaccount/material/media.go @@ -38,7 +38,7 @@ type Media struct { } // MediaUpload 临时素材上传 -func (material *Material) MediaUpload(mediaType MediaType, filename string) (media Media, err error) { +func (material *Material) MediaUpload(mediaType MediaType, url string) (media Media, err error) { var accessToken string accessToken, err = material.GetAccessToken() if err != nil { @@ -46,8 +46,12 @@ func (material *Material) MediaUpload(mediaType MediaType, filename string) (med } uri := fmt.Sprintf("%s?access_token=%s&type=%s", mediaUploadURL, accessToken, mediaType) + filename, byteData, err := util.GetFileSourceByURL(url) + if err != nil { + return + } var response []byte - response, err = util.PostFile("media", filename, uri) + response, err = util.PostFileByStream("media", filename, uri, byteData) if err != nil { return } diff --git a/util/http.go b/util/http.go index b9b4b004b..692b9784b 100644 --- a/util/http.go +++ b/util/http.go @@ -13,6 +13,7 @@ import ( "mime/multipart" "net/http" "os" + "path" "golang.org/x/crypto/pkcs12" ) @@ -146,24 +147,57 @@ func PostJSONWithRespContentType(uri string, obj interface{}) ([]byte, string, e return responseData, contentType, err } +// PostFileByStream 上传文件 +func PostFileByStream(fieldName, fileName, uri string, byteData []byte) ([]byte, error) { + fields := []MultipartFormField{ + { + IsFile: false, + Fieldname: fieldName, + Filename: fileName, + Value: byteData, + }, + } + return PostMultipartForm(fields, uri) +} + +// GetFileSourceByURL 从给定的 URL 获取文件名和文件字节数据 +func GetFileSourceByURL(url string) (filename string, byteData []byte, err error) { + // 获取文件名 + filename = path.Base(url) + // 获取资源 + resp, err := http.Get(url) + if err != nil { + err = fmt.Errorf("get resp error: %v", err) + return + } + byteData, err = io.ReadAll(resp.Body) + defer func() { _ = resp.Body.Close() }() + if err != nil { + err = fmt.Errorf("read resp error: %v", err) + return + } + return +} + // PostFile 上传文件 -func PostFile(fieldName, filename, uri string) ([]byte, error) { +func PostFile(fieldName, directory, uri string) ([]byte, error) { fields := []MultipartFormField{ { IsFile: true, Fieldname: fieldName, - Filename: filename, + Directory: directory, }, } return PostMultipartForm(fields, uri) } // PostFileFromReader 上传文件,从 io.Reader 中读取 -func PostFileFromReader(filedName, fileName, uri string, reader io.Reader) ([]byte, error) { +func PostFileFromReader(filedName, directory, fileName, uri string, reader io.Reader) ([]byte, error) { fields := []MultipartFormField{ { IsFile: true, Fieldname: filedName, + Directory: directory, Filename: fileName, FileReader: reader, }, @@ -176,6 +210,7 @@ type MultipartFormField struct { IsFile bool Fieldname string Value []byte + Directory string Filename string FileReader io.Reader } @@ -197,7 +232,7 @@ func PostMultipartForm(fields []MultipartFormField, uri string) (respBody []byte } if field.FileReader == nil { - fh, e := os.Open(field.Filename) + fh, e := os.Open(field.Directory) if e != nil { err = fmt.Errorf("error opening file , err=%v", e) return @@ -213,7 +248,7 @@ func PostMultipartForm(fields []MultipartFormField, uri string) (respBody []byte } } } else { - partWriter, e := bodyWriter.CreateFormField(field.Fieldname) + partWriter, e := bodyWriter.CreateFormFile(field.Fieldname, field.Filename) if e != nil { err = e return diff --git a/work/material/media.go b/work/material/media.go index b32785a5c..5ba3f6ebd 100644 --- a/work/material/media.go +++ b/work/material/media.go @@ -59,7 +59,8 @@ func (r *Client) UploadImg(filename string) (*UploadImgResponse, error) { // UploadTempFile 上传临时素材 // @see https://developer.work.weixin.qq.com/document/path/90253 // @mediaType 媒体文件类型,分别有图片(image)、语音(voice)、视频(video),普通文件(file) -func (r *Client) UploadTempFile(filename string, mediaType string) (*UploadTempFileResponse, error) { +// 临时素材一般都是存储在oss上的,可以直接传递url +func (r *Client) UploadTempFile(url string, mediaType string) (*UploadTempFileResponse, error) { var ( accessToken string err error @@ -67,8 +68,12 @@ func (r *Client) UploadTempFile(filename string, mediaType string) (*UploadTempF if accessToken, err = r.GetAccessToken(); err != nil { return nil, err } + filename, byteData, err := util.GetFileSourceByURL(url) + if err != nil { + return nil, err + } var response []byte - if response, err = util.PostFile("media", filename, fmt.Sprintf(uploadTempFile, accessToken, mediaType)); err != nil { + if response, err = util.PostFileByStream("media", filename, fmt.Sprintf(uploadTempFile, accessToken, mediaType), byteData); err != nil { return nil, err } result := &UploadTempFileResponse{} @@ -80,7 +85,7 @@ func (r *Client) UploadTempFile(filename string, mediaType string) (*UploadTempF // @see https://developer.work.weixin.qq.com/document/path/95098 // @mediaType 媒体文件类型,分别有图片(image)、视频(video)、普通文件(file) // @attachment_type 附件类型,不同的附件类型用于不同的场景。1:朋友圈;2:商品图册 -func (r *Client) UploadAttachment(filename string, mediaType string, attachmentType int) (*UploadAttachmentResponse, error) { +func (r *Client) UploadAttachment(url string, mediaType string, attachmentType int) (*UploadAttachmentResponse, error) { var ( accessToken string err error @@ -88,8 +93,12 @@ func (r *Client) UploadAttachment(filename string, mediaType string, attachmentT if accessToken, err = r.GetAccessToken(); err != nil { return nil, err } + filename, byteData, err := util.GetFileSourceByURL(url) + if err != nil { + return nil, err + } var response []byte - if response, err = util.PostFile("media", filename, fmt.Sprintf(uploadAttachment, accessToken, mediaType, attachmentType)); err != nil { + if response, err = util.PostFileByStream("media", filename, fmt.Sprintf(uploadAttachment, accessToken, mediaType, attachmentType), byteData); err != nil { return nil, err } result := &UploadAttachmentResponse{}