Tube - Mux Integration

  • Hook useMutation()
    • 在 tRPC 和 React Query 里,query 用于查询、获取数据(useQuery / useInfiniteQuery),mutation 用于修改、变更数据(创建、更新、删除)
    • useMutation() 通常与创建数据时 procedure.mutation() 共同使用
    • 现在返回的 createVideo 就是一个 mutation 实例,它是个对象,包含了一些触发函数和属性:
      • data: mutation 返回的数据
      • isPending: 是否正在执行,是否请求中
      • mutate(): 立即执行 mutation(不会返回 Promise,用回调)
      • reset(): 重置状态()loading / error / success)
  const createVideo = trpc.videos.create.useMutation({
    onSuccess: () => { ... },
    onError: (err) => { ... }
  })
  • Mux
    MUX_TOKEN_ID=...
    MUX_TOKEN_SECRET=...
    MUX_WEBHOOK_SECRET=...
    
    • 安装 bun add @mux/mux-uploader-react,版本 "@mux/mux-uploader-react": "^1.2.0"
    • 安装 bun add @mux/mux-node,版本 "@mux/mux-node": "^12.6.1",使用该sdk创建上传url
    // src/lib/mux.ts
    
    import Mux from '@mux/mux-node'
    
    export const mux = new Mux({
      tokenId: process.env.MUX_TOKEN_ID,
      tokenSecret: process.env.MUX_TOKEN_SECRET
    })
    
    // src/modules/videos/server/procedure.ts
    
    import { mux } from '@/lib/mux'
    ...
    
    export const videosRouter = createTRPCRouter({
      create: protectedProcedure.mutation(async ({ ctx }) => {
        const { id: userId } = ctx.user
    
        // mux-node-sdk提供的:创建一个新的 Direct Upload 接口
        // Direct Upload 表示前端直接将视频文件上传到 Mux,不需要经过自己的服务器
        const upload = await mux.video.uploads.create({
          new_asset_settings: {
            cors_origin: '*', // 允许所有CORS来源
            passthrough: userId, // 传递用户ID到Mux
            playback_policy: ['public'], // 设置播放策略为公开
            input: [
              {
                generated_subtitles: [
                  {
                    language_code: 'en',
                    name: 'English'
                  }
                ]
              }
            ]
          }
        })
        ...
        return {
          ...
          uploadUrl: upload.url // 返回上传URL给前端
        }
      })
    })
    
    • 返回对象:upload
      • id: 是 Direct Upload 的位置标识符,用于标记这个上传任务,可以用它查询上传状态、关联用户、上传任务的详细信息,上传完成后Mux后台会生成一个Asset,也就是视频资源,可以通过 upload.id 追溯这个视频的信息
      • url: 是一个预签名的上传终点,是一个临时可用的、带有权限验证的地址,前端可以直接把视频文件上传到这里,这个 url 只对上传任务可用,不能重复用来上传其他文件,一般有一定的过期时间
  • Mux Webhook
    • 上面的流程我们完成了将视频上传至Mux,但数据并没有同步我们的数据库,下面我们通过监听特定的 Webhook 事件来实现
    • 首先我们创建webhook文件在 src/app/api/videos/webhook/route.ts,通过这个api路由可以生成对应的环境变量 MUX_WEBHOOK_SECRET
    • Mux 会通过 HTTP POST 请求把 webhook 数据发送到我们指定的Webhook URL,会触发我们在webhook文件中定义的 POST 方法,在这个方法中我们会处理Mux发来的请求头、请求体,通过 mux.webhooks.verifySignature() 验证请求头和请求体中的签名,签名验证成功后再处理不同的事件
    • 验证签名的流程请参考 verify-webhook-signatures
// 请求头

import { headers } from 'next/headers'

const headersPayload = await headers()
const muxSignature = headersPayload.get('mux-signature')
// 请求体

const payload = await request.json() 
const body = JSON.stringify(payload)
// 签名验证

mux.webhooks.verifySignature(
  body,  // body
  { "mux-signature": muxSignature, },  // header
  process.env.MUX_WEBHOOK_SECRET  // secret
)
// 事件处理

import {
  VideoAssetCreatedWebhookEvent,
  VideoAssetErroredWebhookEvent,
  VideoAssetReadyWebhookEvent,
  VideoAssetTrackReadyWebhookEvent,
  VideoAssetDeletedWebhookEvent,
} from '@mux/mux-node/resources/webhooks'  // Mux 提供的事件类型

// 联合类型
type WebhookEvent = 
  | VideoAssetCreatedWebhookEvent
  | VideoAssetErroredWebhookEvent
  | VideoAssetReadyWebhookEvent
  | VideoAssetTrackReadyWebhookEvent
  | VideoAssetDeletedWebhookEvent

// 类型断言
switch(payload.type as WebhookEvent["type"]) {
  // 已创建
  case "video.asset.created": {...}
  // 已准备好播放
  case "video.asset.ready": {...}
  // error
  case 'video.asset.errored': {...}
  // 已删除
  case 'video.asset.deleted': {...}
  // 字幕文本轨道就绪
  case "video.asset.track.ready": {...}
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容