You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否借助supabase-js获取Supabase存储视频首帧制作缩略图?

用Supabase实现存储视频的第一帧缩略图展示

完全可以实现这个需求,下面是几种落地的方案,按需选择:

方案一:预生成缩略图(推荐,彻底节省带宽)

通过Supabase Edge Functions结合FFmpeg,在视频上传到存储桶时自动提取第一帧并保存为缩略图,后续前端直接加载缩略图即可,完全不用请求视频文件。

具体步骤:

  1. 创建一个Supabase Edge Function,引入FFmpeg库处理视频:
    • 安装依赖:npm install @ffmpeg/ffmpeg @ffmpeg/core
    • 编写函数逻辑,核心是读取上传的视频文件,执行FFmpeg命令提取第一帧:
      import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
      import { FFmpeg } from "https://cdn.skypack.dev/@ffmpeg/ffmpeg@0.12.6";
      import { fetchFile, toBlobURL } from "https://cdn.skypack.dev/@ffmpeg/util@0.12.1";
      import { createClient } from "https://esm.sh/@supabase/supabase-js@2.33.1";
      
      serve(async (req) => {
        const supabase = createClient(
          Deno.env.get("SUPABASE_URL")!,
          Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!
        );
      
        // 获取上传的视频信息(从存储桶webhook的请求体中)
        const { record } = await req.json();
        const videoPath = record.path;
      
        // 下载视频到Edge Function临时存储
        const { data: videoData, error: downloadError } = await supabase.storage
          .from("videos")
          .download(videoPath);
        if (downloadError) return new Response(JSON.stringify(downloadError), { status: 500 });
      
        // 初始化FFmpeg
        const ffmpeg = new FFmpeg();
        await ffmpeg.load({
          coreURL: await toBlobURL(
            "https://unpkg.com/@ffmpeg/core@0.12.6/dist/ffmpeg-core.js",
            "text/javascript"
          ),
        });
      
        // 写入视频文件
        await ffmpeg.writeFile("input.mp4", await fetchFile(videoData));
        // 执行提取第一帧的命令
        await ffmpeg.exec(["-i", "input.mp4", "-vframes", "1", "-f", "image2", "output.jpg"]);
        // 读取生成的缩略图
        const thumbnailData = await ffmpeg.readFile("output.jpg");
      
        // 上传缩略图到存储桶(比如单独的thumbnails桶)
        const thumbnailPath = `thumbnails/${videoPath.split("/").pop()!.replace(".mp4", ".jpg")}`;
        const { error: uploadError } = await supabase.storage
          .from("videos")
          .upload(thumbnailPath, new Blob([thumbnailData], { type: "image/jpeg" }), {
            contentType: "image/jpeg",
          });
        if (uploadError) return new Response(JSON.stringify(uploadError), { status: 500 });
      
        // 更新数据库中对应视频的缩略图路径(如果有对应表的话)
        const { error: dbError } = await supabase
          .from("videos")
          .update({ thumbnail_path: thumbnailPath })
          .eq("video_path", videoPath);
        if (dbError) return new Response(JSON.stringify(dbError), { status: 500 });
      
        return new Response("Thumbnail generated successfully", { status: 200 });
      });
      
  2. 给存储桶配置webhook,当有新视频上传时触发这个Edge Function:
    • 进入Supabase控制台的存储页面,选中视频存储桶,在"Webhooks"标签下添加新webhook,触发事件选择"Object created",目标URL填Edge Function的部署地址。

方案二:前端按需生成缩略图(快速实现,适合小量视频)

如果视频数量不多,可以直接在前端通过视频URL提取第一帧,无需后端预生成。这种方式浏览器只会加载视频的元数据和第一帧数据,带宽消耗远低于加载整个视频。

代码示例:

async function generateVideoThumbnail(videoUrl) {
  const video = document.createElement('video');
  // 处理跨域问题(如果视频存储桶配置了正确的CORS)
  video.crossOrigin = 'anonymous';
  video.src = videoUrl;
  
  // 等待视频加载到第一帧
  await new Promise((resolve, reject) => {
    video.onloadeddata = resolve;
    video.onerror = reject;
  });

  // 用Canvas绘制第一帧
  const canvas = document.createElement('canvas');
  canvas.width = video.videoWidth;
  canvas.height = video.videoHeight;
  const ctx = canvas.getContext('2d');
  ctx.drawImage(video, 0, 0);

  // 转换成Base64格式的图片
  return canvas.toDataURL('image/jpeg', 0.8);
}

// 使用示例
const videoUrl = 'https://your-supabase-url.storage.googleapis.com/videos/example.mp4';
generateVideoThumbnail(videoUrl).then(thumbnailUrl => {
  const img = document.createElement('img');
  img.src = thumbnailUrl;
  document.body.appendChild(img);
});

方案三:数据库关联缩略图路径

不管用哪种方式生成缩略图,建议在Supabase数据库中创建对应表(比如videos),存储视频路径和缩略图路径的关联关系。前端直接从数据库读取缩略图URL,避免重复生成或处理,提升加载效率。

示例表结构:

CREATE TABLE videos (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  video_path TEXT NOT NULL,
  thumbnail_path TEXT,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

内容的提问来源于stack exchange,提问作者Rorp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 09:37:25