"use client"; import { useState } from "react"; import { useRouter } from "next/navigation"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Button } from "@/components/ui/button"; import { Loader2 } from "lucide-react"; import { blockedVideoIds } from "@/config/blocked-ids"; interface Video { video_stat: { view: number; like: number; coin: number; favorite: number; reply: number; share: number; danmaku: number; }; video_info: { uploader_mid: string; uploader_name: string; title: string; pic: string; pages: number; timestamp: number; }; video_id: { avid: string; bvid: string; }; vrank_info: { vrank_score: number; rank: string; rank_code: number; progress_percentage: number; }; video_increase: { view: number; like: number; coin: number; favorite: number; reply: number; share: number; danmaku: number; }; score_rank: number; } function getAchievement(views: number) { const safeViews = Math.max(0, Number(views) || 0); if (safeViews >= 10000000) return { name: "神话曲", next: null, progress: 100 }; if (safeViews >= 1000000) return { name: "传说曲", next: "神话曲", progress: (safeViews / 10000000) * 100, }; if (safeViews >= 100000) return { name: "殿堂曲", next: "传说曲", progress: (safeViews / 1000000) * 100, }; return { name: "未达成", next: "殿堂曲", progress: (safeViews / 100000) * 100, }; } const VideoInfo = ({ video }: { video: Video }) => { const achievement = getAchievement(video.video_stat.view); return (
  • {video.video_info.title}

    UP主: {video.video_info.uploader_name} (UID:{" "} {video.video_info.uploader_mid})

    BV号: {video.video_id.bvid}

    AV号: {video.video_id.avid}

    播放量: {video.video_stat.view.toLocaleString()}

    点赞数: {video.video_stat.like.toLocaleString()}

    投币: {video.video_stat.coin.toLocaleString()}

    收藏: {video.video_stat.favorite.toLocaleString()}

    评论: {video.video_stat.reply.toLocaleString()}

    分享: {video.video_stat.share.toLocaleString()}

    弹幕数: {video.video_stat.danmaku.toLocaleString()}

    周刊数据

    {video.vrank_info ? ( <>

    周刊得分: {video.vrank_info.vrank_score.toFixed(2)}

    周刊排名: {video.score_rank}

    ) : (

    暂无周刊数据

    )} {video.video_increase && ( <>
    数据增长:

    播放增长: {video.video_increase.view.toLocaleString()}

    点赞增长: {video.video_increase.like.toLocaleString()}

    投币增长: {video.video_increase.coin.toLocaleString()}

    收藏增长: {video.video_increase.favorite.toLocaleString()}

    评论增长: {video.video_increase.reply.toLocaleString()}

    分享增长: {video.video_increase.share.toLocaleString()}

    弹幕增长: {video.video_increase.danmaku.toLocaleString()}

    )}

    数据更新时间:{" "} {new Date(video.video_info.timestamp * 1000).toLocaleString( "zh-CN" )}

    成就: {achievement.name}

    {achievement.next && (

    距离 {achievement.next} 还需{" "} {(achievement.next === "殿堂曲" ? 100000 : achievement.next === "传说曲" ? 1000000 : 10000000) - video.video_stat.view}{" "} 播放

    )}
  • ); }; export default function VideoSearch() { const [searchTerm, setSearchTerm] = useState(""); const [videos, setVideos] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const router = useRouter(); const handleSearch = async () => { if (!searchTerm.trim()) { setError("请输入有效的搜索内容"); return; } // 输入格式验证 if (!/^(BV([a-zA-Z0-9]{10})|AV\d+)$/.test(searchTerm)) { setError("请输入有效的BV号或AV号"); return; } if (blockedVideoIds.includes(searchTerm)) { router.push("/blocked"); return; } setLoading(true); setError(null); try { const [response, weeklyResponse] = await Promise.all([ fetch( `https://api.mmeiblog.cn/NineVocalRank/vocaloid_rank/v1/video/${searchTerm}` ), fetch( `https://api.mmeiblog.cn/NineVocalRank/vocaloid_rank/v1/sorted/${searchTerm}` ), ]); if (!response.ok || !weeklyResponse.ok) { const statusText = response.status === 404 ? "视频未找到" : "服务器响应错误"; throw new Error(statusText); } const data = await response.json(); const weeklyData = await weeklyResponse.json(); const combinedData = { ...data, score_rank: weeklyData.score_rank, }; setVideos([combinedData]); setLoading(false); if (!combinedData) { setError("未找到匹配的视频"); } } catch (err) { if (err instanceof TypeError && err.message.includes("network error")) { setError("网络连接异常,请检查网络状态"); } else if (err instanceof Error && err.message.includes("JSON")) { setError("数据解析失败,请稍后重试"); } else if (err instanceof Error && err.message.includes("视频不符合")) { setError("该视频不在Vocaloid分区,无法查询"); } else { setError(err instanceof Error ? err.message : "搜索过程中出现未知错误"); } console.error("搜索视频时出错:", err); setLoading(false); } }; return ( 搜索视频
    setSearchTerm(e.target.value)} />
    {error &&

    {error}

    } {videos.length > 0 ? (
      {videos .map((video) => { // 空值校验 if (!video?.video_id?.bvid) { console.warn("该视频不在Vocaloid分区,无法查询", video); return null; } return ; }) .filter(Boolean)}
    ) : ( !loading && !error &&

    暂无数据

    )}
    ); }