如何在Next.js中调用YouTube API获取视频字幕?
在Next.js中通过YouTube API获取视频字幕
我已经有一个Next.js客户端组件,能通过useSearchParams获取视频链接{link},并且知道如何用Python的youtube_transcript_api获取YouTube视频字幕,现在需要在Next.js中借助YouTube API实现相同功能。
现有客户端组件代码
"use client"; import { useSearchParams } from "next/navigation"; function VideoCreado() { const searchParams = useSearchParams(); // 修正拼写错误:searchParmas → searchParams const link = searchParams.get("link"); return ( <div className="bg-gray-900 text-gray-100 min-h-screen flex flex-col items-center justify-center"> <h1 className="text-3xl font-bold mb-4">视频已生成!</h1> <p className="text-lg">字幕:</p> <p>{link}</p> </div> ); } export default VideoCreado;
Python实现示例(注释汉化)
from youtube_transcript_api import YouTubeTranscriptApi def get_transcription(video_url): # 从URL中提取视频ID video_id = video_url.split("v=")[1] ampersand_position = video_id.find("&") if ampersand_position != -1: video_id = video_id[:ampersand_position] # 获取字幕 transcript = YouTubeTranscriptApi.get_transcript(video_id) # 将字幕合并为单个字符串 transcription = ' '.join([entry['text'] for entry in transcript]) return transcription # 示例用法 video_url = "https://www.youtube.com/watch?v=8yZ-x-WuFw0&ab_channel=NamePointer" transcription = get_transcription(video_url) print(transcription)
Next.js实现步骤
1. 前端提取视频ID
和Python逻辑一致,在客户端组件中添加提取视频ID的工具函数:
const extractVideoId = (url) => { if (!url) return null; // 匹配标准YouTube链接的视频ID(11位字符) const videoIdMatch = url.match(/(?:v=|\/)([0-9A-Za-z_-]{11}).*/); return videoIdMatch ? videoIdMatch[1] : null; };
2. 创建API路由代理请求
直接在客户端调用YouTube API会暴露密钥,因此用Next.js API路由做代理。在app/api/transcript/route.js创建文件:
export async function GET(request) { const { searchParams } = new URL(request.url); const videoId = searchParams.get("videoId"); const apiKey = process.env.YOUTUBE_API_KEY; // 从环境变量读取API密钥 if (!videoId || !apiKey) { return new Response(JSON.stringify({ error: "缺少视频ID或API密钥" }), { status: 400, headers: { "Content-Type": "application/json" }, }); } // 调用YouTube Data API获取字幕列表 const transcriptListUrl = `https://www.googleapis.com/youtube/v3/captions?part=snippet&videoId=${videoId}&key=${apiKey}`; const transcriptListResponse = await fetch(transcriptListUrl); const transcriptListData = await transcriptListResponse.json(); if (!transcriptListData.items || transcriptListData.items.length === 0) { return new Response(JSON.stringify({ error: "该视频无可用公开字幕" }), { status: 404, headers: { "Content-Type": "application/json" }, }); } // 获取第一个可用字幕的JSON格式内容 const captionId = transcriptListData.items[0].id; const transcriptUrl = `https://www.googleapis.com/youtube/v3/captions/${captionId}?key=${apiKey}&tfmt=json`; const transcriptResponse = await fetch(transcriptUrl); const transcriptData = await transcriptResponse.json(); // 格式化字幕为纯文本 const transcriptText = transcriptData.events .map((event) => event.segs?.map((seg) => seg.utf8).join("")) .filter(Boolean) .join(" "); return new Response(JSON.stringify({ transcript: transcriptText }), { headers: { "Content-Type": "application/json" }, }); }
3. 客户端组件集成API调用
修改原组件,添加状态管理和字幕获取逻辑:
"use client"; import { useSearchParams } from "next/navigation"; import { useState, useEffect } from "react"; function VideoCreado() { const searchParams = useSearchParams(); const link = searchParams.get("link"); const [transcript, setTranscript] = useState(""); const [loading, setLoading] = useState(false); const [error, setError] = useState(""); // 提取视频ID的工具函数 const extractVideoId = (url) => { if (!url) return null; const videoIdMatch = url.match(/(?:v=|\/)([0-9A-Za-z_-]{11}).*/); return videoIdMatch ? videoIdMatch[1] : null; }; useEffect(() => { if (link) { const videoId = extractVideoId(link); if (!videoId) { setError("无效的YouTube视频链接"); return; } setLoading(true); setError(""); // 调用API路由获取字幕 fetch(`/api/transcript?videoId=${videoId}`) .then(res => res.json()) .then(data => { if (data.error) { setError(data.error); } else { setTranscript(data.transcript); } }) .catch(() => { setError("获取字幕失败,请稍后重试"); }) .finally(() => { setLoading(false); }); } }, [link]); return ( <div className="bg-gray-900 text-gray-100 min-h-screen flex flex-col items-center justify-center p-4"> <h1 className="text-3xl font-bold mb-4">视频已生成!</h1> <p className="text-lg mb-2">视频链接:</p> <p className="mb-4 break-all">{link}</p> <p className="text-lg mb-2">字幕:</p> {loading && <p>正在加载字幕...</p>} {error && <p className="text-red-400">{error}</p>} {transcript && ( <div className="bg-gray-800 p-4 rounded max-w-2xl whitespace-pre-wrap"> {transcript} </div> )} </div> ); } export default VideoCreado;
关键注意事项
- 需在Google Cloud控制台创建项目,启用YouTube Data API v3,生成API密钥后添加到
.env.local:YOUTUBE_API_KEY=你的密钥 - YouTube API有调用配额限制,需留意配额使用情况
- 部分视频可能没有公开字幕,需处理无字幕的异常场景
内容的提问来源于stack exchange,提问作者samsamradas
相关产品推荐
相关产品推荐

