Przeglądaj źródła

add stream_upload_source (#786)

Co-authored-by: _oah <57302072@qq.com>
oah8 1 rok temu
rodzic
commit
c1770130a0

+ 13 - 8
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, filePath 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(filePath)
 	var response []byte
-	response, err = util.PostFileFromReader("media", filename, uri, reader)
+	response, err = util.PostFileFromReader("media", filePath, 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(filePath, 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(filePath)
 	fields := []util.MultipartFormField{
 		{
 			IsFile:     true,
 			Fieldname:  "media",
-			Filename:   filename,
+			FilePath:   filePath,
+			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 {

+ 33 - 0
officialaccount/material/media.go

@@ -3,6 +3,7 @@ package material
 import (
 	"encoding/json"
 	"fmt"
+	"io"
 
 	"github.com/silenceper/wechat/v2/util"
 )
@@ -62,6 +63,38 @@ func (material *Material) MediaUpload(mediaType MediaType, filename string) (med
 	return
 }
 
+// MediaUploadFromReader 临时素材上传
+func (material *Material) MediaUploadFromReader(mediaType MediaType, filename string, reader io.Reader) (media Media, err error) {
+	var accessToken string
+	accessToken, err = material.GetAccessToken()
+	if err != nil {
+		return
+	}
+
+	uri := fmt.Sprintf("%s?access_token=%s&type=%s", mediaUploadURL, accessToken, mediaType)
+
+	var byteData []byte
+	byteData, err = io.ReadAll(reader)
+	if err != nil {
+		return
+	}
+
+	var response []byte
+	response, err = util.PostFileByStream("media", filename, uri, byteData)
+	if err != nil {
+		return
+	}
+	err = json.Unmarshal(response, &media)
+	if err != nil {
+		return
+	}
+	if media.ErrCode != 0 {
+		err = fmt.Errorf("MediaUpload error : errcode=%v , errmsg=%v", media.ErrCode, media.ErrMsg)
+		return
+	}
+	return
+}
+
 // GetMediaURL 返回临时素材的下载地址供用户自己处理
 // NOTICE: URL 不可公开,因为含access_token 需要立即另存文件
 func (material *Material) GetMediaURL(mediaID string) (mediaURL string, err error) {

+ 20 - 5
util/http.go

@@ -146,24 +146,38 @@ 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)
+}
+
 // PostFile 上传文件
-func PostFile(fieldName, filename, uri string) ([]byte, error) {
+func PostFile(fieldName, filePath, uri string) ([]byte, error) {
 	fields := []MultipartFormField{
 		{
 			IsFile:    true,
 			Fieldname: fieldName,
-			Filename:  filename,
+			FilePath:  filePath,
 		},
 	}
 	return PostMultipartForm(fields, uri)
 }
 
 // PostFileFromReader 上传文件,从 io.Reader 中读取
-func PostFileFromReader(filedName, fileName, uri string, reader io.Reader) ([]byte, error) {
+func PostFileFromReader(filedName, filePath, fileName, uri string, reader io.Reader) ([]byte, error) {
 	fields := []MultipartFormField{
 		{
 			IsFile:     true,
 			Fieldname:  filedName,
+			FilePath:   filePath,
 			Filename:   fileName,
 			FileReader: reader,
 		},
@@ -176,6 +190,7 @@ type MultipartFormField struct {
 	IsFile     bool
 	Fieldname  string
 	Value      []byte
+	FilePath   string
 	Filename   string
 	FileReader io.Reader
 }
@@ -197,7 +212,7 @@ func PostMultipartForm(fields []MultipartFormField, uri string) (respBody []byte
 			}
 
 			if field.FileReader == nil {
-				fh, e := os.Open(field.Filename)
+				fh, e := os.Open(field.FilePath)
 				if e != nil {
 					err = fmt.Errorf("error opening file , err=%v", e)
 					return
@@ -213,7 +228,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

+ 52 - 0
work/material/media.go

@@ -2,6 +2,7 @@ package material
 
 import (
 	"fmt"
+	"io"
 
 	"github.com/silenceper/wechat/v2/util"
 )
@@ -96,3 +97,54 @@ func (r *Client) UploadAttachment(filename string, mediaType string, attachmentT
 	err = util.DecodeWithError(response, result, "UploadAttachment")
 	return result, err
 }
+
+// UploadTempFileFromReader 上传临时素材
+// @see https://developer.work.weixin.qq.com/document/path/90253
+// @mediaType 媒体文件类型,分别有图片(image)、语音(voice)、视频(video),普通文件(file)
+func (r *Client) UploadTempFileFromReader(filename, mediaType string, reader io.Reader) (*UploadTempFileResponse, error) {
+	var (
+		accessToken string
+		err         error
+	)
+	if accessToken, err = r.GetAccessToken(); err != nil {
+		return nil, err
+	}
+	var byteData []byte
+	byteData, err = io.ReadAll(reader)
+	if err != nil {
+		return nil, err
+	}
+	var response []byte
+	if response, err = util.PostFileByStream("media", filename, fmt.Sprintf(uploadTempFile, accessToken, mediaType), byteData); err != nil {
+		return nil, err
+	}
+	result := &UploadTempFileResponse{}
+	err = util.DecodeWithError(response, result, "UploadTempFile")
+	return result, err
+}
+
+// UploadAttachmentFromReader 上传附件资源
+// @see https://developer.work.weixin.qq.com/document/path/95098
+// @mediaType 媒体文件类型,分别有图片(image)、视频(video)、普通文件(file)
+// @attachment_type 附件类型,不同的附件类型用于不同的场景。1:朋友圈;2:商品图册
+func (r *Client) UploadAttachmentFromReader(filename, mediaType string, reader io.Reader, attachmentType int) (*UploadAttachmentResponse, error) {
+	var (
+		accessToken string
+		err         error
+	)
+	if accessToken, err = r.GetAccessToken(); err != nil {
+		return nil, err
+	}
+	var byteData []byte
+	byteData, err = io.ReadAll(reader)
+	if err != nil {
+		return nil, err
+	}
+	var response []byte
+	if response, err = util.PostFileByStream("media", filename, fmt.Sprintf(uploadAttachment, accessToken, mediaType, attachmentType), byteData); err != nil {
+		return nil, err
+	}
+	result := &UploadAttachmentResponse{}
+	err = util.DecodeWithError(response, result, "UploadAttachment")
+	return result, err
+}