@seshuk/payload-storage-bunny
Version:
Payload storage adapter for Bunny.net
132 lines (131 loc) • 5.92 kB
JavaScript
export const streamStaticHandler = async (req, stream, { collection, docId, videoId, videoMeta })=>{
const fallbackEnabled = stream.mp4Fallback?.enabled || !!stream.mp4FallbackQuality;
if (!fallbackEnabled) {
return new Response('MP4 fallback not configured.', {
status: 400
});
}
let fallbackQuality = undefined;
let availableResolutions = [];
let metaNeedsUpdate = false;
if (videoMeta && typeof videoMeta === 'object' && 'highestMp4Resolution' in videoMeta && videoMeta.highestMp4Resolution) {
const savedResolutionUrl = `https://${stream.hostname}/${videoId}/play_${videoMeta.highestMp4Resolution}.mp4`;
try {
const headResponse = await fetch(savedResolutionUrl, {
headers: {
'Accept': 'video/mp4'
},
method: 'HEAD'
});
if (headResponse.ok) {
fallbackQuality = videoMeta.highestMp4Resolution;
if (videoMeta.availableMp4Resolutions && videoMeta.availableMp4Resolutions.length > 0) {
availableResolutions = videoMeta.availableMp4Resolutions;
}
} else {
metaNeedsUpdate = true;
}
} catch (error) {
req.payload.logger.error(`Error checking saved resolution: ${error instanceof Error ? error.message : String(error)}`);
metaNeedsUpdate = true;
}
} else {
metaNeedsUpdate = true;
}
if (!fallbackQuality) {
try {
const resolutionsUrl = `https://video.bunnycdn.com/library/${stream.libraryId}/videos/${videoId}/resolutions`;
const resolutionsResponse = await fetch(resolutionsUrl, {
headers: {
'Accept': 'application/json',
'AccessKey': stream.apiKey || ''
}
});
if (resolutionsResponse.ok) {
const resolutionsData = await resolutionsResponse.json();
if (resolutionsData.success && resolutionsData.data.mp4Resolutions.length > 0) {
availableResolutions = resolutionsData.data.mp4Resolutions.map((r)=>r.resolution);
if (availableResolutions.length > 0) {
const sortedResolutions = [
...availableResolutions
].sort((a, b)=>parseInt(b.replace('p', '')) - parseInt(a.replace('p', '')));
for (const resolution of sortedResolutions){
const checkUrl = `https://${stream.hostname}/${videoId}/play_${resolution}.mp4`;
try {
const headResponse = await fetch(checkUrl, {
headers: {
'Accept': 'video/mp4'
},
method: 'HEAD'
});
if (headResponse.ok) {
fallbackQuality = resolution;
break;
}
} catch (error) {
req.payload.logger.error(`Error checking resolution ${resolution}: ${error instanceof Error ? error.message : String(error)}`);
}
}
if (fallbackQuality) {
metaNeedsUpdate = !videoMeta || !videoMeta.highestMp4Resolution || videoMeta.highestMp4Resolution !== fallbackQuality;
}
}
} else {
req.payload.logger.error('No MP4 resolutions available from Bunny API');
}
} else {
req.payload.logger.error(`Failed to fetch available resolutions: ${resolutionsResponse.status}`);
}
} catch (error) {
req.payload.logger.error(`Error fetching available resolutions: ${error instanceof Error ? error.message : String(error)}`);
}
}
if (!fallbackQuality) {
return new Response('Could not determine a valid resolution for the video', {
status: 404
});
}
if (metaNeedsUpdate && fallbackQuality && docId && collection) {
try {
await req.payload.update({
id: docId,
collection,
data: {
bunnyVideoMeta: {
availableMp4Resolutions: availableResolutions.length > 0 ? availableResolutions : undefined,
highestMp4Resolution: fallbackQuality
}
}
});
} catch (error) {
req.payload.logger.error(`Failed to update bunnyVideoMeta: ${error instanceof Error ? error.message : String(error)}`);
}
}
const rangeHeader = req.headers.get('range');
const requestHeaders = new Headers();
if (rangeHeader) {
requestHeaders.set('Range', rangeHeader);
}
const mp4Url = `https://${stream.hostname}/${videoId}/play_${fallbackQuality}.mp4`;
const response = await fetch(mp4Url, {
headers: requestHeaders
});
if (!response.ok && response.status !== 206) {
return new Response(null, {
status: 404,
statusText: 'Not Found'
});
}
const responseHeaders = new Headers();
response.headers.forEach((value, key)=>{
responseHeaders.set(key, value);
});
if (!responseHeaders.has('content-type')) {
responseHeaders.set('content-type', 'video/mp4');
}
return new Response(response.body, {
headers: responseHeaders,
status: response.status
});
};
//# sourceMappingURL=staticHandlerStream.js.map