feat(bunny-cdn): refactor CDN hostname resolution and update asset URLs for improved flexibility

This commit is contained in:
Yusuf İpek
2026-02-26 11:53:03 +03:00
parent 3522c3da30
commit 4ea6099508
15 changed files with 192 additions and 98 deletions
+5 -1
View File
@@ -20,6 +20,7 @@ import { BunnyPreviewPlayer, type BunnyPreviewPlayerHandle } from '@/components/
import { AssetListSection } from '@/components/video-page/asset-list-section';
import type { VideoAsset } from '@/components/video-page/types';
import { extractPastedImageFile, validateImageFile } from '@/components/video-page/image-upload-utils';
import { resolvePublicBunnyCdnHostname } from '@/lib/bunny-cdn';
interface AssetsPaneProps {
videoId: string;
@@ -82,6 +83,7 @@ export const AssetsPane = memo(function AssetsPane({
const [previewImage, setPreviewImage] = useState<string | null>(null);
const [previewImageTitle, setPreviewImageTitle] = useState<string | null>(null);
const [selectedAsset, setSelectedAsset] = useState<VideoAsset | null>(null);
const bunnyCdnHostname = useMemo(() => resolvePublicBunnyCdnHostname(), []);
const [focusedAssetId, setFocusedAssetId] = useState<string | null>(null);
const bunnyPreviewPlayerRef = useRef<BunnyPreviewPlayerHandle | null>(null);
const youtubeIframeRef = useRef<HTMLIFrameElement | null>(null);
@@ -369,7 +371,9 @@ export const AssetsPane = memo(function AssetsPane({
});
const sourceUrl = `https://iframe.mediadelivery.net/embed/${initData.libraryId}/${initData.videoId}`;
const thumbnailUrl = `https://vz-965f4f4a-fc1.b-cdn.net/${initData.videoId}/thumbnail.jpg`;
const thumbnailUrl = bunnyCdnHostname
? `https://${bunnyCdnHostname}/${initData.videoId}/thumbnail.jpg`
: undefined;
const createdAsset = await createAsset({
provider: 'BUNNY',
sourceUrl,
+2 -12
View File
@@ -11,6 +11,7 @@ import {
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { resolvePublicBunnyCdnHostname } from '@/lib/bunny-cdn';
import { cn } from '@/lib/utils';
import type { BunnyPlaybackState, BunnyQualityOption } from '@/components/video-page/types';
@@ -28,17 +29,6 @@ export interface BunnyPreviewPlayerHandle {
const SPEED_OPTIONS = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];
function resolveBunnyCdnHostname(): string | null {
const configured = process.env.NEXT_PUBLIC_BUNNY_CDN_URL;
if (!configured) return null;
try {
const parsed = new URL(configured);
return parsed.hostname || null;
} catch {
return configured.replace(/^https?:\/\//, '').replace(/\/+$/, '') || null;
}
}
function formatTime(value: number): string {
if (!Number.isFinite(value) || value < 0) return '0:00';
const total = Math.floor(value);
@@ -78,7 +68,7 @@ export const BunnyPreviewPlayer = forwardRef<BunnyPreviewPlayerHandle, BunnyPrev
const [selectedQualityLevel, setSelectedQualityLevel] = useState<number>(-1);
const [bunnySourcePreference, setBunnySourcePreference] = useState<'auto' | 'original'>('auto');
const [bunnyPlaybackState, setBunnyPlaybackState] = useState<BunnyPlaybackState>('none');
const bunnyCdnHostname = useMemo(() => resolveBunnyCdnHostname(), []);
const bunnyCdnHostname = useMemo(() => resolvePublicBunnyCdnHostname(), []);
const playlistUrl = useMemo(() => {
if (!providerVideoId || !bunnyCdnHostname) return null;
@@ -3,8 +3,7 @@
import { useCallback, useState } from 'react';
import { toast } from 'sonner';
import type { BunnyDownloadPreference, Comment, DownloadTarget, Version, VideoData } from '@/components/video-page/types';
const BUNNY_PULL_ZONE_HOSTNAME = 'vz-965f4f4a-fc1.b-cdn.net';
import { resolvePublicBunnyCdnHostname } from '@/lib/bunny-cdn';
function sanitizeDownloadFileName(value: string): string {
return value
@@ -14,17 +13,9 @@ function sanitizeDownloadFileName(value: string): string {
}
function getAllowedHosts() {
const bunnyCdnHostname = resolvePublicBunnyCdnHostname();
return [
BUNNY_PULL_ZONE_HOSTNAME,
...(process.env.NEXT_PUBLIC_BUNNY_CDN_URL
? (() => {
try {
return [new URL(process.env.NEXT_PUBLIC_BUNNY_CDN_URL).hostname];
} catch {
return [process.env.NEXT_PUBLIC_BUNNY_CDN_URL.replace(/^https?:\/\//, '').replace(/\/+$/, '')];
}
})()
: []),
...(bunnyCdnHostname ? [bunnyCdnHostname] : []),
...(process.env.NEXT_PUBLIC_DIRECT_DOWNLOAD_ALLOWED_HOSTS ?? '').split(','),
]
.map((host) => host.trim().toLowerCase())
@@ -5,6 +5,7 @@ import { toast } from 'sonner';
import * as tus from 'tus-js-client';
import { parseVideoUrl, getThumbnailUrl, fetchVideoMetadata, type VideoSource } from '@/lib/video-providers';
import type { VersionActionsConfig, VideoData } from '@/components/video-page/types';
import { resolvePublicBunnyCdnHostname } from '@/lib/bunny-cdn';
interface UseVersionActionsParams extends VersionActionsConfig {
setVideo: Dispatch<SetStateAction<VideoData | null>>;
@@ -33,6 +34,7 @@ export function useVersionActions({
const [showDeleteVersionDialog, setShowDeleteVersionDialog] = useState(false);
const [versionToDelete, setVersionToDelete] = useState<string | null>(null);
const [isDeletingVersion, setIsDeletingVersion] = useState(false);
const bunnyCdnHostname = resolvePublicBunnyCdnHostname();
const handleNewVersionUrlChange = (url: string) => {
setNewVersionUrl(url);
@@ -126,7 +128,9 @@ export function useVersionActions({
finalVideoUrl = `https://iframe.mediadelivery.net/embed/${libraryId}/${bunnyVideoId}`;
finalProviderId = 'bunny';
finalProviderVideoId = bunnyVideoId;
finalThumbnailUrl = `https://vz-965f4f4a-fc1.b-cdn.net/${bunnyVideoId}/thumbnail.jpg`;
finalThumbnailUrl = bunnyCdnHostname
? `https://${bunnyCdnHostname}/${bunnyVideoId}/thumbnail.jpg`
: null;
}
const res = await fetch(`/api/projects/${projectId}/videos/${videoId}/versions`, {