fix: weekly_rank

This commit is contained in:
mei 2025-02-10 09:47:51 +08:00
parent 6a7a771f2e
commit 38efae7c49
4 changed files with 100 additions and 154 deletions

View File

@ -18,8 +18,8 @@ export default function DatabaseStats() {
const fetchCounts = async () => {
try {
setLoading(true)
const videoResponse = await fetch("https://api.ninevocalrank.top/basic/v1/database/video_count")
const uploaderResponse = await fetch("https://api.ninevocalrank.top/basic/v1/database/uploader_count")
const videoResponse = await fetch("https://ecs-113-44-166-103.compute.hwclouds-dns.com/basic/v1/database/video_count")
const uploaderResponse = await fetch("https://ecs-113-44-166-103.compute.hwclouds-dns.com/basic/v1/database/uploader_count")
if (!videoResponse.ok || !uploaderResponse.ok) {
throw new Error("服务器响应错误")

View File

@ -13,7 +13,7 @@ export default function ServerStats() {
const fetchServerStat = async () => {
try {
setLoading(true)
const response = await fetch("https://api.ninevocalrank.top/basic/v1/ServerStat/info")
const response = await fetch("https://ecs-113-44-166-103.compute.hwclouds-dns.com/basic/v1/ServerStat/info")
if (!response.ok) {
throw new Error("服务器响应错误")
}

View File

@ -29,7 +29,7 @@ export default function UploaderSearch() {
setLoading(true)
setError(null)
try {
const response = await fetch(`https://api.ninevocalrank.top/basic/v1/uploader/${uid}`)
const response = await fetch(`https://ecs-113-44-166-103.compute.hwclouds-dns.com/basic/v1/uploader/${uid}`)
if (!response.ok) {
throw new Error("服务器响应错误")
}

View File

@ -1,119 +1,117 @@
"use client";
"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";
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;
};
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;
};
uploader_mid: string
uploader_name: string
title: string
pic: string
pages: number
timestamp: number
}
video_id: {
avid: string;
bvid: string;
};
avid: string
bvid: string
}
vrank_info: {
vrank_score: number;
rank: string;
rank_code: number;
progress_percentage: number;
};
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;
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 >= 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 };
}
return { name: "未达成", next: "殿堂曲", progress: (views / 100000) * 100 }
}
export default function VideoSearch() {
const [searchTerm, setSearchTerm] = useState("");
const [videos, setVideos] = useState<Video[]>([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const [searchTerm, setSearchTerm] = useState("")
const [videos, setVideos] = useState<Video[]>([])
const [loading, setLoading] = useState(false)
const [error, setError] = useState<string | null>(null)
const handleSearch = async () => {
if (!searchTerm) {
setError("请输入搜索内容");
return;
setError("请输入搜索内容")
return
}
setLoading(true);
setError(null);
setLoading(true)
setError(null)
try {
const response = await fetch(
`https://api.ninevocalrank.top/vocaloid_rank/v1/video/${searchTerm}`
);
`https://ecs-113-44-166-103.compute.hwclouds-dns.com/vocaloid_rank/v1/video/${searchTerm}`,
)
const weekly_response = await fetch(
`https://api.ninevocalrank.top/vocaloid_rank/v1/video/${searchTerm}`
);
`https://ecs-113-44-166-103.compute.hwclouds-dns.com/vocaloid_rank/v1/sorted/${searchTerm}`,
)
if (!response.ok || !weekly_response.ok) {
throw new Error("服务器响应错误");
throw new Error("服务器响应错误")
}
const data = await response.json();
const weekly_data = await weekly_response.json();
const data = await response.json()
const weekly_data = await weekly_response.json()
// 合并 data 和 weekly_data
const combinedData = {
...data,
weekly_data: weekly_data,
};
score_rank: weekly_data.score_rank,
}
setVideos([combinedData]);
setVideos([combinedData])
if (videos.length === 0) {
setError("未找到匹配的视频");
setError("未找到匹配的视频")
}
} catch (error) {
console.error("搜索视频时出错:", error);
setError("搜索过程中出现错误");
console.error("搜索视频时出错:", error)
setError("搜索过程中出现错误")
} finally {
setLoading(false);
setLoading(false)
}
};
}
return (
<Card className="bg-gradient-to-br from-yellow-100 to-red-100">
<CardHeader>
<CardTitle className="text-2xl font-bold text-primary">
</CardTitle>
<CardTitle className="text-2xl font-bold text-primary"></CardTitle>
</CardHeader>
<CardContent>
<div className="flex space-x-2 mb-4">
@ -131,69 +129,40 @@ export default function VideoSearch() {
{videos.length > 0 ? (
<ul className="space-y-8">
{videos.map((video) => {
const achievement = getAchievement(video.video_stat.view);
const achievement = getAchievement(video.video_stat.view)
return (
<li
key={video.video_id.bvid}
className="border p-6 rounded-lg bg-white shadow-md"
>
<li key={video.video_id.bvid} className="border p-6 rounded-lg bg-white shadow-md">
<div className="flex flex-col gap-6">
<div className="w-full">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={video.video_info.pic}
src={video.video_info.pic || "/placeholder.svg"}
className="w-full h-64 object-cover rounded-lg"
alt="视频封面"
></img>
</div>
<div className="w-full">
<h3 className="font-bold text-xl mb-2">
{video.video_info.title}
</h3>
<h3 className="font-bold text-xl mb-2">{video.video_info.title}</h3>
<p className="text-gray-600">
UP主: {video.video_info.uploader_name} (UID:{" "}
{video.video_info.uploader_mid})
</p>
<p className="text-gray-600">
BV号: {video.video_id.bvid}
</p>
<p className="text-gray-600">
AV号: {video.video_id.avid}
UP主: {video.video_info.uploader_name} (UID: {video.video_info.uploader_mid})
</p>
<p className="text-gray-600">BV号: {video.video_id.bvid}</p>
<p className="text-gray-600">AV号: {video.video_id.avid}</p>
<div className="mt-4 grid grid-cols-2 gap-2">
<p className="text-gray-600">
: {video.video_stat.view.toLocaleString()}
</p>
<p className="text-gray-600">
: {video.video_stat.like.toLocaleString()}
</p>
<p className="text-gray-600">
: {video.video_stat.coin.toLocaleString()}
</p>
<p className="text-gray-600">
: {video.video_stat.favorite.toLocaleString()}
</p>
<p className="text-gray-600">
: {video.video_stat.reply.toLocaleString()}
</p>
<p className="text-gray-600">
: {video.video_stat.share.toLocaleString()}
</p>
<p className="text-gray-600">
: {video.video_stat.danmaku.toLocaleString()}
</p>
<p className="text-gray-600">: {video.video_stat.view.toLocaleString()}</p>
<p className="text-gray-600">: {video.video_stat.like.toLocaleString()}</p>
<p className="text-gray-600">: {video.video_stat.coin.toLocaleString()}</p>
<p className="text-gray-600">: {video.video_stat.favorite.toLocaleString()}</p>
<p className="text-gray-600">: {video.video_stat.reply.toLocaleString()}</p>
<p className="text-gray-600">: {video.video_stat.share.toLocaleString()}</p>
<p className="text-gray-600">: {video.video_stat.danmaku.toLocaleString()}</p>
</div>
<div className="mt-4 bg-blue-100 p-4 rounded-lg">
<h4 className="font-bold text-lg mb-2"></h4>
{video.vrank_info ? (
<>
<p className="text-gray-700">
:{" "}
{video.vrank_info.vrank_score.toFixed(2)}
</p>
<p className="text-gray-700 font-bold text-xl">
: {video.score_rank}
</p>
<p className="text-gray-700">: {video.vrank_info.vrank_score.toFixed(2)}</p>
<p className="text-gray-700 font-bold text-xl">: {video.score_rank}</p>
</>
) : (
<p className="text-gray-700"></p>
@ -202,48 +171,24 @@ export default function VideoSearch() {
<>
<h5 className="font-semibold mt-2"></h5>
<div className="grid grid-cols-2 gap-2">
<p className="text-gray-700">: {video.video_increase.view.toLocaleString()}</p>
<p className="text-gray-700">: {video.video_increase.like.toLocaleString()}</p>
<p className="text-gray-700">: {video.video_increase.coin.toLocaleString()}</p>
<p className="text-gray-700">
:{" "}
{video.video_increase.view.toLocaleString()}
</p>
<p className="text-gray-700">
:{" "}
{video.video_increase.like.toLocaleString()}
</p>
<p className="text-gray-700">
:{" "}
{video.video_increase.coin.toLocaleString()}
</p>
<p className="text-gray-700">
:{" "}
{video.video_increase.favorite.toLocaleString()}
</p>
<p className="text-gray-700">
:{" "}
{video.video_increase.reply.toLocaleString()}
</p>
<p className="text-gray-700">
:{" "}
{video.video_increase.share.toLocaleString()}
</p>
<p className="text-gray-700">
:{" "}
{video.video_increase.danmaku.toLocaleString()}
: {video.video_increase.favorite.toLocaleString()}
</p>
<p className="text-gray-700">: {video.video_increase.reply.toLocaleString()}</p>
<p className="text-gray-700">: {video.video_increase.share.toLocaleString()}</p>
<p className="text-gray-700">: {video.video_increase.danmaku.toLocaleString()}</p>
</div>
</>
)}
</div>
<p className="text-gray-600 mt-2">
:{" "}
{new Date(
video.video_info.timestamp * 1000
).toLocaleString("zh-CN")}
: {new Date(video.video_info.timestamp * 1000).toLocaleString("zh-CN")}
</p>
<div className="mt-4">
<p className="font-semibold">
: {achievement.name}
</p>
<p className="font-semibold">: {achievement.name}</p>
{achievement.next && (
<div className="mt-2">
<p>
@ -251,8 +196,8 @@ export default function VideoSearch() {
{(achievement.next === "殿堂曲"
? 100000
: achievement.next === "传说曲"
? 1000000
: 10000000) - video.video_stat.view}{" "}
? 1000000
: 10000000) - video.video_stat.view}{" "}
</p>
<div className="w-full bg-gray-200 rounded-full h-2.5 mt-2">
@ -267,7 +212,7 @@ export default function VideoSearch() {
</div>
</div>
</li>
);
)
})}
</ul>
) : (
@ -275,5 +220,6 @@ export default function VideoSearch() {
)}
</CardContent>
</Card>
);
)
}