Skip to content

Commit d55fe7d

Browse files
carlosgiolazynina
andauthored
New endpoint for enabling video download of Cloudfare videos (#411)
* New endpoint that enables an uploaded video to be downloaded * gofmt * gofmt Co-authored-by: Carlos G <[email protected]> Co-authored-by: Lazy Nina <[email protected]>
1 parent 10f7d45 commit d55fe7d

File tree

2 files changed

+71
-5
lines changed

2 files changed

+71
-5
lines changed

routes/media.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,64 @@ func (fes *APIServer) GetVideoStatus(ww http.ResponseWriter, req *http.Request)
411411
}
412412
}
413413

414+
type EnableVideoDownloadResponse struct {
415+
Default map[string]interface{}
416+
}
417+
418+
// Cloudflare does NOT allow uploaded videos to be downloaded (just streamed)
419+
// Cloudflare allows adding download support on a per-video basis
420+
// EnableVideoDownload enables download support for an already uploaded video
421+
// See Cloudflare documentation here: https://developers.cloudflare.com/stream/viewing-videos/download-videos/
422+
func (fes *APIServer) EnableVideoDownload(ww http.ResponseWriter, req *http.Request) {
423+
if fes.Config.CloudflareStreamToken == "" || fes.Config.CloudflareAccountId == "" {
424+
_AddBadRequestError(ww, fmt.Sprintf("EnableVideoDownload: This node is not configured to support video uploads"))
425+
return
426+
}
427+
vars := mux.Vars(req)
428+
videoId, videoIdExists := vars["videoId"]
429+
if !videoIdExists {
430+
_AddBadRequestError(ww, fmt.Sprintf("EnableVideoDownload: Missing videoId"))
431+
return
432+
}
433+
url := fmt.Sprintf("https://api.cloudflare.com/client/v4/accounts/%v/stream/%v/downloads", fes.Config.CloudflareAccountId, videoId)
434+
client := &http.Client{}
435+
436+
// This is a POST request because:
437+
// - If video downloading is not enabled for the video, the POST request will enable it and return the video URL
438+
// - If video downloading is already enabled for the video, the POST request will just return the video URL
439+
request, err := http.NewRequest("POST", url, nil)
440+
request.Header.Add("Authorization", fmt.Sprintf("Bearer %v", fes.Config.CloudflareStreamToken))
441+
request.Header.Add("Content-Type", "application/json")
442+
resp, err := client.Do(request)
443+
if err != nil {
444+
_AddBadRequestError(ww, fmt.Sprintf(
445+
"EnableVideoDownload: error performing POST request: %v", err))
446+
return
447+
}
448+
if resp.StatusCode != 200 {
449+
_AddBadRequestError(ww, fmt.Sprintf("EnableVideoDownload: POST request did not return 200 status code but instead a status code of %v", resp.StatusCode))
450+
return
451+
}
452+
cfVideoDetailsResponse := &CFVideoDetailsResponse{}
453+
if err = json.NewDecoder(resp.Body).Decode(&cfVideoDetailsResponse); err != nil {
454+
_AddBadRequestError(ww, fmt.Sprintf("EnableVideoDownload: failed decoding body: %v", err))
455+
return
456+
}
457+
if err = resp.Body.Close(); err != nil {
458+
_AddBadRequestError(ww, fmt.Sprintf("EnableVideoDownload: failed closing body: %v", err))
459+
return
460+
}
461+
defaultVideo, _ := cfVideoDetailsResponse.Result["default"]
462+
463+
res := &EnableVideoDownloadResponse{
464+
Default: defaultVideo.(map[string]interface{}),
465+
}
466+
if err = json.NewEncoder(ww).Encode(res); err != nil {
467+
_AddInternalServerError(ww, fmt.Sprintf("EnableVideoDownload: Problem serializing object to JSON: %v", err))
468+
return
469+
}
470+
}
471+
414472
type CFVideoOEmbedResponse struct {
415473
Height uint64 `json:"height"`
416474
Width uint64 `json:"width"`

routes/server.go

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -132,11 +132,12 @@ const (
132132
RoutePathGetAcceptedBidHistory = "/api/v0/accepted-bid-history"
133133

134134
// media.go
135-
RoutePathUploadImage = "/api/v0/upload-image"
136-
RoutePathGetFullTikTokURL = "/api/v0/get-full-tiktok-url"
137-
RoutePathUploadVideo = "/api/v0/upload-video"
138-
RoutePathGetVideoStatus = "/api/v0/get-video-status"
139-
RoutePathGetVideoDimensions = "/api/v0/get-video-dimensions"
135+
RoutePathUploadImage = "/api/v0/upload-image"
136+
RoutePathGetFullTikTokURL = "/api/v0/get-full-tiktok-url"
137+
RoutePathUploadVideo = "/api/v0/upload-video"
138+
RoutePathGetVideoStatus = "/api/v0/get-video-status"
139+
RoutePathGetVideoDimensions = "/api/v0/get-video-dimensions"
140+
RoutePathEnableVideoDownload = "/api/v0/enable-video-download"
140141

141142
// message.go
142143
RoutePathSendMessageStateless = "/api/v0/send-message-stateless"
@@ -1852,6 +1853,12 @@ func (fes *APIServer) NewRouter() *muxtrace.Router {
18521853
fes.GetVideoStatus,
18531854
PublicAccess,
18541855
},
1856+
{
1857+
"EnableVideoDownload",
1858+
[]string{"POST", "OPTIONS"},
1859+
RoutePathEnableVideoDownload,
1860+
fes.EnableVideoDownload,
1861+
},
18551862
{
18561863
"GetVideoDimensions",
18571864
[]string{"GET"},
@@ -2129,6 +2136,7 @@ func Logger(inner http.Handler, name string) http.Handler {
21292136
var publicRoutes = map[string]interface{}{
21302137
RoutePathGetJumioStatusForPublicKey: nil,
21312138
RoutePathUploadVideo: nil,
2139+
RoutePathEnableVideoDownload: nil,
21322140
RoutePathGetReferralInfoForReferralHash: nil,
21332141
RoutePathGetReferralInfoForUser: nil,
21342142
RoutePathGetVerifiedUsernames: nil,

0 commit comments

Comments
 (0)