Please bookmark this page to avoid losing your image tool!

YouTube Video Photo And Stats Viewer

(Free & Supports Bulk Upload)

Drag & drop your images here or

The result will appear here...
You can edit the below JavaScript code to customize the image tool.
async function processImage(originalImg, youtubeUrlOrVideoId = "dQw4w9WgXcQ", showMockStats = "yes") {
    // Extract video ID from typical YouTube URL formats or use directly if it's just an ID
    const videoId = (function (url) {
        const match = url.match(/(?:youtu\.be\/|youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/\s]{11})/);
        return match ? match[1] : (url.length === 11 ? url : "dQw4w9WgXcQ");
    })(youtubeUrlOrVideoId);

    // Default real stats
    let title = "Unknown Title";
    let author = "Unknown Channel";
    let views = "N/A";
    let likes = "N/A";
    let dislikes = "N/A";
    let rating = "N/A";

    // Attempt to fetch Title and Channel from public Noembed API
    try {
        const noembedRes = await fetch(`https://noembed.com/embed?url=https://www.youtube.com/watch?v=${videoId}`);
        if (noembedRes.ok) {
            const noembedData = await noembedRes.json();
            if (noembedData.title) title = noembedData.title;
            if (noembedData.author_name) author = noembedData.author_name;
        }
    } catch (e) {
        console.warn("Failed to fetch video details from noembed", e);
    }

    // Attempt to fetch public Views, Likes, Dislikes via Return YouTube Dislike API
    try {
        const rydRes = await fetch(`https://returnyoutubedislikeapi.com/votes?videoId=${videoId}`);
        if (rydRes.ok) {
            const rydData = await rydRes.json();
            if (rydData.viewCount !== undefined) views = rydData.viewCount.toLocaleString();
            if (rydData.likes !== undefined) likes = rydData.likes.toLocaleString();
            if (rydData.dislikes !== undefined) dislikes = rydData.dislikes.toLocaleString();
            if (rydData.rating !== undefined) rating = rydData.rating.toFixed(2);
        }
    } catch (e) {
        console.warn("Failed to fetch view/like stats", e);
    }

    // Create Canvas
    const canvas = document.createElement("canvas");
    const w = originalImg.width || 1280;
    const h = originalImg.height || 720;
    canvas.width = w;
    canvas.height = h;
    const ctx = canvas.getContext("2d");

    // Draw original image as the background
    ctx.drawImage(originalImg, 0, 0, w, h);

    // Helpers to generate random mock data for advanced stats
    const generateMockCPN = () => {
        const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
        return Array.from({ length: 12 }).map(() => chars.charAt(Math.floor(Math.random() * chars.length))).join('');
    };
    const generateRandomString = (len) => {
        const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
        return Array.from({ length: len }).map(() => chars.charAt(Math.floor(Math.random() * chars.length))).join('');
    };

    // Construct Stats Lines
    const lines = [
        { label: "Title", value: title },
        { label: "Channel", value: author },
        { label: "Video ID / sCPN", value: `${videoId} / ${generateMockCPN()}` },
        { label: "Views", value: views },
        { label: "Likes / Dislikes", value: `${likes} / ${dislikes}` }
    ];

    if (showMockStats.toLowerCase() === "yes" || showMockStats === "1" || showMockStats === "true") {
        lines.push(
            { label: "Rating", value: `${rating} / 5.00` },
            { label: "Viewport / Frames", value: `${w}x${h} / 0 dropped of ${(Math.random() * 5000 + 1000).toFixed(0)}` },
            { label: "Current / Optimal Res", value: `${w}x${h}@60 / ${w}x${h}@60` },
            { label: "Volume / Normalized", value: "100% / 100% (content loudness -1.2dB)" },
            { label: "Codecs", value: "vp09.00.51.08.01.01.01.01 (248) / opus (251)" },
            { label: "Host", value: `r${Math.floor(Math.random() * 8) + 1}---sn-${generateRandomString(8)}.googlevideo.com` },
            { label: "Buffer Health", value: (Math.random() * 30 + 10).toFixed(1) + " s" },
            { label: "Connection Speed", value: (Math.random() * 50000 + 10000).toFixed(0) + " Kbps" },
            { label: "Network Activity", value: "0 KB" }
        );
    }

    // Determine font size dynamically based on canvas dimensions to fit appropriately
    let fontSize = Math.max(10, Math.floor(w / 45));
    let lineHeight = fontSize * 1.6;

    // Shrink font size if the height of the generated table would exceed limits
    const requiredTotalHeight = lineHeight * (lines.length + 4);
    if (requiredTotalHeight > h * 0.9) {
        fontSize = Math.floor((h * 0.9) / ((lines.length + 4) * 1.6));
        if (fontSize < 8) fontSize = 8;
        lineHeight = fontSize * 1.6;
    }

    // Measure widths to build columns
    ctx.font = `${fontSize}px sans-serif`;
    let maxLabelWidth = 0;
    
    ctx.font = `bold ${fontSize}px sans-serif`;
    lines.forEach(l => {
        const lw = ctx.measureText(l.label).width;
        if (lw > maxLabelWidth) maxLabelWidth = lw;
    });

    // Truncate long values to prevent breaking out of the container bounds
    const maxValChars = Math.max(10, Math.floor(w * 0.85 / (fontSize * 0.6)) - Math.ceil(maxLabelWidth / fontSize) - 5);
    lines.forEach(l => {
        if (l.value.length > maxValChars) {
            l.value = l.value.substring(0, maxValChars - 3) + "...";
        }
    });

    // Measure values side length
    let maxValueWidth = 0;
    ctx.font = `normal ${fontSize}px sans-serif`;
    lines.forEach(l => {
        const vw = ctx.measureText(l.value).width;
        if (vw > maxValueWidth) maxValueWidth = vw;
    });

    // Compile layout parameters
    const boxInnerPadding = fontSize * 1.5;
    const boxWidth = Math.min(maxLabelWidth + maxValueWidth + boxInnerPadding * 2, w * 0.9);
    const boxHeight = lines.length * lineHeight + boxInnerPadding * 2.5;
    const boxX = Math.max(10, w * 0.05);
    const boxY = Math.max(10, h * 0.05);

    // Draw Stats Box Base (Semi-transparent black)
    ctx.fillStyle = "rgba(0, 0, 0, 0.75)";
    ctx.beginPath();
    const r = Math.min(8, fontSize); // border radius
    ctx.moveTo(boxX + r, boxY);
    ctx.lineTo(boxX + boxWidth - r, boxY);
    ctx.quadraticCurveTo(boxX + boxWidth, boxY, boxX + boxWidth, boxY + r);
    ctx.lineTo(boxX + boxWidth, boxY + boxHeight - r);
    ctx.quadraticCurveTo(boxX + boxWidth, boxY + boxHeight, boxX + boxWidth - r, boxY + boxHeight);
    ctx.lineTo(boxX + r, boxY + boxHeight);
    ctx.quadraticCurveTo(boxX, boxY + boxHeight, boxX, boxY + boxHeight - r);
    ctx.lineTo(boxX, boxY + r);
    ctx.quadraticCurveTo(boxX, boxY, boxX + r, boxY);
    ctx.closePath();
    ctx.fill();

    // Draw "Stats for nerds" Header
    ctx.fillStyle = "white";
    ctx.font = `bold ${fontSize * 1.2}px sans-serif`;
    ctx.fillText("Stats for nerds", boxX + boxInnerPadding, boxY + boxInnerPadding);

    // Draw pseudo-close "✕" icon
    ctx.font = `normal ${fontSize * 1.2}px sans-serif`;
    ctx.fillText("✕", boxX + boxWidth - boxInnerPadding - fontSize * 0.5, boxY + boxInnerPadding);

    // Draw Separator Line under title
    ctx.strokeStyle = "rgba(255, 255, 255, 0.25)";
    ctx.lineWidth = 1;
    ctx.beginPath();
    ctx.moveTo(boxX + boxInnerPadding, boxY + boxInnerPadding + fontSize * 0.8);
    ctx.lineTo(boxX + boxWidth - boxInnerPadding, boxY + boxInnerPadding + fontSize * 0.8);
    ctx.stroke();

    // Draw Data Entries line by line
    let currentY = boxY + boxInnerPadding * 2.2;
    for (let i = 0; i < lines.length; i++) {
        const lineData = lines[i];

        // Label Column
        ctx.fillStyle = "#bbbbbb"; // Customary YouTube grey for labels
        ctx.font = `bold ${fontSize}px sans-serif`;
        ctx.fillText(lineData.label, boxX + boxInnerPadding, currentY);

        // Value Column
        ctx.fillStyle = "white"; // White for actual values
        ctx.font = `normal ${fontSize}px sans-serif`;
        ctx.fillText(lineData.value, boxX + boxInnerPadding + maxLabelWidth + fontSize, currentY);

        currentY += lineHeight;
    }

    return canvas;
}

Free Image Tool Creator

Can't find the image tool you're looking for?
Create one based on your own needs now!

Description

This tool allows users to overlay detailed video information and technical statistics onto an image, mimicking the ‘Stats for nerds’ interface found on YouTube. By providing a YouTube URL or video ID, the tool fetches real-time data such as the video title, channel name, view count, and like/dislike ratios. It can also generate comprehensive mock technical data, including playback resolution, codecs, buffer health, and connection speed, making it useful for creating realistic mockups, educational content, or visual demonstrations of video player interfaces.

Leave a Reply

Your email address will not be published. Required fields are marked *

Other Image Tools:

Image To G Major 16 Color Filter Converter

YouTube Video Photo and Image Stats For Nerds Tool

Image To Scalable Kaomoji Converter With Decorative Symbols

Kingdom Hearts SVTFOE Gameplay Image Viewer

Kingdom Hearts SVTFOE Gameplay Video Player

Image To Video Content Description Tool

Big Hero 6 2014 Tubi TV June 30 2027 Video Screenshot

No tool description provided

Big Hero 6 2014 Tubi Jun 30 2027 Photo

San Diego Comic-Con Image Gallery

Movie Studio Intro YTP Collab Style Image Maker

Movie Studio Music Fanfare Logo Maker

Movie Studio Music Fanfare Logo Generator

Kurdish Dubbing Audio to Image Visualizer Tool

Kurdish Dubbed Audio Video Tool

Kurdish Dub Audio to Image Converter

Kurdish Dub Audio Overlay Tool

Warner Bros Discovery Animation Studio Divisions Image Viewer

Image To Character Voice Actor Idea Generator

Image To Character Voice Actor Suggestion Tool

Image Color Adjustment Tool

Dingbats Logo Compilation Image Generator

Image Color and Opacity Adjustment Tool

The Lion King VHS Mar 3 1995 Image

The Lion King Hamtaro Character Cast Reimaginer

Audio Transcription and Identification Tool

The Lion King Hamtaro Character Role Swap Image Generator

Audio to Image Fanfare Visualizer Tool

Audio Clip of Universal Pictures Fanfares

Audio File to Image Converter

Universal Pictures Fanfare Audio Identifier

Universal Pictures Fanfare Audio Identification Tool

Universal Pictures Fanfare Audio Comparison Tool

Universal Pictures Fanfare Audio Search Tool

Universal Pictures Fanfare Audio Player

Universal Pictures David Newman Fanfare Audio Player

See All →