From 36372a2994ee5e4148ad2a01f54b18f5df3ccb0e Mon Sep 17 00:00:00 2001 From: Carlos G Date: Thu, 10 Nov 2022 17:53:31 +0100 Subject: [PATCH 1/3] New endpoint that enables an uploaded video to be downloaded --- routes/media.go | 58 ++++++++++++++++++++++++++++++++++++++++++++++++ routes/server.go | 17 ++++++++++---- 2 files changed, 71 insertions(+), 4 deletions(-) diff --git a/routes/media.go b/routes/media.go index fe59689f..d9710bfd 100644 --- a/routes/media.go +++ b/routes/media.go @@ -410,3 +410,61 @@ func (fes *APIServer) GetVideoStatus(ww http.ResponseWriter, req *http.Request) return } } + +type EnableVideoDownloadResponse struct { + Default map[string]interface {} +} + +// Cloudflare does NOT allow uploaded videos to be downloaded (just streamed) +// Cloudflare allows adding download support on a per-video basis +// EnableVideoDownload enables download support for an already uploaded video +// See Cloudflare documentation here: https://developers.cloudflare.com/stream/viewing-videos/download-videos/ +func (fes *APIServer) EnableVideoDownload(ww http.ResponseWriter, req *http.Request) { + if fes.Config.CloudflareStreamToken == "" || fes.Config.CloudflareAccountId == "" { + _AddBadRequestError(ww, fmt.Sprintf("EnableVideoDownload: This node is not configured to support video uploads")) + return + } + vars := mux.Vars(req) + videoId, videoIdExists := vars["videoId"] + if !videoIdExists { + _AddBadRequestError(ww, fmt.Sprintf("EnableVideoDownload: Missing videoId")) + return + } + url := fmt.Sprintf("https://api.cloudflare.com/client/v4/accounts/%v/stream/%v/downloads", fes.Config.CloudflareAccountId, videoId) + client := &http.Client{} + + // This is a POST request because: + // - If video downloading is not enabled for the video, the POST request will enable it and return the video URL + // - If video downloading is already enabled for the video, the POST request will just return the video URL + request, err := http.NewRequest("POST", url, nil) + request.Header.Add("Authorization", fmt.Sprintf("Bearer %v", fes.Config.CloudflareStreamToken)) + request.Header.Add("Content-Type", "application/json") + resp, err := client.Do(request) + if err != nil { + _AddBadRequestError(ww, fmt.Sprintf( + "EnableVideoDownload: error performing POST request: %v", err)) + return + } + if resp.StatusCode != 200 { + _AddBadRequestError(ww, fmt.Sprintf("EnableVideoDownload: POST request did not return 200 status code but instead a status code of %v", resp.StatusCode)) + return + } + cfVideoDetailsResponse := &CFVideoDetailsResponse{} + if err = json.NewDecoder(resp.Body).Decode(&cfVideoDetailsResponse); err != nil { + _AddBadRequestError(ww, fmt.Sprintf("EnableVideoDownload: failed decoding body: %v", err)) + return + } + if err = resp.Body.Close(); err != nil { + _AddBadRequestError(ww, fmt.Sprintf("EnableVideoDownload: failed closing body: %v", err)) + return + } + defaultVideo, _ := cfVideoDetailsResponse.Result["default"] + + res := &EnableVideoDownloadResponse{ + Default: defaultVideo.(map[string]interface{}), + } + if err = json.NewEncoder(ww).Encode(res); err != nil { + _AddInternalServerError(ww, fmt.Sprintf("EnableVideoDownload: Problem serializing object to JSON: %v", err)) + return + } +} \ No newline at end of file diff --git a/routes/server.go b/routes/server.go index a3df2646..dc219d70 100644 --- a/routes/server.go +++ b/routes/server.go @@ -130,10 +130,11 @@ const ( RoutePathGetAcceptedBidHistory = "/api/v0/accepted-bid-history" // media.go - RoutePathUploadImage = "/api/v0/upload-image" - RoutePathGetFullTikTokURL = "/api/v0/get-full-tiktok-url" - RoutePathUploadVideo = "/api/v0/upload-video" - RoutePathGetVideoStatus = "/api/v0/get-video-status" + RoutePathUploadImage = "/api/v0/upload-image" + RoutePathGetFullTikTokURL = "/api/v0/get-full-tiktok-url" + RoutePathUploadVideo = "/api/v0/upload-video" + RoutePathGetVideoStatus = "/api/v0/get-video-status" + RoutePathEnableVideoDownload = "/api/v0/enable-video-download" // message.go RoutePathSendMessageStateless = "/api/v0/send-message-stateless" @@ -1710,6 +1711,13 @@ func (fes *APIServer) NewRouter() *muxtrace.Router { fes.GetVideoStatus, PublicAccess, }, + { + "EnableVideoDownload", + []string{"POST", "OPTIONS"}, + RoutePathEnableVideoDownload, + fes.EnableVideoDownload, + PublicAccess, + }, // Paths for wyre { "GetWyreWalletOrderQuotation", @@ -1859,6 +1867,7 @@ func Logger(inner http.Handler, name string) http.Handler { var publicRoutes = map[string]interface{}{ RoutePathGetJumioStatusForPublicKey: nil, RoutePathUploadVideo: nil, + RoutePathEnableVideoDownload: nil, RoutePathGetReferralInfoForReferralHash: nil, RoutePathGetReferralInfoForUser: nil, RoutePathGetVerifiedUsernames: nil, From 5ec844a25f8bcbff7d23ba70cb5c5023202208a3 Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Wed, 25 Jan 2023 18:07:57 -0500 Subject: [PATCH 2/3] gofmt --- routes/server.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/routes/server.go b/routes/server.go index ccfea2ca..fbcebfe7 100644 --- a/routes/server.go +++ b/routes/server.go @@ -136,7 +136,7 @@ const ( RoutePathGetFullTikTokURL = "/api/v0/get-full-tiktok-url" RoutePathUploadVideo = "/api/v0/upload-video" RoutePathGetVideoStatus = "/api/v0/get-video-status" - RoutePathGetVideoDimensions = "/api/v0/get-video-dimensions" + RoutePathGetVideoDimensions = "/api/v0/get-video-dimensions" RoutePathEnableVideoDownload = "/api/v0/enable-video-download" // message.go @@ -1858,8 +1858,8 @@ func (fes *APIServer) NewRouter() *muxtrace.Router { []string{"POST", "OPTIONS"}, RoutePathEnableVideoDownload, fes.EnableVideoDownload, - }, - { + }, + { "GetVideoDimensions", []string{"GET"}, RoutePathGetVideoDimensions + "/{videoId:[0-9a-z]{25,35}}", From befd20de208c18d62fc27ebe1ceccf0b1a641f4e Mon Sep 17 00:00:00 2001 From: Lazy Nina <81658138+lazynina@users.noreply.github.com> Date: Wed, 25 Jan 2023 18:10:06 -0500 Subject: [PATCH 3/3] gofmt --- routes/media.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/routes/media.go b/routes/media.go index ddd89aad..dcaffeca 100644 --- a/routes/media.go +++ b/routes/media.go @@ -412,7 +412,7 @@ func (fes *APIServer) GetVideoStatus(ww http.ResponseWriter, req *http.Request) } type EnableVideoDownloadResponse struct { - Default map[string]interface {} + Default map[string]interface{} } // Cloudflare does NOT allow uploaded videos to be downloaded (just streamed) @@ -430,7 +430,7 @@ func (fes *APIServer) EnableVideoDownload(ww http.ResponseWriter, req *http.Requ _AddBadRequestError(ww, fmt.Sprintf("EnableVideoDownload: Missing videoId")) return } - url := fmt.Sprintf("https://api.cloudflare.com/client/v4/accounts/%v/stream/%v/downloads", fes.Config.CloudflareAccountId, videoId) + url := fmt.Sprintf("https://api.cloudflare.com/client/v4/accounts/%v/stream/%v/downloads", fes.Config.CloudflareAccountId, videoId) client := &http.Client{} // This is a POST request because: