All files / app/api/og route.ts

100% Statements 40/40
69.23% Branches 36/52
100% Functions 2/2
100% Lines 38/38

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89          5x 5x 5x   5x 1x       4x   4x 2x     2x 2x   2x 2x   2x 2x 2x 2x 2x     2x 1x 1x     1x 2x 1x   1x 1x       1x 1x 1x           2x 2x 2x 2x 2x     2x                             2x 1x             1x 1x    
import { NextResponse } from "next/server";
import { Innertube } from "youtubei.js";
import ogs from "open-graph-scraper";
 
export async function GET(req: Request) {
  try {
    const { searchParams } = new URL(req.url);
    const url = searchParams.get("url");
 
    if (!url) {
      return NextResponse.json({ error: "URL parameter is required" }, { status: 400 });
    }
 
    // Regex to check if it's a valid YouTube video or playlist URL
    const youtubeRegex = /^(https?:\/\/)?(www\.)?(youtube\.com\/(watch\?v=|playlist\?list=|[^\/]+)|youtu\.be\/[^\/]+)/;
 
    if (youtubeRegex.test(url)) {
      const youtube = await Innertube.create();
 
      // Extract Video ID and Playlist ID if present
      const videoMatch = url.match(/[?&]v=([^&]+)/);
      const playlistMatch = url.match(/[?&]list=([^&]+)/);
 
      const videoId = videoMatch ? videoMatch[1] : null;
      const playlistId = playlistMatch ? playlistMatch[1] : null;
 
      let playlistTitle = "";
      let playlistDescription = "";
      let videoTitle = "";
      let videoDescription = "";
      let thumbnailUrl = "";
 
      // If playlist ID is found, fetch playlist details
      if (playlistId) {
        const playlist = await youtube.getPlaylist(playlistId);
        const info = playlist?.info;
 
        // Find the current video position in the playlist
        Eif (videoId && playlist?.videos) {
          const index = playlist.videos.findIndex(video => ('id' in video) && video.id === videoId);
          const videoPosition = index !== -1 ? index + 1 : null; // Convert 0-based index to 1-based
 
          Eif (videoPosition) {
            playlistDescription = `🎬 #${videoPosition} out of `;
          }
        }
        
        playlistTitle = info?.title || "Untitled Playlist";
        playlistDescription += `${info?.total_items} 🎬 ${info?.subtitle?.text || ""}`;
        thumbnailUrl = info?.thumbnails?.[0]?.url || "";
 
      }
 
      
      // If video ID is found, fetch video details
      Eif (videoId) {
        const video = await youtube.getBasicInfo(videoId);
        videoTitle = video.basic_info?.title || "Untitled Video";
        videoDescription = video.basic_info?.short_description || "No description available";
        if (!thumbnailUrl) thumbnailUrl = video.basic_info?.thumbnail?.[0]?.url || "";
      }
 
      return NextResponse.json({
        title: playlistTitle
          ? `[Playlist : ${playlistTitle}] ❂ ${videoTitle}` // Show both if available
          : videoTitle, // Show only video title if no playlist
        description: playlistDescription
          ? `${playlistDescription}\n\n${videoDescription}` // Combine both descriptions
          : videoDescription, // Show only video description if no playlist
        image: thumbnailUrl,
        url: playlistId
          ? `https://www.youtube.com/playlist?list=${playlistId}&v=${videoId || ""}` // Use both if available
          : `https://www.youtube.com/watch?v=${videoId}`, // Fallback to video-only link
      });
    }
 
    // Use Open Graph Scraper for non-YouTube links
    const { result } = await ogs({ url });
    return NextResponse.json({
      title: result.ogTitle || "No title",
      description: result.ogDescription || "No description available",
      image: result.ogImage?.[0]?.url || "",
      url: result.ogUrl || url,
    });
  } catch (error) {
    console.error("Error fetching metadata:", error);
    return NextResponse.json({ error: "Failed to fetch metadata" }, { status: 500 });
  }
}