mirror of
https://gh-proxy.org/https://github.com/tiajinsha/JKVideo
synced 2026-07-08 07:28:37 +08:00
本项目已收到哔哩哔哩(bilibili)律师函,要求停止对 B 站 API 的调用及相关仿制行为。
为尊重知识产权及相关法律法规,本仓库即日起停止后续维护与更新,不再接受新的 Issue 和 Pull Request。 现有代码仅作学习参考保留,请勿将本项目用于任何商业或违法用途。 感谢所有支持过本项目的朋友。
This commit is contained in:
68
hooks/useFollow.ts
Normal file
68
hooks/useFollow.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { getRelation, modifyRelation } from "../services/bilibili";
|
||||
import { useAuthStore } from "../store/authStore";
|
||||
import { getSecure } from "../utils/secureStorage";
|
||||
import { toast } from "../utils/toast";
|
||||
|
||||
/**
|
||||
* 关注 / 取消关注 UP 主。
|
||||
* - 未登录:toggle 时 toast 提示,按钮 disabled=false 仍允许点击
|
||||
* - 已登录但无 bili_jct:toggle 时 toast 提示让用户重登
|
||||
* - 正常路径:乐观更新 UI,请求失败回滚
|
||||
*/
|
||||
export function useFollow(mid: number | undefined) {
|
||||
const isLoggedIn = useAuthStore((s) => s.isLoggedIn);
|
||||
const [following, setFollowing] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const inflightRef = useRef(false);
|
||||
|
||||
// 首次拉取 / mid 切换时刷新关注状态
|
||||
useEffect(() => {
|
||||
if (!mid || !isLoggedIn) {
|
||||
setFollowing(false);
|
||||
return;
|
||||
}
|
||||
let cancelled = false;
|
||||
getRelation(mid)
|
||||
.then((r) => {
|
||||
if (!cancelled) setFollowing(r.following);
|
||||
})
|
||||
.catch(() => {});
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [mid, isLoggedIn]);
|
||||
|
||||
const toggle = useCallback(async () => {
|
||||
if (!mid) return;
|
||||
if (!isLoggedIn) {
|
||||
toast("请先登录后再关注");
|
||||
return;
|
||||
}
|
||||
const biliJct = await getSecure("bili_jct");
|
||||
if (!biliJct) {
|
||||
toast("请重新登录后再使用关注功能");
|
||||
return;
|
||||
}
|
||||
if (inflightRef.current) return;
|
||||
inflightRef.current = true;
|
||||
setLoading(true);
|
||||
const next = !following;
|
||||
setFollowing(next); // 乐观更新
|
||||
try {
|
||||
await modifyRelation(mid, next ? 1 : 2);
|
||||
} catch (e: any) {
|
||||
setFollowing(!next); // 失败回滚
|
||||
if (e?.message === "NO_CSRF") {
|
||||
toast("请重新登录后再使用关注功能");
|
||||
} else {
|
||||
toast(`操作失败:${e?.message || "未知错误"}`);
|
||||
}
|
||||
} finally {
|
||||
inflightRef.current = false;
|
||||
setLoading(false);
|
||||
}
|
||||
}, [mid, isLoggedIn, following]);
|
||||
|
||||
return { following, loading, toggle };
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState, useCallback, useRef } from 'react';
|
||||
import { useState, useCallback, useEffect, useRef } from 'react';
|
||||
import { getVideoRelated } from '../services/bilibili';
|
||||
import type { VideoItem } from '../services/types';
|
||||
|
||||
@@ -7,6 +7,11 @@ export function useRelatedVideos(bvid: string) {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const loadingRef = useRef(false);
|
||||
|
||||
// 切到不同 bvid 时立刻清空,避免新页面短暂显示上一支视频的推荐流
|
||||
useEffect(() => {
|
||||
setVideos([]);
|
||||
}, [bvid]);
|
||||
|
||||
const load = useCallback(async () => {
|
||||
if (loadingRef.current) return;
|
||||
loadingRef.current = true;
|
||||
|
||||
@@ -37,6 +37,12 @@ export function useVideoDetail(bvid: string) {
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
// bvid 切换时立刻清空旧数据,防止上一支视频的播放器/简介/清晰度短暂"残影"造成抖动
|
||||
setVideo(null);
|
||||
setPlayData(null);
|
||||
setQualities([]);
|
||||
setCurrentQn(0);
|
||||
cidRef.current = 0;
|
||||
async function fetchData() {
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
Reference in New Issue
Block a user