11import { NextRequest , NextResponse } from 'next/server' ;
2- import { S3Client , ListObjectsV2Command } from '@aws-sdk/client-s3' ;
2+ import { S3Client , ListObjectsV2Command , GetObjectCommand , HeadBucketCommand } from '@aws-sdk/client-s3' ;
33
44import { PlatformCredentials } from '../../components/Utils/types' ;
55import processVideosForPlatform from '../../components/Utils/fastpix' ;
6+ import { getSignedUrl } from '@aws-sdk/s3-request-presigner' ;
7+ import https from 'https' ;
8+
9+ export async function getBucketRegion ( bucketUrl : string ) {
10+ return new Promise ( ( resolve , reject ) => {
11+ const req = https . request ( bucketUrl , { method : 'HEAD' } , ( res ) => {
12+ const region = res . headers [ 'x-amz-bucket-region' ] ;
13+ if ( region ) {
14+ resolve ( region ) ;
15+ } else {
16+ reject ( 'Bucket region not found in headers' ) ;
17+ }
18+ } ) ;
19+
20+ req . on ( 'error' , reject ) ;
21+ req . end ( ) ;
22+ } ) ;
23+ }
24+
25+ const isPublicObject = ( bucket : string , key : string ) : Promise < boolean > => {
26+ const url = `https://${ bucket } .s3.amazonaws.com/${ encodeURIComponent ( key ) } ` ;
27+
28+ return new Promise ( ( resolve ) => {
29+ https . request ( url , { method : 'HEAD' } , ( res ) => {
30+ const status = res . statusCode || 0 ;
31+ if ( status === 200 ) {
32+ resolve ( true ) ; // public
33+ } else if ( status === 403 || status === 401 ) {
34+ resolve ( false ) ; // private
35+ } else {
36+ resolve ( false ) ; // treat unknown as private
37+ }
38+ } ) . on ( 'error' , ( err ) => {
39+ console . log ( "HEAD error:" , err . message ) ;
40+ resolve ( false ) ;
41+ } ) . end ( ) ;
42+ } ) ;
43+ } ;
644
745const fetchS3Media = async ( sourcePlatform : PlatformCredentials ) => {
846 const { publicKey, secretKey, additionalMetadata } = sourcePlatform . credentials ;
947 const { bucket, region } = additionalMetadata ;
48+ const bucketUrl = `https://${ bucket } .s3.amazonaws.com`
49+ const s3Region = await getBucketRegion ( bucketUrl ) ;
1050
1151 const s3 = new S3Client ( {
1252 credentials : {
1353 accessKeyId : publicKey ,
1454 secretAccessKey : secretKey ,
1555 } ,
16- region : region ,
56+ region : s3Region ,
1757 } ) ;
1858
1959 let videos : Array < any > = [ ] ;
2060 let continuationToken : string | undefined = undefined ;
2161
2262 try {
2363 do {
24-
25- // @ts -ignore
26- const command = new ListObjectsV2Command ( {
64+ const command = new ListObjectsV2Command ( {
2765 Bucket : bucket . trim ( ) ,
2866 ContinuationToken : continuationToken ,
2967 } ) ;
30-
31- // @ts -ignore
32- const response = await s3 . send ( command ) ;
68+
69+ const response = await s3 . send ( command ) ;
3370 const filteredVideos = response . Contents ?. filter ( file => file . Key ?. endsWith ( '.mp4' ) ) || [ ] ;
3471 videos = [ ...videos , ...filteredVideos ] ;
35-
36- // @ts -ignore
37- continuationToken = response ?. NextContinuationToken ?? "" ;
72+ continuationToken = response . NextContinuationToken ?? "" ;
3873 } while ( continuationToken ) ;
3974
75+ const signedUrls = await Promise . all ( videos . map ( async ( video ) => {
76+ const key = video . Key ! ;
77+ const isPublic = await isPublicObject ( bucket , key ) ;
78+
79+ let url : string ;
80+ if ( isPublic ) {
81+ url = `https://${ bucket } .s3.amazonaws.com/${ encodeURIComponent ( key ) } ` ;
82+ } else {
83+ const getCommand = new GetObjectCommand ( { Bucket : bucket , Key : key } ) ;
84+ url = await getSignedUrl ( s3 , getCommand , { expiresIn : 86400 } ) ;
85+ }
86+
87+ return {
88+ videoId : key ,
89+ mp4_url : url ,
90+ ETag : video . ETag ?? null
91+ } ;
92+ } ) ) ;
93+
4094 return {
4195 success : true ,
42- videos : videos . map ( video => ( {
43- videoId : video . Key ?? null ,
44- mp4_url : `https://${ bucket } .s3.amazonaws.com/${ video . Key } ` ,
45- ETag : video . ETag ?? null
46- } ) ) ,
96+ videos : signedUrls
4797 } ;
48- } catch ( error ) {
49-
98+
99+ } catch ( error : any ) {
100+
50101 // @ts -ignore
51102 return { success : false , status : 404 , message : error ?. message } ;
52103 }
@@ -65,28 +116,29 @@ export async function POST(request: NextRequest) {
65116 { status : 404 }
66117 ) ;
67118 }
68-
69- const videos = amazonS3Response . videos ?? [ ] ; // Vidoes from amazon s3
119+
120+ const videos = amazonS3Response . videos ?? [ ] ; // Videos from Amazon S3
121+
70122 const result = await processVideosForPlatform ( destinationPlatform , videos , "amazon-s3" ) ; // process videos in fastpix
71123
72124 const createdMedia = result . createdMedia ; // created vidoes in fastpix
73125 const failedMedia = result . failedMedia ; // failed vidoes in fastpix
74126
75127 if ( createdMedia . length > 0 || failedMedia . length > 0 ) { // Either video is created or failed to create we send the response
76-
128+
77129 return NextResponse . json (
78130 { success : true , createdMedia, failedMedia } ,
79131 { status : 200 }
80132 ) ;
81133 } else { // If there are no vidoes in amazon s3 then we send 404
82134 const errorMsg = videos . length === 0 ? "No Vidoes found in AmazonS3 Video" : "Something went wrong" ;
83-
135+
84136 return NextResponse . json (
85- { message : errorMsg } ,
137+ { message : errorMsg } ,
86138 { status : videos . length === 0 ? 404 : 400 }
87139 ) ;
88140 }
89-
141+
90142 } catch ( error : any ) {
91143
92144 return NextResponse . json (
0 commit comments