Browse Source

Can upload video

HEAD
Yang Luo 2 years ago
parent
commit
22cefa3002
8 changed files with 198 additions and 4 deletions
  1. +49
    -0
      controllers/video.go
  2. +1
    -0
      routers/router.go
  3. +4
    -0
      util/path.go
  4. +10
    -0
      util/string.go
  5. +28
    -0
      video/oss_api.go
  6. +57
    -0
      video/vod_api.go
  7. +1
    -1
      web/src/VideoEditPage.js
  8. +48
    -3
      web/src/VideoListPage.js

+ 49
- 0
controllers/video.go View File

@@ -1,9 +1,14 @@
package controllers

import (
"bytes"
"encoding/json"
"fmt"
"io"

"github.com/casbin/casbase/object"
"github.com/casbin/casbase/util"
"github.com/casbin/casbase/video"
)

func (c *ApiController) GetGlobalVideos() {
@@ -59,3 +64,47 @@ func (c *ApiController) DeleteVideo() {
c.Data["json"] = object.DeleteVideo(&video)
c.ServeJSON()
}

func (c *ApiController) UploadVideo() {
owner := c.GetSessionUsername()

file, header, err := c.GetFile("file")
if err != nil {
panic(err)
}
defer file.Close()

filename := header.Filename
fileId := util.RemoveExt(filename)

fileBuffer := bytes.NewBuffer(nil)
if _, err = io.Copy(fileBuffer, file); err != nil {
c.ResponseError(err.Error())
return
}

fileType := "unknown"
contentType := header.Header.Get("Content-Type")
fileType, _ = util.GetOwnerAndNameFromId(contentType)

if fileType != "video" {
c.ResponseError(fmt.Sprintf("contentType: %s is not video", contentType))
return
}

videoId := video.UploadVideo(fileId, filename, fileBuffer)
if videoId != "" {
video := &object.Video{
Owner: owner,
Name: fileId,
CreatedTime: util.GetCurrentTime(),
DisplayName: fileId,
VideoId: videoId,
Labels: []*object.Label{},
}
object.AddVideo(video)
c.ResponseOk(fileId)
} else {
c.ResponseError("videoId is empty")
}
}

+ 1
- 0
routers/router.go View File

@@ -44,6 +44,7 @@ func initAPI() {
beego.Router("/api/update-video", &controllers.ApiController{}, "POST:UpdateVideo")
beego.Router("/api/add-video", &controllers.ApiController{}, "POST:AddVideo")
beego.Router("/api/delete-video", &controllers.ApiController{}, "POST:DeleteVideo")
beego.Router("/api/upload-video", &controllers.ApiController{}, "POST:UploadVideo")

beego.Router("/api/get-global-stores", &controllers.ApiController{}, "GET:GetGlobalStores")
beego.Router("/api/get-stores", &controllers.ApiController{}, "GET:GetStores")


+ 4
- 0
util/path.go View File

@@ -29,6 +29,10 @@ func EnsureFileFolderExists(path string) {
}
}

func RemoveExt(filename string) string {
return filename[:len(filename)-len(filepath.Ext(filename))]
}

func ListFiles(path string) []string {
res := []string{}



+ 10
- 0
util/string.go View File

@@ -1,6 +1,7 @@
package util

import (
"encoding/base64"
"errors"
"fmt"
"io/ioutil"
@@ -115,3 +116,12 @@ func WriteBytesToPath(b []byte, path string) {
panic(err)
}
}

func DecodeBase64(s string) string {
res, err := base64.StdEncoding.DecodeString(s)
if err != nil {
panic(err)
}

return string(res)
}

+ 28
- 0
video/oss_api.go View File

@@ -0,0 +1,28 @@
package video

import (
"bytes"

"github.com/aliyun/aliyun-oss-go-sdk/oss"
)

func getOssClient(endpoint string, accessKeyId string, accessKeySecret string, securityToken string) *oss.Client {
client, err := oss.New(endpoint, accessKeyId, accessKeySecret, oss.SecurityToken(securityToken))
if err != nil {
panic(err)
}

return client
}

func uploadLocalFile(ossClient *oss.Client, bucketName string, objectKey string, fileBuffer *bytes.Buffer) {
bucket, err := ossClient.Bucket(bucketName)
if err != nil {
panic(err)
}

err = bucket.PutObject(objectKey, fileBuffer)
if err != nil {
panic(err)
}
}

+ 57
- 0
video/vod_api.go View File

@@ -1,9 +1,12 @@
package video

import (
"bytes"
"fmt"
"time"

"github.com/aliyun/alibaba-cloud-sdk-go/services/vod"
"github.com/casbin/casbase/util"
)

func GetVideoPlayAuth(videoId string) string {
@@ -20,3 +23,57 @@ func GetVideoPlayAuth(videoId string) string {
playAuth := resp.PlayAuth
return playAuth
}

type UploadAddress struct {
Endpoint string `json:"Endpoint"`
Bucket string `json:"Bucket"`
FileName string `json:"FileName"`
}

type UploadAuth struct {
SecurityToken string `json:"SecurityToken"`
AccessKeyId string `json:"AccessKeyId"`
ExpireUTCTime time.Time `json:"ExpireUTCTime"`
AccessKeySecret string `json:"AccessKeySecret"`
Expiration string `json:"Expiration"`
Region string `json:"Region"`
}

func UploadVideo(fileId string, filename string, fileBuffer *bytes.Buffer) string {
// https://help.aliyun.com/document_detail/476208.html

r := vod.CreateCreateUploadVideoRequest()
r.Scheme = "https"
r.FileName = filename
r.Title = fileId

resp, err := vodClient.CreateUploadVideo(r)
if err != nil {
panic(err)
}

encodedUploadAddress := resp.UploadAddress
videoId := resp.VideoId
encodedUploadAuth := resp.UploadAuth

uploadAddressStr := util.DecodeBase64(encodedUploadAddress)
uploadAuthStr := util.DecodeBase64(encodedUploadAuth)

uploadAddress := &UploadAddress{}
err = util.JsonToStruct(uploadAddressStr, uploadAddress)
if err != nil {
panic(err)
}

uploadAuth := &UploadAuth{}
err = util.JsonToStruct(uploadAuthStr, uploadAuth)
if err != nil {
panic(err)
}

ossClient := getOssClient(uploadAddress.Endpoint, uploadAuth.AccessKeyId, uploadAuth.AccessKeySecret, uploadAuth.SecurityToken)

uploadLocalFile(ossClient, uploadAddress.Bucket, uploadAddress.FileName, fileBuffer)

return videoId
}

+ 1
- 1
web/src/VideoEditPage.js View File

@@ -136,7 +136,7 @@ class VideoEditPage extends React.Component {
{i18next.t("video:Video ID")}:
</Col>
<Col span={22} >
<Input value={this.state.video.videoId} onChange={e => {
<Input disabled={true} value={this.state.video.videoId} onChange={e => {
this.updateVideoField('videoId', e.target.value);
}} />
</Col>


+ 48
- 3
web/src/VideoListPage.js View File

@@ -1,6 +1,7 @@
import React from "react";
import {Link} from "react-router-dom";
import {Button, Col, Popconfirm, Row, Table} from 'antd';
import {Button, Col, Popconfirm, Row, Table, Upload} from 'antd';
import {UploadOutlined} from "@ant-design/icons";
import moment from "moment";
import * as Setting from "./Setting";
import * as VideoBackend from "./backend/VideoBackend";
@@ -68,6 +69,45 @@ class VideoListPage extends React.Component {
});
}
uploadFile(info) {
const { status, response: res } = info.file;
if (status !== 'uploading') {
console.log(info.file, info.fileList);
}
if (status === 'done') {
if (res.status === 'ok') {
Setting.showMessage("success", `上传视频成功`);
const videoName = res.data;
this.props.history.push(`/videos/${videoName}`);
} else {
Setting.showMessage("error", `上传视频失败:${res.msg}`);
}
} else if (status === 'error') {
Setting.showMessage("success", `上传视频失败`);
}
}
renderUpload() {
const props = {
name: 'file',
accept: '.mp4',
method: 'post',
action: `${Setting.ServerUrl}/api/upload-video`,
withCredentials: true,
onChange: (info) => {
this.uploadFile(info);
},
};
return (
<Upload {...props}>
<Button type="primary" size="small">
<UploadOutlined /> 上传视频(.mp4)
</Button>
</Upload>
)
}
renderTable(videos) {
const columns = [
{
@@ -158,8 +198,13 @@ class VideoListPage extends React.Component {
<Table columns={columns} dataSource={videos} rowKey="name" size="middle" bordered pagination={{pageSize: 100}}
title={() => (
<div>
{i18next.t("general:Videos")}&nbsp;&nbsp;&nbsp;&nbsp;
<Button type="primary" size="small" onClick={this.addVideo.bind(this)}>{i18next.t("general:Add")}</Button>
{i18next.t("general:Videos")}
{/*&nbsp;&nbsp;&nbsp;&nbsp;*/}
{/*<Button type="primary" size="small" onClick={this.addVideo.bind(this)}>{i18next.t("general:Add")}</Button>*/}
&nbsp;&nbsp;&nbsp;&nbsp;
{
this.renderUpload()
}
</div>
)}
loading={videos === null}


Loading…
Cancel
Save