diff --git a/app/blocked/page.tsx b/app/blocked/page.tsx new file mode 100644 index 0000000..733138d --- /dev/null +++ b/app/blocked/page.tsx @@ -0,0 +1,43 @@ +"use client" + +import { useEffect, useState } from "react" +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" +import Link from "next/link" + +export default function BlockedPage() { + const [countdown, setCountdown] = useState(3) + + useEffect(() => { + const timer = setInterval(() => { + setCountdown((prev) => prev - 1) + }, 1000) + + const redirect = setTimeout(() => { + window.location.href = "https://www.bilibili.com/video/BV1kW411m7VP" + }, 3000) + + return () => { + clearInterval(timer) + clearTimeout(redirect) + } + }, []) + + return ( +
+ + + 访问被禁止 + + +

抱歉,您尝试访问的内容已被禁止。这可能是由于版权、隐私或其他法律原因。

+

如果您认为这是一个错误,请联系网站管理员。

+

{countdown} 秒后将自动跳转...

+ + 返回首页 + +
+
+
+ ) +} + diff --git a/components/uploader-search.tsx b/components/uploader-search.tsx index 2901d2a..a518ecc 100644 --- a/components/uploader-search.tsx +++ b/components/uploader-search.tsx @@ -1,10 +1,12 @@ "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 { blockedUploaderIds } from "@/config/blocked-ids" interface Uploader { mid: string @@ -19,6 +21,7 @@ export default function UploaderSearch() { const [uploaders, setUploaders] = useState([]) const [loading, setLoading] = useState(false) const [error, setError] = useState(null) + const router = useRouter() const handleSearch = async () => { if (!uid) { @@ -26,15 +29,21 @@ export default function UploaderSearch() { return } + // 检查是否为禁止的 UP 主 ID + if (blockedUploaderIds.includes(uid)) { + router.push("/blocked") + return + } + setLoading(true) setError(null) try { - const response = await fetch(`https://ecs-113-44-166-103.compute.hwclouds-dns.com/basic/v1/uploader/${uid}`) + const response = await fetch(`https://api.ninevocalrank.top/basic/v1/uploader/${uid}`) if (!response.ok) { throw new Error("服务器响应错误") } const data: Uploader = await response.json() - setUploaders([data]) // 将单个 UP 主数据包装在数组中 + setUploaders([data]) } catch (error) { console.error("搜索UP主时出错:", error) setError("搜索过程中出现错误") diff --git a/components/video-search.tsx b/components/video-search.tsx index 986623c..5daf8f9 100644 --- a/components/video-search.tsx +++ b/components/video-search.tsx @@ -1,141 +1,125 @@ -"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 { -// Dialog, -// DialogContent, -// DialogDescription, -// DialogHeader, -// DialogTitle, -// DialogFooter, -// } from "@/components/ui/dialog"; +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; - }; + 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([]); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(null); - // const [showCoverDialog, setShowCoverDialog] = useState(false); - // const [confirmText, setConfirmText] = useState(""); - // const [showCover, setShowCover] = useState(false); + 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) { - setError("请输入搜索内容"); - return; + setError("请输入搜索内容") + return } - setLoading(true); - setError(null); + // 检查是否为禁止的视频 ID + if (blockedVideoIds.includes(searchTerm)) { + router.push("/blocked") + return + } + + setLoading(true) + setError(null) try { const response = await fetch( - `https://ecs-113-44-166-103.compute.hwclouds-dns.com/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://ecs-113-44-166-103.compute.hwclouds-dns.com/vocaloid_rank/v1/sorted/${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() const combinedData = { ...data, score_rank: weekly_data.score_rank, - }; + } - setVideos([combinedData]); - // setShowCover(false); + setVideos([combinedData]) if (videos.length === 0) { - setError("未找到匹配的视频"); + setError("未找到匹配的视频") } } catch (error) { - console.error("搜索视频时出错:", error); - setError("搜索过程中出现错误"); + console.error("搜索视频时出错:", error) + setError("搜索过程中出现错误") } finally { - setLoading(false); + setLoading(false) } - }; - - // const handleShowCover = () => { - // setShowCoverDialog(true); - // }; - - // const handleConfirmShowCover = () => { - // if (confirmText === "我已知晓") { - // setShowCover(true); - // setShowCoverDialog(false); - // } - // }; + } return ( - - 搜索视频 - + 搜索视频
@@ -153,74 +137,32 @@ export default function VideoSearch() { {videos.length > 0 ? (
    {videos.map((video) => { - const achievement = getAchievement(video.video_stat.view); + const achievement = getAchievement(video.video_stat.view) return ( -
  • +
  • - {/* 此功能可能引发版权纠纷,不再使用 */} - {/*
    - {showCover ? ( - // eslint-disable-next-line @next/next/no-img-element - 视频封面 - ) : ( - - )} -
    */}
    -

    - {video.video_info.title} -

    +

    {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} + 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.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.vrank_info.vrank_score.toFixed(2)}

    +

    周刊排名: {video.score_rank}

    ) : (

    暂无周刊数据

    @@ -229,48 +171,24 @@ export default function VideoSearch() { <>
    数据增长:
    +

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

    +

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

    +

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

    - 播放增长:{" "} - {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()} + 收藏增长: {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")} + 数据更新时间: {new Date(video.video_info.timestamp * 1000).toLocaleString("zh-CN")}

    -

    - 成就: {achievement.name} -

    +

    成就: {achievement.name}

    {achievement.next && (

    @@ -278,8 +196,8 @@ export default function VideoSearch() { {(achievement.next === "殿堂曲" ? 100000 : achievement.next === "传说曲" - ? 1000000 - : 10000000) - video.video_stat.view}{" "} + ? 1000000 + : 10000000) - video.video_stat.view}{" "} 播放

    @@ -294,52 +212,14 @@ export default function VideoSearch() {
  • - ); + ) })}
) : ( !loading && !error &&

暂无数据

)} - {/* - - - 确认显示封面 - - 本站依法通过哔哩哔哩开放平台API获取内容引用,相关内容展示严格遵循《信息网络传播权保护条例》关于合理使用的规定。引用内容著作权归属著作权人及哔哩哔哩平台所有,本站不享有任何著作权权益。用户应知悉: -
    -
  • - 本站引用行为不替代对原内容的访问,建议通过 - 哔哩哔哩官方链接 - 获取完整服务 -
  • -
  • - 任何单位或个人认为引用涉嫌侵权,请通过 i@mei.lv - 提交权属证明,本站将依法处理 -
  • -
  • - 内容展示受哔哩哔哩《开发者协议》约束,若接口服务终止将即时停止引用 -
  • -
  • 本站对引用内容不享有解释权,观点分歧请以原发布渠道为准
  • -
  • - 用户不得对引用内容进行下载、转载、改编等二次使用,相关行为需直接获得权利人授权 -
  • -
- 显示的内容仅用于介绍目的,实时引用自哔哩哔哩。除另有说明外,所有权利归著作权人所有,内容不代表本站观点,本站亦非这些内容的著作权人。 -
-
-
- setConfirmText(e.target.value)} - /> -
- - - -
-
*/} - ); + ) } + diff --git a/config/blocked-ids.ts b/config/blocked-ids.ts new file mode 100644 index 0000000..0498367 --- /dev/null +++ b/config/blocked-ids.ts @@ -0,0 +1,30 @@ +// tsy 过滤器 +export const blockedVideoIds = [ + "BV1Nmp4eKE5H", + "BV1M5fDYkEGB", + "BV1hqykY9E72", + "BV1LHU9YuEqm", + "BV1AtidYfES6", + "BV1TLkVYbEsS", + "BV1iE421w7B6", + "BV1mdW8enEdh", + "BV1m9cbepErC", + "BV1Xpr6YyErN", + "BV1PAFWeFE3f", + "BV1wYwTeHEEW", + "BV1cMSUYiE5m", + "BV157yLYXEZN", + "BV1h2tue6EbD", + "BV1MSYMeEEZS", + "BV1Nmp4eKE5H", + "BV1zBY2euEA4", + "BV1bStreZEMr", + "BV1dt2eYyE86", + "BV1M8411R75Z", + ] + + export const blockedUploaderIds = [ + "1037289255", + "823284" + ] +