作者 yangfu

增加 aliyun 视频点播接入

1 package v1 1 package v1
2 2
3 import ( 3 import (
  4 + "encoding/json"
4 "fmt" 5 "fmt"
5 "github.com/astaxie/beego" 6 "github.com/astaxie/beego"
  7 + "gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/log"
6 "opp/controllers" 8 "opp/controllers"
  9 + "opp/internal/aliyun"
7 "opp/internal/utils" 10 "opp/internal/utils"
8 "opp/protocol" 11 "opp/protocol"
  12 + "opp/services/file"
9 "path/filepath" 13 "path/filepath"
10 "strings" 14 "strings"
11 ) 15 )
@@ -37,3 +41,24 @@ func (this *FileController) DownLoad() { @@ -37,3 +41,24 @@ func (this *FileController) DownLoad() {
37 } 41 }
38 msg = protocol.NewReturnResponse(rsp, err) 42 msg = protocol.NewReturnResponse(rsp, err)
39 } 43 }
  44 +
  45 +//GetPlayInfo 获取播放信息
  46 +// @router /getPlayInfo [post]
  47 +func (this *FileController) GetPlayInfo() {
  48 + var msg *protocol.ResponseMessage
  49 + defer func() {
  50 + this.Resp(msg)
  51 + }()
  52 + var request *aliyun.GetPlayInfoRequest
  53 + if err := json.Unmarshal(this.ByteBody, &request); err != nil {
  54 + log.Error(err)
  55 + msg = protocol.BadRequestParam(1)
  56 + return
  57 + }
  58 + if b, m := this.Valid(request); !b {
  59 + msg = m
  60 + return
  61 + }
  62 + header := controllers.GetRequestHeader(this.Ctx)
  63 + msg = protocol.NewReturnResponse(file.GetPlayInfo(header, request))
  64 +}
@@ -2,8 +2,10 @@ package v1 @@ -2,8 +2,10 @@ package v1
2 2
3 import ( 3 import (
4 "bytes" 4 "bytes"
  5 + "encoding/json"
5 "fmt" 6 "fmt"
6 "opp/controllers" 7 "opp/controllers"
  8 + "opp/internal/aliyun"
7 "opp/protocol" 9 "opp/protocol"
8 "opp/services/upload" 10 "opp/services/upload"
9 11
@@ -94,3 +96,24 @@ func (this *UploadController) Video() { @@ -94,3 +96,24 @@ func (this *UploadController) Video() {
94 } 96 }
95 msg = protocol.NewReturnResponse(rsp, err) 97 msg = protocol.NewReturnResponse(rsp, err)
96 } 98 }
  99 +
  100 +//创建视频上传凭证 CreateUploadVideo
  101 +// @router /createUploadVideo [post]
  102 +func (this *UploadController) CreateUploadVideo() {
  103 + var msg *protocol.ResponseMessage
  104 + defer func() {
  105 + this.Resp(msg)
  106 + }()
  107 + var request *aliyun.CreateUploadVideoRequest
  108 + if err := json.Unmarshal(this.ByteBody, &request); err != nil {
  109 + log.Error(err)
  110 + msg = protocol.BadRequestParam(1)
  111 + return
  112 + }
  113 + if b, m := this.Valid(request); !b {
  114 + msg = m
  115 + return
  116 + }
  117 + header := controllers.GetRequestHeader(this.Ctx)
  118 + msg = protocol.NewReturnResponse(upload.CreateUploadVideo(header, request))
  119 +}
@@ -3,6 +3,7 @@ module opp @@ -3,6 +3,7 @@ module opp
3 go 1.12 3 go 1.12
4 4
5 require ( 5 require (
  6 + github.com/aliyun/alibaba-cloud-sdk-go v1.60.348
6 github.com/astaxie/beego v1.10.0 7 github.com/astaxie/beego v1.10.0
7 github.com/disintegration/imaging v1.6.2 8 github.com/disintegration/imaging v1.6.2
8 github.com/go-sql-driver/mysql v1.4.1 9 github.com/go-sql-driver/mysql v1.4.1
  1 +package aliyun
  2 +
  3 +const (
  4 + RegionID = "cn-shanghai"
  5 + AccessKeyID = "LTAI4FhiZ3UktC6N1u3H5GFC"
  6 + AccessKeySecret = "UyspWwdni55CYQ02hUCint4qY2jNYO"
  7 +)
  8 +
  9 +const (
  10 + FileImage = "image"
  11 + FileVoice = "voice"
  12 + FileVideo = "video"
  13 +)
  1 +package aliyun
  2 +
  3 +//创建视频上传凭证
  4 +/*CreateUploadVideo */
  5 +type CreateUploadVideoRequest struct {
  6 +}
  7 +
  8 +type CreateUploadVideoResponse struct {
  9 + RequestId string `json:"requestId"`
  10 + VideoId string `json:"videoId"`
  11 + UploadAddress string `json:"uploadAddress"`
  12 + UploadAuth string `json:"uploadAuth"`
  13 +}
  14 +
  15 +/*GetPlayInfo 获取播放信息*/
  16 +type GetPlayInfoRequest struct {
  17 + VideoId string `json:"videoId" xml:"VideoId"`
  18 +}
  19 +
  20 +// GetPlayInfoResponse is the response struct for api GetPlayInfo
  21 +type GetPlayInfoResponse struct {
  22 + //*responses.BaseResponse
  23 + //RequestId string `json:"RequestId" xml:"RequestId"`
  24 + VideoBase VideoBase `json:"VideoBase" xml:"VideoBase"`
  25 + PlayInfoList PlayInfoListInGetPlayInfo `json:"PlayInfoList" xml:"PlayInfoList"`
  26 +}
  27 +
  28 +// VideoBase is a nested struct in vod response
  29 +type VideoBase struct {
  30 + OutputType string `json:"OutputType" xml:"OutputType"`
  31 + CoverURL string `json:"CoverURL" xml:"CoverURL"`
  32 + Duration string `json:"Duration" xml:"Duration"`
  33 + Status string `json:"Status" xml:"Status"`
  34 + Title string `json:"Title" xml:"Title"`
  35 + VideoId string `json:"VideoId" xml:"VideoId"`
  36 + MediaType string `json:"MediaType" xml:"MediaType"`
  37 + CreationTime string `json:"CreationTime" xml:"CreationTime"`
  38 + TranscodeMode string `json:"TranscodeMode" xml:"TranscodeMode"`
  39 + //ThumbnailList ThumbnailListInGetPlayInfo `json:"ThumbnailList" xml:"ThumbnailList"`
  40 +}
  41 +
  42 +type PlayInfoListInGetPlayInfo struct {
  43 + PlayInfo []PlayInfo `json:"PlayInfo" xml:"PlayInfo"`
  44 +}
  45 +
  46 +// PlayInfo is a nested struct in vod response
  47 +type PlayInfo struct {
  48 + JobId string `json:"JobId" xml:"JobId"`
  49 + Format string `json:"Format" xml:"Format"`
  50 + PreprocessStatus string `json:"PreprocessStatus" xml:"PreprocessStatus"`
  51 + EncryptType string `json:"EncryptType" xml:"EncryptType"`
  52 + Fps string `json:"Fps" xml:"Fps"`
  53 + ModificationTime string `json:"ModificationTime" xml:"ModificationTime"`
  54 + NarrowBandType string `json:"NarrowBandType" xml:"NarrowBandType"`
  55 + Bitrate string `json:"Bitrate" xml:"Bitrate"`
  56 + Encrypt int64 `json:"Encrypt" xml:"Encrypt"`
  57 + Rand string `json:"Rand" xml:"Rand"`
  58 + CreationTime string `json:"CreationTime" xml:"CreationTime"`
  59 + StreamType string `json:"StreamType" xml:"StreamType"`
  60 + Height int64 `json:"Height" xml:"Height"`
  61 + WatermarkId string `json:"WatermarkId" xml:"WatermarkId"`
  62 + Duration string `json:"Duration" xml:"Duration"`
  63 + Complexity string `json:"Complexity" xml:"Complexity"`
  64 + Width int64 `json:"Width" xml:"Width"`
  65 + Size int64 `json:"Size" xml:"Size"`
  66 + Status string `json:"Status" xml:"Status"`
  67 + Definition string `json:"Definition" xml:"Definition"`
  68 + Plaintext string `json:"Plaintext" xml:"Plaintext"`
  69 + PlayURL string `json:"PlayURL" xml:"PlayURL"`
  70 + Specification string `json:"Specification" xml:"Specification"`
  71 +}
  1 +package aliyun
  2 +
  3 +import (
  4 + "fmt"
  5 + "github.com/aliyun/alibaba-cloud-sdk-go/sdk"
  6 + "github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
  7 + "github.com/aliyun/alibaba-cloud-sdk-go/services/vod"
  8 + "github.com/astaxie/beego"
  9 + "gitlab.fjmaimaimai.com/mmm-go/gocomm/common"
  10 + comm_time "gitlab.fjmaimaimai.com/mmm-go/gocomm/time"
  11 + "path"
  12 + "time"
  13 +)
  14 +
  15 +//客户端
  16 +func DefaultVodClient() (client *vod.Client, err error) {
  17 + return InitVodClient(AccessKeyID, AccessKeySecret)
  18 +}
  19 +
  20 +//初始化客户端
  21 +func InitVodClient(accessKeyId string, accessKeySecret string) (client *vod.Client, err error) {
  22 + // 点播服务接入区域
  23 + regionId := RegionID
  24 + // 创建授权对象
  25 + credential := &credentials.AccessKeyCredential{
  26 + accessKeyId,
  27 + accessKeySecret,
  28 + }
  29 + // 自定义config
  30 + config := sdk.NewConfig()
  31 + config.AutoRetry = true // 失败是否自动重试
  32 + config.MaxRetryTime = 3 // 最大重试次数
  33 + config.Timeout = 3000000000 // 连接超时,单位:纳秒;默认为3秒
  34 + // 创建vodClient实例
  35 + return vod.NewClientWithOptions(regionId, config, credential)
  36 +}
  37 +
  38 +//获取视频上传地址和凭证,并创建视频信息
  39 +func CreateUploadVideo(client *vod.Client) (response *CreateUploadVideoResponse, err error) {
  40 + request := vod.CreateCreateUploadVideoRequest()
  41 + request.Title = getFileName(FileVideo, "video_file.mp4")
  42 + request.FileName = getFileName(FileVideo, "video_file.mp4")
  43 + //request.CoverURL = "http://img.alicdn.com/tps/TB1qnJ1PVXXXXXCXXXXXXXXXXXX-700-700.png"
  44 + //request.Tags = "tag1,tag2"
  45 + request.AcceptFormat = "JSON"
  46 + rsp, err := client.CreateUploadVideo(request)
  47 + if err != nil {
  48 + return
  49 + }
  50 + response = &CreateUploadVideoResponse{
  51 + RequestId: rsp.RequestId,
  52 + VideoId: rsp.VideoId,
  53 + UploadAddress: rsp.UploadAddress,
  54 + UploadAuth: rsp.UploadAuth,
  55 + }
  56 + return
  57 +}
  58 +
  59 +//获取播放信息
  60 +func GetPlayInfo(client *vod.Client, videoId string) (response *vod.GetPlayInfoResponse, err error) {
  61 + request := vod.CreateGetPlayInfoRequest()
  62 + request.VideoId = videoId
  63 + request.AcceptFormat = "JSON"
  64 + return client.GetPlayInfo(request)
  65 +}
  66 +
  67 +//fileType: video voice image
  68 +func getFileName(fileType string, filename string) string {
  69 + date := comm_time.GetTimeByYyyymmdd()
  70 + subfix := path.Ext(filename)
  71 + prefix := fmt.Sprintf("%v_%v", time.Now().Unix(), common.RandomString(32))
  72 + filename = fmt.Sprintf("%v%v", prefix, subfix)
  73 + sourcePath := fmt.Sprintf("%v/%v/%v/%v/%v", beego.BConfig.AppName, beego.BConfig.RunMode, fileType, date, filename)
  74 + return sourcePath
  75 +}
1 package utils 1 package utils
2 2
3 import ( 3 import (
  4 + "bytes"
  5 + "encoding/gob"
4 "encoding/json" 6 "encoding/json"
5 "errors" 7 "errors"
6 "fmt" 8 "fmt"
@@ -85,3 +87,12 @@ func JsonUnmarshal(jsonData string, v interface{}) { @@ -85,3 +87,12 @@ func JsonUnmarshal(jsonData string, v interface{}) {
85 log.Error("json.unmarshal error data:", jsonData, e) 87 log.Error("json.unmarshal error data:", jsonData, e)
86 } 88 }
87 } 89 }
  90 +
  91 +//深度拷贝
  92 +func DeepCopy(dst, src interface{}) error {
  93 + var buf bytes.Buffer
  94 + if err := gob.NewEncoder(&buf).Encode(src); err != nil {
  95 + return err
  96 + }
  97 + return gob.NewDecoder(&buf).Decode(dst)
  98 +}
  1 +package utils
  2 +
  3 +import "testing"
  4 +
  5 +func Test_DeepCopy(t *testing.T) {
  6 + type User1 struct {
  7 + Name string
  8 + Age int
  9 + Address string
  10 + }
  11 + type User2 struct {
  12 + Name string
  13 + Age int
  14 + Job string
  15 + }
  16 + var src = User1{Name: "foo", Age: 10, Address: "bar"}
  17 + var dst *User2
  18 + if err := DeepCopy(&dst, src); err != nil {
  19 + t.Fatal(err)
  20 + }
  21 + if src.Name != dst.Name {
  22 + t.Fatal("deep copy fail.")
  23 + }
  24 + //t.Log(src,"\n",dst)
  25 +}
@@ -5,7 +5,7 @@ import "mime/multipart" @@ -5,7 +5,7 @@ import "mime/multipart"
5 const ( 5 const (
6 FileImage = "image" 6 FileImage = "image"
7 FileVoice = "voice" 7 FileVoice = "voice"
8 - FileVideo ="video" 8 + FileVideo = "video"
9 ) 9 )
10 10
11 /*Image */ 11 /*Image */
@@ -393,6 +393,14 @@ func init() { @@ -393,6 +393,14 @@ func init() {
393 393
394 beego.GlobalControllerRouter["opp/controllers/v1:UploadController"] = append(beego.GlobalControllerRouter["opp/controllers/v1:UploadController"], 394 beego.GlobalControllerRouter["opp/controllers/v1:UploadController"] = append(beego.GlobalControllerRouter["opp/controllers/v1:UploadController"],
395 beego.ControllerComments{ 395 beego.ControllerComments{
  396 + Method: "CreateUploadVideo",
  397 + Router: `/createUploadVideo`,
  398 + AllowHTTPMethods: []string{"post"},
  399 + MethodParams: param.Make(),
  400 + Params: nil})
  401 +
  402 + beego.GlobalControllerRouter["opp/controllers/v1:UploadController"] = append(beego.GlobalControllerRouter["opp/controllers/v1:UploadController"],
  403 + beego.ControllerComments{
396 Method: "Image", 404 Method: "Image",
397 Router: `/image`, 405 Router: `/image`,
398 AllowHTTPMethods: []string{"post"}, 406 AllowHTTPMethods: []string{"post"},
@@ -23,6 +23,7 @@ func init() { @@ -23,6 +23,7 @@ func init() {
23 beego.NSNamespace("message", beego.NSBefore(controllers.FilterComm), beego.NSInclude(&v1.MessageController{})), 23 beego.NSNamespace("message", beego.NSBefore(controllers.FilterComm), beego.NSInclude(&v1.MessageController{})),
24 beego.NSNamespace("department", beego.NSBefore(controllers.FilterComm), beego.NSInclude(&v1.DepartmentController{})), 24 beego.NSNamespace("department", beego.NSBefore(controllers.FilterComm), beego.NSInclude(&v1.DepartmentController{})),
25 beego.NSNamespace("config", beego.NSBefore(controllers.FilterComm), beego.NSInclude(&v1.ConfigController{})), 25 beego.NSNamespace("config", beego.NSBefore(controllers.FilterComm), beego.NSInclude(&v1.ConfigController{})),
  26 + beego.NSNamespace("file", beego.NSBefore(controllers.FilterComm), beego.NSInclude(&v1.FileController{})),
26 ) 27 )
27 beego.AddNamespace(nsV1) 28 beego.AddNamespace(nsV1)
28 29
  1 +package file
  2 +
  3 +import (
  4 + "github.com/prometheus/common/log"
  5 + "opp/internal/aliyun"
  6 + "opp/internal/utils"
  7 + "opp/protocol"
  8 +)
  9 +
  10 +//GetPlayInfo 获取播放信息
  11 +func GetPlayInfo(header *protocol.RequestHeader, request *aliyun.GetPlayInfoRequest) (rsp *aliyun.GetPlayInfoResponse, err error) {
  12 + var ()
  13 + client, e := aliyun.DefaultVodClient()
  14 + if e != nil {
  15 + log.Error(e)
  16 + err = e
  17 + return
  18 + }
  19 + response, e := aliyun.GetPlayInfo(client, request.VideoId)
  20 + if e != nil {
  21 + log.Error(e)
  22 + err = e
  23 + return
  24 + }
  25 + rsp = &aliyun.GetPlayInfoResponse{}
  26 + if err = utils.DeepCopy(&rsp, response); err != nil {
  27 + log.Error(err)
  28 + return
  29 + }
  30 + return
  31 +}
@@ -5,6 +5,7 @@ import ( @@ -5,6 +5,7 @@ import (
5 "github.com/disintegration/imaging" 5 "github.com/disintegration/imaging"
6 "io" 6 "io"
7 "mime/multipart" 7 "mime/multipart"
  8 + "opp/internal/aliyun"
8 "os" 9 "os"
9 "path" 10 "path"
10 "path/filepath" 11 "path/filepath"
@@ -133,3 +134,16 @@ func GetSortFileKeys(files map[string][]*multipart.FileHeader) (keys []string) { @@ -133,3 +134,16 @@ func GetSortFileKeys(files map[string][]*multipart.FileHeader) (keys []string) {
133 sort.Strings(keys) 134 sort.Strings(keys)
134 return 135 return
135 } 136 }
  137 +
  138 +//创建视频上传凭证
  139 +func CreateUploadVideo(header *protocol.RequestHeader, request *aliyun.CreateUploadVideoRequest) (rsp *aliyun.CreateUploadVideoResponse, err error) {
  140 + var ()
  141 + client, e := aliyun.DefaultVodClient()
  142 + if e != nil {
  143 + log.Error(e)
  144 + err = e
  145 + return
  146 + }
  147 + rsp, err = aliyun.CreateUploadVideo(client)
  148 + return
  149 +}