"use client"; import { useState } from "react"; 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"; 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) { if (views >= 10000000) return { name: "神话曲", next: null, progress: 100 }; if (views >= 1000000) return { name: "传说曲", next: "神话曲", progress: (views / 10000000) * 100, }; if (views >= 100000) return { name: "殿堂曲", next: "传说曲", progress: (views / 1000000) * 100, }; return { name: "未达成", next: "殿堂曲", progress: (views / 100000) * 100 }; } export default function VideoSearch() { const [searchTerm, setSearchTerm] = useState(""); const [videos, setVideos] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const handleSearch = async () => { if (!searchTerm) { setError("请输入搜索内容"); return; } setLoading(true); setError(null); try { const response = await fetch( `https://api.ninevocalrank.top/vocaloid_rank/v1/video/${searchTerm}` ); const weekly_response = await fetch( `https://api.ninevocalrank.top/vocaloid_rank/v1/video/${searchTerm}` ); if (!response.ok || !weekly_response.ok) { throw new Error("服务器响应错误"); } const data = await response.json(); const weekly_data = await weekly_response.json(); // 合并 data 和 weekly_data const combinedData = { ...data, weekly_data: weekly_data, }; setVideos([combinedData]); if (videos.length === 0) { setError("未找到匹配的视频"); } } catch (error) { console.error("搜索视频时出错:", error); setError("搜索过程中出现错误"); } finally { setLoading(false); } }; return ( 搜索视频
setSearchTerm(e.target.value)} />
{error &&

{error}

} {videos.length > 0 ? (
    {videos.map((video) => { const achievement = getAchievement(video.video_stat.view); return (
  • {/* eslint-disable-next-line @next/next/no-img-element */} 视频封面

    {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}{" "} 播放

    )}
  • ); })}
) : ( !loading && !error &&

暂无数据

)}
); }