This repository has been archived by the owner on Jun 16, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
videos.go
222 lines (181 loc) · 5.38 KB
/
videos.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
package routes
import (
"context"
"fmt"
"log"
"path/filepath"
"github.com/bken-io/api/src/db"
"github.com/bken-io/api/src/models"
"github.com/bken-io/api/src/s3"
"github.com/bken-io/api/src/tidal"
jwt "github.com/form3tech-oss/jwt-go"
"github.com/gofiber/fiber/v2"
"github.com/minio/minio-go/v7"
)
// CreateVideoInput is used for creating videos
type CreateVideoInput struct {
ID string `json:"id"`
Title string `json:"title"`
Duration float32 `json:"duration"`
}
// GetVideo returns a video
func GetVideo(c *fiber.Ctx) error {
id := c.Params("id")
db := db.DBConn
var video models.Video
result := db.Where("id = ?", id).Find(&video)
if result.Error != nil {
return c.SendStatus(500)
}
if video.ID == "" {
return c.SendStatus(404)
}
// This logic can be used once private videos are a thing
// user := c.Locals("user").(*jwt.Token)
// claims := user.Claims.(jwt.MapClaims)
// userID := claims["id"].(string)
// if video.Visibility != "public" {
// if video.UserID != userID {
// return c.SendStatus(403)
// }
// }
video.URL = fmt.Sprintf("https://cdn.bken.io/v/%s/hls/master.m3u8", video.ID)
// video.URL = fmt.Sprintf("https://s3.us-east-2.wasabisys.com/cdn.bken.io/v/%s/hls/master.m3u8", video.ID)
return c.JSON(video)
}
// GetVideos returns all videos
func GetVideos(c *fiber.Ctx) error {
userID := c.Query("userId")
db := db.DBConn
videos := []models.Video{}
if userID != "" {
visibility := c.Query("visibility")
if visibility == "all" {
fmt.Println("user is querying for all videos", userID)
db.
Where("user_id = ?", userID).
Order("created_at desc").
Find(&videos)
} else {
fmt.Println("querying for public videos", userID)
db.
Where("visibility = 'public' and user_id = ?", userID).
Order("created_at desc").
Find(&videos)
}
} else {
fmt.Println("returning all videos query")
db.Where("visibility = 'public'").Order("created_at desc").Find(&videos)
}
return c.JSON(videos)
}
// CreateVideo creates a new video
func CreateVideo(c *fiber.Ctx) error {
db := db.DBConn
video := new(models.Video)
input := new(CreateVideoInput)
if err := c.BodyParser(input); err != nil {
return c.Status(400).SendString("video input failed unmarshalling")
}
extension := filepath.Ext(input.Title)
filenameWithoutExtension := input.Title[0 : len(input.Title)-len(extension)]
if extension == "" {
return c.Status(400).SendString("failed to infer file extension")
}
video.ID = input.ID
video.Duration = input.Duration
user := c.Locals("user").(*jwt.Token)
claims := user.Claims.(jwt.MapClaims)
userID := claims["id"].(string)
video.UserID = userID
video.Title = filenameWithoutExtension
video.Thumbnail = fmt.Sprintf("https://cdn.bken.io/i/%s/t/thumb.webp", video.ID)
res := db.Create(&video)
if res.Error != nil {
return c.SendStatus(500)
}
S3SourceIn := fmt.Sprintf("s3://cdn.bken.io/v/%s/source%s", video.ID, extension)
S3ThumbnailOut := fmt.Sprintf("s3://cdn.bken.io/i/%s/t/thumb.webp", video.ID)
tidal.DispatchThumbnailJob("thumbnail", S3SourceIn, S3ThumbnailOut)
tidal.DispatchIngestJob("ingest", S3SourceIn, video.ID)
return c.JSON(video)
}
// PatchVideo creates a new video
func PatchVideo(c *fiber.Ctx) error {
id := c.Params("id")
user := c.Locals("user").(*jwt.Token)
claims := user.Claims.(jwt.MapClaims)
userID := claims["id"].(string)
if userID == "" {
c.SendStatus(403)
}
db := db.DBConn
inputVideo := new(models.Video)
c.BodyParser(inputVideo)
video := new(models.Video)
db.Where("id = ? and user_id = ?", id, userID).Find(&video)
if inputVideo.Title != "" {
video.Title = inputVideo.Title
}
if inputVideo.Visibility != "" {
video.Visibility = inputVideo.Visibility
}
db.Save(&video)
return c.SendString("Video successfully updated")
}
// HardDeleteVideo fully delete the video and all cdn resources
// Tidal resources will be retained
func HardDeleteVideo(c *fiber.Ctx) error {
id := c.Params("id")
db := db.DBConn
user := c.Locals("user").(*jwt.Token)
claims := user.Claims.(jwt.MapClaims)
userID := claims["id"].(string)
var video models.Video
db.Where("id = ?", id).Find(&video)
if video.Title == "" {
return c.SendStatus(404)
}
if video.UserID != userID {
return c.SendStatus(403)
}
wasabiBucket := "cdn.bken.io"
thumbnailsPrefix := fmt.Sprintf("i/%s/", id)
videosPrefix := fmt.Sprintf("v/%s/", id)
deleteObjects("wasabi", wasabiBucket, thumbnailsPrefix)
deleteObjects("wasabi", wasabiBucket, videosPrefix)
db.Unscoped().Delete(&video)
return c.SendString("video successfully deleted")
}
func deleteObjects(client string, bucket string, prefix string) {
var s3Client *minio.Client
if client == "wasabi" {
s3Client = s3.Wasabi()
} else if client == "doco" {
s3Client = s3.Doco()
} else {
panic("invalid s3 client")
}
objectsCh := make(chan minio.ObjectInfo)
opts := minio.ListObjectsOptions{
Recursive: true,
Prefix: prefix,
}
go func() {
defer close(objectsCh)
// List all objects from a bucket-name with a matching prefix.
for object := range s3Client.ListObjects(context.Background(), bucket, opts) {
if object.Err != nil {
log.Fatalln(object.Err)
}
fmt.Println("object", object.Key)
objectsCh <- object
}
}()
opts2 := minio.RemoveObjectsOptions{
GovernanceBypass: false,
}
for rErr := range s3Client.RemoveObjects(context.Background(), bucket, objectsCh, opts2) {
fmt.Println("Error detected during deletion: ", rErr)
}
}