@@ -2,92 +2,88 @@ import { NextRequest, NextResponse } from "next/server";
22
33export async function POST ( request : NextRequest ) {
44 const form = await request . formData ( ) ;
5- // https://docs.livepeer.org/reference/api#upload-an-asset
6- const requestedUrlReq = await fetch (
7- "https://livepeer.studio/api/asset/request-upload" ,
5+
6+ const controller = new AbortController ( ) ;
7+ const signal = controller . signal ;
8+
9+ // Cancel upload if it takes longer than 15s
10+ setTimeout ( ( ) => {
11+ controller . abort ( ) ;
12+ } , 15_000 ) ;
13+
14+ const uploadRes : Response | null = await fetch (
15+ "https://ipfs.infura.io:5001/api/v0/add" ,
816 {
917 method : "POST" ,
18+ body : form ,
1019 headers : {
11- Authorization : `Bearer ${ process . env . LIVEPEER_API_SECRET } ` ,
12- "Content-Type" : "application/json" ,
20+ Authorization :
21+ "Basic " +
22+ Buffer . from (
23+ process . env . INFURA_API_KEY + ":" + process . env . INFURA_API_SECRET
24+ ) . toString ( "base64" ) ,
1325 } ,
14- body : JSON . stringify ( {
15- name : "video.mp4" ,
16- staticMp4 : true ,
17- playbackPolicy : {
18- type : "public" ,
19- } ,
20- storage : {
21- ipfs : true ,
22- } ,
23- } ) ,
26+ signal,
2427 }
2528 ) ;
2629
27- const requestedUrl = await requestedUrlReq . json ( ) ;
30+ const { Hash : hash } = await uploadRes . json ( ) ;
2831
29- const url = requestedUrl . url ;
32+ const responseData = { url : `ipfs:// ${ hash } ` } ;
3033
31- const videoUpload = await fetch ( url , {
32- method : "PUT" ,
33- headers : {
34- Authorization : `Bearer ${ process . env . LIVEPEER_API_SECRET } ` ,
35- "Content-Type" : "video/mp4" ,
36- } ,
37- body : form . get ( "file" ) ,
38- } ) ;
34+ return NextResponse . json ( { data : responseData } ) ;
35+ }
3936
40- if ( videoUpload . status >= 400 ) {
41- return NextResponse . json (
42- { message : "Something went wrong" } ,
43- {
44- status : videoUpload . status ,
45- }
46- ) ;
47- }
37+ // needed for preflight requests to succeed
38+ export const OPTIONS = async ( request : NextRequest ) => {
39+ return NextResponse . json ( { } ) ;
40+ } ;
4841
49- // simpler than webhooks, but constrained by serverless function timeout time
50- let isUploadSuccess = false ;
51- let maxTries = 10 ;
52- let tries = 0 ;
53- while ( ! isUploadSuccess && tries < maxTries ) {
54- const details = await fetch (
55- `https://livepeer.studio/api/asset/${ requestedUrl . asset . id } ` ,
56- {
57- method : "GET" ,
58- headers : {
59- Authorization : `Bearer ${ process . env . LIVEPEER_API_SECRET } ` ,
60- "Content-Type" : "application/json" ,
61- } ,
62- }
63- ) ;
64- const detailsJson = await details . json ( ) ;
42+ export const GET = async ( request : NextRequest ) => {
43+ let url = request . nextUrl . searchParams . get ( "url" ) ;
6544
66- if ( detailsJson . status !== "waiting" ) {
67- break ;
68- }
45+ // Exchange for livepeer url
46+ const cid = url . replace ( "ipfs://" , "" ) ;
47+ const gatewayUrl = ` ${ process . env . IPFS_DEFAULT_GATEWAY } / ${ cid } ` ;
6948
70- // wait 1s
71- await new Promise ( ( resolve ) => setTimeout ( ( ) => resolve ( null ) , 1000 ) ) ;
72- tries = tries + 1 ;
73- }
49+ // Get HEAD to get content type
50+ const response = await fetch ( gatewayUrl , { method : "HEAD" } ) ;
51+ const contentType = response . headers . get ( "content-type" ) ;
7452
75- if ( tries === maxTries ) {
76- return NextResponse . json (
77- {
78- message : "Took too long to upload. Try a smaller file" ,
53+ // TODO: Cache this
54+ const uploadRes = await fetch (
55+ "https://livepeer.studio/api/asset/upload/url" ,
56+ {
57+ method : "POST" ,
58+ headers : {
59+ Authorization : `Bearer ${ process . env . LIVEPEER_API_SECRET } ` ,
60+ "Content-Type" : "application/json" ,
7961 } ,
80- { status : 400 }
81- ) ;
62+ body : JSON . stringify ( {
63+ name : "filename.mp4" ,
64+ staticMp4 : contentType === "video/mp4" ? true : false ,
65+ playbackPolicy : {
66+ type : "public" ,
67+ } ,
68+ url : gatewayUrl ,
69+ } ) ,
70+ }
71+ ) ;
72+
73+ if ( ! uploadRes . ok ) {
74+ // console.error(uploadRes.status, await uploadRes.text());
75+ return NextResponse . error ( ) ;
8276 }
8377
84- // hack, wait at least 3s to make sure url doesn't error
85- await new Promise ( ( resolve ) => setTimeout ( ( ) => resolve ( null ) , 3000 ) ) ;
78+ const { asset } = await uploadRes . json ( ) ;
8679
87- return NextResponse . json ( { data : requestedUrl } ) ;
88- }
80+ const playbackUrl = `https://lp-playback.com/hls/${ asset . playbackId } /index.m3u8` ;
8981
90- // needed for preflight requests to succeed
91- export const OPTIONS = async ( request : NextRequest ) => {
92- return NextResponse . json ( { } ) ;
82+ return NextResponse . json ( {
83+ url : playbackUrl ,
84+ fallbackUrl : gatewayUrl ,
85+ mimeType : contentType ,
86+ } ) ;
9387} ;
88+
89+ export const runtime = "edge" ;
0 commit comments