"use client"; import Image from "next/image"; import { FileAudio, FileImage, FileVideo, LinkIcon } from "lucide-react"; import { Badge } from "@/components/ui/badge"; import { resolveMediaUrl } from "@/lib/media-url"; import type { ApiPost } from "@/types/api"; function pickImageUrl(post: ApiPost) { const variant = Array.isArray(post.imageVariants) ? post.imageVariants[0] : post.imageVariants; return ( post.imageItems?.find((item) => item.variants?.medium || item.url)?.variants?.medium ?? post.imageItems?.find((item) => item.url)?.url ?? variant?.medium ?? variant?.thumbnail ?? post.imageUrls?.[0] ?? "" ); } function getPostMedia(post: ApiPost) { const imageUrl = pickImageUrl(post); const thumbnailUrl = post.thumbnailVariants?.medium ?? post.thumbnailVariants?.thumbnail ?? post.thumbnailUrl ?? ""; const playbackUrl = post.hlsUrl || post.videoUrl || ""; const audioUrl = post.audioUrl ?? ""; return { imageUrl: resolveMediaUrl(imageUrl), thumbnailUrl: resolveMediaUrl(thumbnailUrl), playbackUrl: resolveMediaUrl(playbackUrl), audioUrl: resolveMediaUrl(audioUrl), }; } export function getMediaHealth(post: ApiPost) { const checks = { hasImage: Boolean(pickImageUrl(post)), hasVideo: Boolean(post.videoUrl || post.hlsUrl), hasAudio: Boolean(post.audioUrl), hasThumbnail: Boolean(post.thumbnailUrl || post.thumbnailVariants?.thumbnail || post.thumbnailVariants?.medium), hasDuration: typeof post.durationSeconds === "number" && post.durationSeconds > 0, hasOptimizedImage: Boolean(post.imageItems?.some((item) => item.variants && Object.keys(item.variants).length > 0)) || Boolean(post.imageVariants && Object.keys(post.imageVariants).length > 0), hasHls: Boolean(post.hlsUrl), }; const problems: string[] = []; if (post.postType === "image" && !checks.hasImage) problems.push("missing image"); if (post.postType === "image" && !checks.hasOptimizedImage) problems.push("no image variants"); if (post.postType === "video" && !checks.hasVideo) problems.push("missing video"); if (post.postType === "video" && !checks.hasThumbnail) problems.push("missing thumbnail"); if (post.postType === "video" && !checks.hasHls) problems.push("no HLS"); if ((post.postType === "video" || post.postType === "audio") && !checks.hasDuration) { problems.push("missing duration"); } if (post.postType === "audio" && !checks.hasAudio) problems.push("missing audio"); return { checks, problems, score: Math.max(0, 100 - problems.length * 20), }; } export function MediaInspector({ post, compact = false }: { post: ApiPost; compact?: boolean }) { const media = getPostMedia(post); const health = getMediaHealth(post); const badges = [ post.hlsUrl ? "HLS" : null, post.thumbnailUrl ? "thumbnail" : null, post.durationSeconds ? `${Math.round(post.durationSeconds)}s` : null, post.processingStatus ? post.processingStatus : null, ].filter(Boolean); return (
{post.postType === "video" && media.playbackUrl ? ( ) : post.postType === "audio" && media.audioUrl ? (
{media.thumbnailUrl ? ( {post.content ) : (
)}
) : media.imageUrl ? ( {post.imageItems?.[0]?.altText ) : (
{post.postType === "video" ? : } No preview media
)}
media health {health.score}% {badges.map((badge) => ( {badge} ))}
{health.problems.length ? (
{health.problems.map((problem) => ( {problem} ))}
) : null} {!compact ? (
{[media.imageUrl, media.playbackUrl, media.audioUrl, media.thumbnailUrl].filter(Boolean).map((url) => (
{url}
))}
) : null}
); }