Add video pages.
This commit is contained in:
parent
36f2787837
commit
c38af47c59
|
@ -0,0 +1,61 @@
|
||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/openbrainorg/openbrain/object"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *ApiController) GetGlobalVideos() {
|
||||||
|
c.Data["json"] = object.GetGlobalVideos()
|
||||||
|
c.ServeJSON()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ApiController) GetVideos() {
|
||||||
|
owner := c.Input().Get("owner")
|
||||||
|
|
||||||
|
c.Data["json"] = object.GetVideos(owner)
|
||||||
|
c.ServeJSON()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ApiController) GetVideo() {
|
||||||
|
id := c.Input().Get("id")
|
||||||
|
|
||||||
|
c.Data["json"] = object.GetVideo(id)
|
||||||
|
c.ServeJSON()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ApiController) UpdateVideo() {
|
||||||
|
id := c.Input().Get("id")
|
||||||
|
|
||||||
|
var video object.Video
|
||||||
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &video)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Data["json"] = object.UpdateVideo(id, &video)
|
||||||
|
c.ServeJSON()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ApiController) AddVideo() {
|
||||||
|
var video object.Video
|
||||||
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &video)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Data["json"] = object.AddVideo(&video)
|
||||||
|
c.ServeJSON()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *ApiController) DeleteVideo() {
|
||||||
|
var video object.Video
|
||||||
|
err := json.Unmarshal(c.Ctx.Input.RequestBody, &video)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Data["json"] = object.DeleteVideo(&video)
|
||||||
|
c.ServeJSON()
|
||||||
|
}
|
1
go.mod
1
go.mod
|
@ -3,6 +3,7 @@ module github.com/openbrainorg/openbrain
|
||||||
go 1.16
|
go 1.16
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1585
|
||||||
github.com/astaxie/beego v1.12.3
|
github.com/astaxie/beego v1.12.3
|
||||||
github.com/casdoor/casdoor-go-sdk v0.3.3
|
github.com/casdoor/casdoor-go-sdk v0.3.3
|
||||||
github.com/danaugrs/go-tsne/tsne v0.0.0-20220306155740-2250969e057f
|
github.com/danaugrs/go-tsne/tsne v0.0.0-20220306155740-2250969e057f
|
||||||
|
|
10
go.sum
10
go.sum
|
@ -51,6 +51,8 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
|
||||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
|
github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
|
||||||
github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk=
|
github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk=
|
||||||
|
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1585 h1:ECnkjykkSn3Gsibjd8FrcC+8SMDJcUbJOP4iT2hItrw=
|
||||||
|
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1585/go.mod h1:RcDobYh8k5VP6TNybz9m++gL3ijVI5wueVr0EM10VsU=
|
||||||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||||
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
|
||||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||||
|
@ -159,6 +161,7 @@ github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFG
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||||
|
github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A=
|
||||||
github.com/golang-jwt/jwt/v4 v4.1.0 h1:XUgk2Ex5veyVFVeLm0xhusUTQybEbexJXrvPNOKkSY0=
|
github.com/golang-jwt/jwt/v4 v4.1.0 h1:XUgk2Ex5veyVFVeLm0xhusUTQybEbexJXrvPNOKkSY0=
|
||||||
github.com/golang-jwt/jwt/v4 v4.1.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
github.com/golang-jwt/jwt/v4 v4.1.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
||||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||||
|
@ -301,8 +304,10 @@ github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0f
|
||||||
github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||||
github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||||
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
|
||||||
|
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
|
||||||
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||||
|
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
|
@ -875,6 +880,8 @@ gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
|
gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
|
||||||
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
||||||
|
gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI=
|
||||||
|
gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
|
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
|
||||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||||
|
@ -887,8 +894,9 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
|
|
@ -94,4 +94,9 @@ func (a *Adapter) createTable() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = a.engine.Sync2(new(Video))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
package object
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/openbrainorg/openbrain/util"
|
||||||
|
"github.com/openbrainorg/openbrain/video"
|
||||||
|
"xorm.io/core"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Video struct {
|
||||||
|
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
|
||||||
|
Name string `xorm:"varchar(100) notnull pk" json:"name"`
|
||||||
|
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
|
||||||
|
DisplayName string `xorm:"varchar(500)" json:"displayName"`
|
||||||
|
|
||||||
|
VideoId string `xorm:"varchar(100)" json:"videoId"`
|
||||||
|
CoverUrl string `xorm:"varchar(200)" json:"coverUrl"`
|
||||||
|
|
||||||
|
PlayAuth string `xorm:"-" json:"playAuth"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetGlobalVideos() []*Video {
|
||||||
|
videos := []*Video{}
|
||||||
|
err := adapter.engine.Asc("owner").Desc("created_time").Find(&videos)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return videos
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetVideos(owner string) []*Video {
|
||||||
|
videos := []*Video{}
|
||||||
|
err := adapter.engine.Desc("created_time").Find(&videos, &Video{Owner: owner})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return videos
|
||||||
|
}
|
||||||
|
|
||||||
|
func getVideo(owner string, name string) *Video {
|
||||||
|
v := Video{Owner: owner, Name: name}
|
||||||
|
existed, err := adapter.engine.Get(&v)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if existed {
|
||||||
|
v.PlayAuth = video.GetVideoPlayAuth(v.VideoId)
|
||||||
|
return &v
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetVideo(id string) *Video {
|
||||||
|
owner, name := util.GetOwnerAndNameFromId(id)
|
||||||
|
return getVideo(owner, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateVideo(id string, video *Video) bool {
|
||||||
|
owner, name := util.GetOwnerAndNameFromId(id)
|
||||||
|
if getVideo(owner, name) == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := adapter.engine.ID(core.PK{owner, name}).AllCols().Update(video)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
//return affected != 0
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddVideo(video *Video) bool {
|
||||||
|
affected, err := adapter.engine.Insert(video)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return affected != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteVideo(video *Video) bool {
|
||||||
|
affected, err := adapter.engine.ID(core.PK{video.Owner, video.Name}).Delete(&Video{})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return affected != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (video *Video) GetId() string {
|
||||||
|
return fmt.Sprintf("%s/%s", video.Owner, video.Name)
|
||||||
|
}
|
|
@ -38,4 +38,11 @@ func initAPI() {
|
||||||
beego.Router("/api/update-vectorset", &controllers.ApiController{}, "POST:UpdateVectorset")
|
beego.Router("/api/update-vectorset", &controllers.ApiController{}, "POST:UpdateVectorset")
|
||||||
beego.Router("/api/add-vectorset", &controllers.ApiController{}, "POST:AddVectorset")
|
beego.Router("/api/add-vectorset", &controllers.ApiController{}, "POST:AddVectorset")
|
||||||
beego.Router("/api/delete-vectorset", &controllers.ApiController{}, "POST:DeleteVectorset")
|
beego.Router("/api/delete-vectorset", &controllers.ApiController{}, "POST:DeleteVectorset")
|
||||||
|
|
||||||
|
beego.Router("/api/get-global-videos", &controllers.ApiController{}, "GET:GetGlobalVideos")
|
||||||
|
beego.Router("/api/get-videos", &controllers.ApiController{}, "GET:GetVideos")
|
||||||
|
beego.Router("/api/get-video", &controllers.ApiController{}, "GET:GetVideo")
|
||||||
|
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")
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
package video
|
||||||
|
|
||||||
|
var regionId = ""
|
||||||
|
var accessKeyId = ""
|
||||||
|
var accessKeySecret = ""
|
|
@ -0,0 +1,18 @@
|
||||||
|
package video
|
||||||
|
|
||||||
|
import "github.com/aliyun/alibaba-cloud-sdk-go/services/vod"
|
||||||
|
|
||||||
|
var vodClient *vod.Client
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
vodClient = InitVodClient()
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitVodClient() *vod.Client {
|
||||||
|
vodClient, err := vod.NewClientWithAccessKey(regionId, accessKeyId, accessKeySecret)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return vodClient
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package video
|
||||||
|
|
||||||
|
import "github.com/aliyun/alibaba-cloud-sdk-go/services/vod"
|
||||||
|
|
||||||
|
func GetVideoPlayAuth(videoId string) string {
|
||||||
|
r := vod.CreateGetVideoPlayAuthRequest()
|
||||||
|
r.VideoId = videoId
|
||||||
|
r.AcceptFormat = "JSON"
|
||||||
|
|
||||||
|
resp, err := vodClient.GetVideoPlayAuth(r)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
playAuth := resp.PlayAuth
|
||||||
|
return playAuth
|
||||||
|
}
|
|
@ -5,6 +5,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design/icons": "4.6.2",
|
"@ant-design/icons": "4.6.2",
|
||||||
"@craco/craco": "6.1.1",
|
"@craco/craco": "6.1.1",
|
||||||
|
"aliplayer-react": "^0.7.0",
|
||||||
"antd": "4.15.5",
|
"antd": "4.15.5",
|
||||||
"casdoor-js-sdk": "^0.2.7",
|
"casdoor-js-sdk": "^0.2.7",
|
||||||
"copy-to-clipboard": "^3.3.1",
|
"copy-to-clipboard": "^3.3.1",
|
||||||
|
|
|
@ -13,6 +13,8 @@ import WordsetEditPage from "./WordsetEditPage";
|
||||||
import WordsetGraphPage from "./WordsetGraphPage";
|
import WordsetGraphPage from "./WordsetGraphPage";
|
||||||
import VectorsetListPage from "./VectorsetListPage";
|
import VectorsetListPage from "./VectorsetListPage";
|
||||||
import VectorsetEditPage from "./VectorsetEditPage";
|
import VectorsetEditPage from "./VectorsetEditPage";
|
||||||
|
import VideoListPage from "./VideoListPage";
|
||||||
|
import VideoEditPage from "./VideoEditPage";
|
||||||
import SigninPage from "./SigninPage";
|
import SigninPage from "./SigninPage";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import SelectLanguageBox from "./SelectLanguageBox";
|
import SelectLanguageBox from "./SelectLanguageBox";
|
||||||
|
@ -58,6 +60,8 @@ class App extends Component {
|
||||||
this.setState({ selectedMenuKey: '/wordsets' });
|
this.setState({ selectedMenuKey: '/wordsets' });
|
||||||
} else if (uri.includes('/vectorsets')) {
|
} else if (uri.includes('/vectorsets')) {
|
||||||
this.setState({ selectedMenuKey: '/vectorsets' });
|
this.setState({ selectedMenuKey: '/vectorsets' });
|
||||||
|
} else if (uri.includes('/videos')) {
|
||||||
|
this.setState({ selectedMenuKey: '/videos' });
|
||||||
} else {
|
} else {
|
||||||
this.setState({selectedMenuKey: 'null'});
|
this.setState({selectedMenuKey: 'null'});
|
||||||
}
|
}
|
||||||
|
@ -231,6 +235,13 @@ class App extends Component {
|
||||||
</Link>
|
</Link>
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
);
|
);
|
||||||
|
res.push(
|
||||||
|
<Menu.Item key="/videos">
|
||||||
|
<Link to="/videos">
|
||||||
|
{i18next.t("general:Videos")}
|
||||||
|
</Link>
|
||||||
|
</Menu.Item>
|
||||||
|
);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -286,6 +297,8 @@ class App extends Component {
|
||||||
<Route exact path="/wordsets/:wordsetName/graph" render={(props) => this.renderSigninIfNotSignedIn(<WordsetGraphPage account={this.state.account} {...props} />)}/>
|
<Route exact path="/wordsets/:wordsetName/graph" render={(props) => this.renderSigninIfNotSignedIn(<WordsetGraphPage account={this.state.account} {...props} />)}/>
|
||||||
<Route exact path="/vectorsets" render={(props) => this.renderSigninIfNotSignedIn(<VectorsetListPage account={this.state.account} {...props} />)}/>
|
<Route exact path="/vectorsets" render={(props) => this.renderSigninIfNotSignedIn(<VectorsetListPage account={this.state.account} {...props} />)}/>
|
||||||
<Route exact path="/vectorsets/:vectorsetName" render={(props) => this.renderSigninIfNotSignedIn(<VectorsetEditPage account={this.state.account} {...props} />)}/>
|
<Route exact path="/vectorsets/:vectorsetName" render={(props) => this.renderSigninIfNotSignedIn(<VectorsetEditPage account={this.state.account} {...props} />)}/>
|
||||||
|
<Route exact path="/videos" render={(props) => this.renderSigninIfNotSignedIn(<VideoListPage account={this.state.account} {...props} />)}/>
|
||||||
|
<Route exact path="/videos/:videoName" render={(props) => this.renderSigninIfNotSignedIn(<VideoEditPage account={this.state.account} {...props} />)}/>
|
||||||
</Switch>
|
</Switch>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
import React from "react";
|
||||||
|
import Player from 'aliplayer-react';
|
||||||
|
import * as Setting from "./Setting";
|
||||||
|
|
||||||
|
class Video extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
classes: props,
|
||||||
|
player: null,
|
||||||
|
width: !Setting.isMobile() ? this.props.task.video.width : "100%",
|
||||||
|
height: "100%",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
updateVideoSize(width, height) {
|
||||||
|
if (this.props.onUpdateVideoSize !== undefined) {
|
||||||
|
this.props.onUpdateVideoSize(width, height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleReady(player) {
|
||||||
|
let videoWidth = player.tag.videoWidth;
|
||||||
|
let videoHeight = player.tag.videoHeight;
|
||||||
|
|
||||||
|
if (this.props.onUpdateVideoSize !== undefined) {
|
||||||
|
if (videoWidth !== 0 && videoHeight !== 0) {
|
||||||
|
this.updateVideoSize(videoWidth, videoHeight);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
videoWidth = this.props.task.video.videoWidth;
|
||||||
|
videoHeight = this.props.task.video.videoHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
const myWidth = player.tag.scrollWidth;
|
||||||
|
const myHeight = videoHeight * myWidth / videoWidth;
|
||||||
|
|
||||||
|
player.setPlayerSize(myWidth, myHeight);
|
||||||
|
this.setState({
|
||||||
|
width: myWidth,
|
||||||
|
height: myHeight,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
initPlayer(player) {
|
||||||
|
player.on('ready', () => {this.handleReady(player)});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const video = this.props.task.video;
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
source: video.source,
|
||||||
|
cover: video.cover,
|
||||||
|
width: !Setting.isMobile() ? video.width : "100%",
|
||||||
|
height: "100%",
|
||||||
|
autoplay: video.autoplay,
|
||||||
|
isLive: video.isLive,
|
||||||
|
rePlay: video.rePlay,
|
||||||
|
playsinline: video.playsinline,
|
||||||
|
preload: video.preload,
|
||||||
|
controlBarVisibility: video.controlBarVisibility,
|
||||||
|
useH5Prism: video.useH5Prism,
|
||||||
|
// components: [
|
||||||
|
// {
|
||||||
|
// name: "RateComponent",
|
||||||
|
// type: Player.components.RateComponent,
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
};
|
||||||
|
|
||||||
|
if (video.source !== undefined) {
|
||||||
|
config.source = video.source;
|
||||||
|
} else {
|
||||||
|
config.vid = video.vid;
|
||||||
|
config.playauth = video.playAuth;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{width: this.state.width, height: this.state.height, margin: "auto"}}>
|
||||||
|
<Player
|
||||||
|
config={config}
|
||||||
|
onGetInstance={player => {
|
||||||
|
this.initPlayer(player);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Video;
|
|
@ -0,0 +1,207 @@
|
||||||
|
import React from "react";
|
||||||
|
import {Button, Card, Col, Input, Row} from 'antd';
|
||||||
|
import * as VideoBackend from "./backend/VideoBackend";
|
||||||
|
import * as Setting from "./Setting";
|
||||||
|
import i18next from "i18next";
|
||||||
|
import {LinkOutlined} from "@ant-design/icons";
|
||||||
|
import Video from "./Video";
|
||||||
|
|
||||||
|
class VideoEditPage extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
classes: props,
|
||||||
|
videoName: props.match.params.videoName,
|
||||||
|
video: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillMount() {
|
||||||
|
this.getVideo();
|
||||||
|
}
|
||||||
|
|
||||||
|
getVideo() {
|
||||||
|
VideoBackend.getVideo(this.props.account.name, this.state.videoName)
|
||||||
|
.then((video) => {
|
||||||
|
this.setState({
|
||||||
|
video: video,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
parseVideoField(key, value) {
|
||||||
|
if (["score"].includes(key)) {
|
||||||
|
value = Setting.myParseInt(value);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateVideoField(key, value) {
|
||||||
|
value = this.parseVideoField(key, value);
|
||||||
|
|
||||||
|
let video = this.state.video;
|
||||||
|
video[key] = value;
|
||||||
|
this.setState({
|
||||||
|
video: video,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
renderVideoContent() {
|
||||||
|
let task = {};
|
||||||
|
task.video = {
|
||||||
|
vid: this.state.video.videoId,
|
||||||
|
playAuth: this.state.video.playAuth,
|
||||||
|
cover: this.state.video.coverUrl,
|
||||||
|
videoWidth: 1920,
|
||||||
|
videoHeight: 1080,
|
||||||
|
width: "840px",
|
||||||
|
autoplay: false,
|
||||||
|
isLive: false,
|
||||||
|
rePlay: false,
|
||||||
|
playsinline: true,
|
||||||
|
preload: true,
|
||||||
|
controlBarVisibility: "hover",
|
||||||
|
useH5Prism: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{marginTop: "10px", textAlign: "center"}}>
|
||||||
|
{/*{*/}
|
||||||
|
{/* JSON.stringify(this.state.video)*/}
|
||||||
|
{/*}*/}
|
||||||
|
<div style={{fontSize: 30, marginBottom: "20px"}}>
|
||||||
|
{
|
||||||
|
this.state.video.name
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<Video task={task} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
renderVideo() {
|
||||||
|
return (
|
||||||
|
<Card size="small" title={
|
||||||
|
<div>
|
||||||
|
{i18next.t("video:Edit Video")}
|
||||||
|
<Button type="primary" onClick={this.submitVideoEdit.bind(this)}>{i18next.t("general:Save")}</Button>
|
||||||
|
</div>
|
||||||
|
} style={{marginLeft: '5px'}} type="inner">
|
||||||
|
<Row style={{marginTop: '10px'}} >
|
||||||
|
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{i18next.t("general:Name")}:
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<Input value={this.state.video.name} onChange={e => {
|
||||||
|
this.updateVideoField('name', e.target.value);
|
||||||
|
}} />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row style={{marginTop: '20px'}} >
|
||||||
|
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{i18next.t("general:Display name")}:
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<Input value={this.state.video.displayName} onChange={e => {
|
||||||
|
this.updateVideoField('displayName', e.target.value);
|
||||||
|
}} />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row style={{marginTop: '20px'}} >
|
||||||
|
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{i18next.t("video:Video ID")}:
|
||||||
|
</Col>
|
||||||
|
<Col span={22} >
|
||||||
|
<Input value={this.state.video.videoId} onChange={e => {
|
||||||
|
this.updateVideoField('videoId', e.target.value);
|
||||||
|
}} />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row style={{marginTop: '20px'}} >
|
||||||
|
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{i18next.t("video:Cover")}:
|
||||||
|
</Col>
|
||||||
|
<Col span={22} style={(Setting.isMobile()) ? {maxWidth:'100%'} :{}}>
|
||||||
|
<Row style={{marginTop: '20px'}} >
|
||||||
|
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 1}>
|
||||||
|
{i18next.t("general:URL")} :
|
||||||
|
</Col>
|
||||||
|
<Col span={23} >
|
||||||
|
<Input prefix={<LinkOutlined/>} value={this.state.video.coverUrl} onChange={e => {
|
||||||
|
this.updateVideoField('coverUrl', e.target.value);
|
||||||
|
}} />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row style={{marginTop: '20px'}} >
|
||||||
|
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 1}>
|
||||||
|
{i18next.t("general:Preview")}:
|
||||||
|
</Col>
|
||||||
|
<Col span={23} >
|
||||||
|
<a target="_blank" rel="noreferrer" href={this.state.video.coverUrl}>
|
||||||
|
<img src={this.state.video.coverUrl} alt={this.state.video.coverUrl} height={90} style={{marginBottom: '20px'}}/>
|
||||||
|
</a>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row style={{marginTop: '20px'}} >
|
||||||
|
<Col style={{marginTop: '5px'}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||||
|
{i18next.t("video:Video")}:
|
||||||
|
</Col>
|
||||||
|
<Col span={22} style={(Setting.isMobile()) ? {maxWidth:'100%'} :{}}>
|
||||||
|
{
|
||||||
|
this.state.video !== null ? this.renderVideoContent() : null
|
||||||
|
}
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
submitVideoEdit() {
|
||||||
|
let video = Setting.deepCopy(this.state.video);
|
||||||
|
VideoBackend.updateVideo(this.state.video.owner, this.state.videoName, video)
|
||||||
|
.then((res) => {
|
||||||
|
if (res) {
|
||||||
|
Setting.showMessage("success", `Successfully saved`);
|
||||||
|
this.setState({
|
||||||
|
videoName: this.state.video.name,
|
||||||
|
});
|
||||||
|
this.props.history.push(`/videos/${this.state.video.name}`);
|
||||||
|
} else {
|
||||||
|
Setting.showMessage("error", `failed to save: server side failure`);
|
||||||
|
this.updateVideoField('name', this.state.videoName);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
Setting.showMessage("error", `failed to save: ${error}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Row style={{width: "100%"}}>
|
||||||
|
<Col span={1}>
|
||||||
|
</Col>
|
||||||
|
<Col span={22}>
|
||||||
|
{
|
||||||
|
this.state.video !== null ? this.renderVideo() : null
|
||||||
|
}
|
||||||
|
</Col>
|
||||||
|
<Col span={1}>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row style={{margin: 10}}>
|
||||||
|
<Col span={2}>
|
||||||
|
</Col>
|
||||||
|
<Col span={18}>
|
||||||
|
<Button type="primary" size="large" onClick={this.submitVideoEdit.bind(this)}>{i18next.t("general:Save")}</Button>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default VideoEditPage;
|
|
@ -0,0 +1,172 @@
|
||||||
|
import React from "react";
|
||||||
|
import {Link} from "react-router-dom";
|
||||||
|
import {Button, Col, Popconfirm, Row, Table} from 'antd';
|
||||||
|
import moment from "moment";
|
||||||
|
import * as Setting from "./Setting";
|
||||||
|
import * as VideoBackend from "./backend/VideoBackend";
|
||||||
|
import i18next from "i18next";
|
||||||
|
|
||||||
|
class VideoListPage extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
classes: props,
|
||||||
|
videos: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillMount() {
|
||||||
|
this.getVideos();
|
||||||
|
}
|
||||||
|
|
||||||
|
getVideos() {
|
||||||
|
VideoBackend.getVideos(this.props.account.name)
|
||||||
|
.then((res) => {
|
||||||
|
this.setState({
|
||||||
|
videos: res,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
newVideo() {
|
||||||
|
return {
|
||||||
|
owner: this.props.account.name,
|
||||||
|
name: `video_${this.state.videos.length}`,
|
||||||
|
createdTime: moment().format(),
|
||||||
|
displayName: `Video ${this.state.videos.length}`,
|
||||||
|
videoId: "",
|
||||||
|
coverUrl: "",
|
||||||
|
playAuth: "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addVideo() {
|
||||||
|
const newVideo = this.newVideo();
|
||||||
|
VideoBackend.addVideo(newVideo)
|
||||||
|
.then((res) => {
|
||||||
|
Setting.showMessage("success", `Video added successfully`);
|
||||||
|
this.setState({
|
||||||
|
videos: Setting.prependRow(this.state.videos, newVideo),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.catch(error => {
|
||||||
|
Setting.showMessage("error", `Video failed to add: ${error}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteVideo(i) {
|
||||||
|
VideoBackend.deleteVideo(this.state.videos[i])
|
||||||
|
.then((res) => {
|
||||||
|
Setting.showMessage("success", `Video deleted successfully`);
|
||||||
|
this.setState({
|
||||||
|
videos: Setting.deleteRow(this.state.videos, i),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.catch(error => {
|
||||||
|
Setting.showMessage("error", `Video failed to delete: ${error}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
renderTable(videos) {
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: i18next.t("general:Name"),
|
||||||
|
dataIndex: 'name',
|
||||||
|
key: 'name',
|
||||||
|
width: '140px',
|
||||||
|
sorter: (a, b) => a.name.localeCompare(b.name),
|
||||||
|
render: (text, record, index) => {
|
||||||
|
return (
|
||||||
|
<Link to={`/videos/${text}`}>
|
||||||
|
{text}
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18next.t("general:Display name"),
|
||||||
|
dataIndex: 'displayName',
|
||||||
|
key: 'displayName',
|
||||||
|
width: '200px',
|
||||||
|
sorter: (a, b) => a.displayName.localeCompare(b.displayName),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18next.t("video:Video ID"),
|
||||||
|
dataIndex: 'videoId',
|
||||||
|
key: 'videoId',
|
||||||
|
width: '250px',
|
||||||
|
sorter: (a, b) => a.videoId.localeCompare(b.videoId),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18next.t("video:Cover"),
|
||||||
|
dataIndex: 'coverUrl',
|
||||||
|
key: 'coverUrl',
|
||||||
|
width: '200px',
|
||||||
|
render: (text, record, index) => {
|
||||||
|
return (
|
||||||
|
<a target="_blank" rel="noreferrer" href={text}>
|
||||||
|
<img src={text} alt={text} width={150} />
|
||||||
|
</a>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: i18next.t("general:Action"),
|
||||||
|
dataIndex: 'action',
|
||||||
|
key: 'action',
|
||||||
|
width: '80px',
|
||||||
|
render: (text, record, index) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Button style={{marginTop: '10px', marginBottom: '10px', marginRight: '10px'}} type="primary" onClick={() => this.props.history.push(`/videos/${record.name}`)}>{i18next.t("general:Edit")}</Button>
|
||||||
|
<Popconfirm
|
||||||
|
title={`Sure to delete video: ${record.name} ?`}
|
||||||
|
onConfirm={() => this.deleteVideo(index)}
|
||||||
|
okText="OK"
|
||||||
|
cancelText="Cancel"
|
||||||
|
>
|
||||||
|
<Button style={{marginBottom: '10px'}} type="danger">{i18next.t("general:Delete")}</Button>
|
||||||
|
</Popconfirm>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Table columns={columns} dataSource={videos} rowKey="name" size="middle" bordered pagination={{pageSize: 100}}
|
||||||
|
title={() => (
|
||||||
|
<div>
|
||||||
|
{i18next.t("general:Videos")}
|
||||||
|
<Button type="primary" size="small" onClick={this.addVideo.bind(this)}>{i18next.t("general:Add")}</Button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
loading={videos === null}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Row style={{width: "100%"}}>
|
||||||
|
<Col span={1}>
|
||||||
|
</Col>
|
||||||
|
<Col span={22}>
|
||||||
|
{
|
||||||
|
this.renderTable(this.state.videos)
|
||||||
|
}
|
||||||
|
</Col>
|
||||||
|
<Col span={1}>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default VideoListPage;
|
|
@ -0,0 +1,56 @@
|
||||||
|
import * as Setting from "../Setting";
|
||||||
|
|
||||||
|
export function getGlobalVideos() {
|
||||||
|
return fetch(`${Setting.ServerUrl}/api/get-global-videos`, {
|
||||||
|
method: "GET",
|
||||||
|
credentials: "include"
|
||||||
|
}).then(res => res.json());
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getVideos(owner) {
|
||||||
|
return fetch(`${Setting.ServerUrl}/api/get-videos?owner=${owner}`, {
|
||||||
|
method: "GET",
|
||||||
|
credentials: "include"
|
||||||
|
}).then(res => res.json());
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getVideo(owner, name) {
|
||||||
|
return fetch(`${Setting.ServerUrl}/api/get-video?id=${owner}/${encodeURIComponent(name)}`, {
|
||||||
|
method: "GET",
|
||||||
|
credentials: "include"
|
||||||
|
}).then(res => res.json());
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getVideoGraph(owner, name, clusterNumber, distanceLimit) {
|
||||||
|
return fetch(`${Setting.ServerUrl}/api/get-video-graph?id=${owner}/${encodeURIComponent(name)}&clusterNumber=${clusterNumber}&distanceLimit=${distanceLimit}`, {
|
||||||
|
method: "GET",
|
||||||
|
credentials: "include"
|
||||||
|
}).then(res => res.json());
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateVideo(owner, name, video) {
|
||||||
|
let newVideo = Setting.deepCopy(video);
|
||||||
|
return fetch(`${Setting.ServerUrl}/api/update-video?id=${owner}/${encodeURIComponent(name)}`, {
|
||||||
|
method: 'POST',
|
||||||
|
credentials: 'include',
|
||||||
|
body: JSON.stringify(newVideo),
|
||||||
|
}).then(res => res.json());
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addVideo(video) {
|
||||||
|
let newVideo = Setting.deepCopy(video);
|
||||||
|
return fetch(`${Setting.ServerUrl}/api/add-video`, {
|
||||||
|
method: 'POST',
|
||||||
|
credentials: 'include',
|
||||||
|
body: JSON.stringify(newVideo),
|
||||||
|
}).then(res => res.json());
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteVideo(video) {
|
||||||
|
let newVideo = Setting.deepCopy(video);
|
||||||
|
return fetch(`${Setting.ServerUrl}/api/delete-video`, {
|
||||||
|
method: 'POST',
|
||||||
|
credentials: 'include',
|
||||||
|
body: JSON.stringify(newVideo),
|
||||||
|
}).then(res => res.json());
|
||||||
|
}
|
|
@ -22,6 +22,7 @@
|
||||||
"Save": "Save",
|
"Save": "Save",
|
||||||
"URL": "URL",
|
"URL": "URL",
|
||||||
"Vectorsets": "Vectorsets",
|
"Vectorsets": "Vectorsets",
|
||||||
|
"Videos": "Videos",
|
||||||
"Wordsets": "Wordsets"
|
"Wordsets": "Wordsets"
|
||||||
},
|
},
|
||||||
"vectorset": {
|
"vectorset": {
|
||||||
|
@ -32,6 +33,12 @@
|
||||||
"File name": "File name",
|
"File name": "File name",
|
||||||
"File size": "File size"
|
"File size": "File size"
|
||||||
},
|
},
|
||||||
|
"video": {
|
||||||
|
"Cover": "Cover",
|
||||||
|
"Edit Video": "Edit Video",
|
||||||
|
"Video": "Video",
|
||||||
|
"Video ID": "Video ID"
|
||||||
|
},
|
||||||
"wordset": {
|
"wordset": {
|
||||||
"All words": "All words",
|
"All words": "All words",
|
||||||
"Distance limit": "Distance limit",
|
"Distance limit": "Distance limit",
|
||||||
|
|
|
@ -21,8 +21,9 @@
|
||||||
"Result": "结果",
|
"Result": "结果",
|
||||||
"Save": "保存",
|
"Save": "保存",
|
||||||
"URL": "链接",
|
"URL": "链接",
|
||||||
"Vectorsets": "向量集",
|
"Vectorsets": "我的向量集",
|
||||||
"Wordsets": "词汇集"
|
"Videos": "我的视频",
|
||||||
|
"Wordsets": "我的词汇集"
|
||||||
},
|
},
|
||||||
"vectorset": {
|
"vectorset": {
|
||||||
"Count": "个数",
|
"Count": "个数",
|
||||||
|
@ -32,6 +33,12 @@
|
||||||
"File name": "文件名",
|
"File name": "文件名",
|
||||||
"File size": "文件大小"
|
"File size": "文件大小"
|
||||||
},
|
},
|
||||||
|
"video": {
|
||||||
|
"Cover": "封面图片",
|
||||||
|
"Edit Video": "编辑视频",
|
||||||
|
"Video": "视频",
|
||||||
|
"Video ID": "视频ID"
|
||||||
|
},
|
||||||
"wordset": {
|
"wordset": {
|
||||||
"All words": "所有词汇",
|
"All words": "所有词汇",
|
||||||
"Distance limit": "距离上限",
|
"Distance limit": "距离上限",
|
||||||
|
|
|
@ -2235,6 +2235,13 @@ ajv@^8.0.1:
|
||||||
require-from-string "^2.0.2"
|
require-from-string "^2.0.2"
|
||||||
uri-js "^4.2.2"
|
uri-js "^4.2.2"
|
||||||
|
|
||||||
|
aliplayer-react@^0.7.0:
|
||||||
|
version "0.7.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/aliplayer-react/-/aliplayer-react-0.7.0.tgz#5560e992e5d06f43a10065c7316e2f60552af82d"
|
||||||
|
integrity sha512-KjjRrtRy48DOUiR4ZdvfiLgD+u1yaT6ywZsGrynxePuv4dWsGt8u5Zsd3V3dxIgKeeep3RoxV7zofhcER40JKQ==
|
||||||
|
dependencies:
|
||||||
|
fetch-js-from-cdn "^0.2.0"
|
||||||
|
|
||||||
alphanum-sort@^1.0.0:
|
alphanum-sort@^1.0.0:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3"
|
resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3"
|
||||||
|
@ -5159,6 +5166,11 @@ fb-watchman@^2.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
bser "2.1.1"
|
bser "2.1.1"
|
||||||
|
|
||||||
|
fetch-js-from-cdn@^0.2.0:
|
||||||
|
version "0.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/fetch-js-from-cdn/-/fetch-js-from-cdn-0.2.0.tgz#0664242d20cae6f69be591bcf2b8dc7c606b7d14"
|
||||||
|
integrity sha512-u+adV8XpElTNrqPF6dcsMkmbP4FFW7W/8XPhU2HgfyXaiGA4NpFp3KXdF1/XMj++vjN65bA17RCxScK7Iw17Yw==
|
||||||
|
|
||||||
fflate@^0.3.8:
|
fflate@^0.3.8:
|
||||||
version "0.3.11"
|
version "0.3.11"
|
||||||
resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.3.11.tgz#2c440d7180fdeb819e64898d8858af327b042a5d"
|
resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.3.11.tgz#2c440d7180fdeb819e64898d8858af327b042a5d"
|
||||||
|
|
Loading…
Reference in New Issue