优化自定义去广告接口

This commit is contained in:
mtvpls
2025-12-05 12:41:14 +08:00
parent 81588443f1
commit 32d2800e25
4 changed files with 162 additions and 136 deletions
+20 -7
View File
@@ -7,17 +7,30 @@ export const runtime = 'nodejs';
/** /**
* GET /api/ad-filter * GET /api/ad-filter
* 获取自定义去广告代码配置(公开接口,无需认证) * 获取自定义去广告代码配置(公开接口,无需认证)
* 返回代码内容和版本号,客户端通过版本号判断是否需要更新缓存 * 支持两种模式:
* - 不带参数:只返回版本号,用于检查更新
* - ?full=true:返回完整代码和版本号
*/ */
export async function GET() { export async function GET(request: Request) {
try { try {
const config = await getConfig(); const config = await getConfig();
const { searchParams } = new URL(request.url);
const full = searchParams.get('full') === 'true';
// 返回自定义去广告代码和版本号 const version = config.SiteConfig?.CustomAdFilterVersion || 0;
return NextResponse.json({
code: config.SiteConfig?.CustomAdFilterCode || '', if (full) {
version: config.SiteConfig?.CustomAdFilterVersion || 0, // 返回完整代码和版本号
}); return NextResponse.json({
code: config.SiteConfig?.CustomAdFilterCode || '',
version,
});
} else {
// 只返回版本号
return NextResponse.json({
version,
});
}
} catch (error) { } catch (error) {
console.error('获取去广告代码配置失败:', error); console.error('获取去广告代码配置失败:', error);
return NextResponse.json( return NextResponse.json(
+24 -24
View File
@@ -232,7 +232,7 @@ function DoubanPageClient() {
snapshot1.selectedWeekday === snapshot2.selectedWeekday && snapshot1.selectedWeekday === snapshot2.selectedWeekday &&
snapshot1.currentPage === snapshot2.currentPage && snapshot1.currentPage === snapshot2.currentPage &&
JSON.stringify(snapshot1.multiLevelSelection) === JSON.stringify(snapshot1.multiLevelSelection) ===
JSON.stringify(snapshot2.multiLevelSelection) JSON.stringify(snapshot2.multiLevelSelection)
); );
}, },
[] []
@@ -715,12 +715,12 @@ function DoubanPageClient() {
return type === 'movie' return type === 'movie'
? '电影' ? '电影'
: type === 'tv' : type === 'tv'
? '电视剧' ? '电视剧'
: type === 'anime' : type === 'anime'
? '动漫' ? '动漫'
: type === 'show' : type === 'show'
? '综艺' ? '综艺'
: '自定义'; : '自定义';
}; };
const getPageDescription = () => { const getPageDescription = () => {
@@ -786,24 +786,24 @@ function DoubanPageClient() {
<div className='justify-start grid grid-cols-3 gap-x-2 gap-y-12 px-0 sm:px-2 sm:grid-cols-[repeat(auto-fill,minmax(160px,1fr))] sm:gap-x-8 sm:gap-y-20'> <div className='justify-start grid grid-cols-3 gap-x-2 gap-y-12 px-0 sm:px-2 sm:grid-cols-[repeat(auto-fill,minmax(160px,1fr))] sm:gap-x-8 sm:gap-y-20'>
{loading || !selectorsReady {loading || !selectorsReady
? // 显示骨架屏 ? // 显示骨架屏
skeletonData.map((index) => <DoubanCardSkeleton key={index} />) skeletonData.map((index) => <DoubanCardSkeleton key={index} />)
: // 显示实际数据 : // 显示实际数据
doubanData.map((item, index) => ( doubanData.map((item, index) => (
<div key={`${item.title}-${index}`} className='w-full'> <div key={`${item.title}-${index}`} className='w-full'>
<VideoCard <VideoCard
from='douban' from='douban'
title={item.title} title={item.title}
poster={item.poster} poster={item.poster}
douban_id={Number(item.id)} douban_id={Number(item.id)}
rate={item.rate} rate={item.rate}
year={item.year} year={item.year}
type={type === 'movie' ? 'movie' : ''} // 电影类型严格控制,tv 不控 type={type === 'movie' ? 'movie' : ''} // 电影类型严格控制,tv 不控
isBangumi={ isBangumi={
type === 'anime' && primarySelection === '每日放送' type === 'anime' && primarySelection === '每日放送'
} }
/> />
</div> </div>
))} ))}
</div> </div>
{/* 加载更多指示器 */} {/* 加载更多指示器 */}
+100 -97
View File
@@ -110,36 +110,39 @@ function HomeClient() {
}, []); }, []);
// 处理收藏数据更新的函数 // 处理收藏数据更新的函数
const updateFavoriteItems = useCallback(async (allFavorites: Record<string, any>) => { const updateFavoriteItems = useCallback(
const allPlayRecords = await getAllPlayRecords(); async (allFavorites: Record<string, any>) => {
const allPlayRecords = await getAllPlayRecords();
// 根据保存时间排序(从近到远) // 根据保存时间排序(从近到远)
const sorted = Object.entries(allFavorites) const sorted = Object.entries(allFavorites)
.sort(([, a], [, b]) => b.save_time - a.save_time) .sort(([, a], [, b]) => b.save_time - a.save_time)
.map(([key, fav]) => { .map(([key, fav]) => {
const plusIndex = key.indexOf('+'); const plusIndex = key.indexOf('+');
const source = key.slice(0, plusIndex); const source = key.slice(0, plusIndex);
const id = key.slice(plusIndex + 1); const id = key.slice(plusIndex + 1);
// 查找对应的播放记录,获取当前集数 // 查找对应的播放记录,获取当前集数
const playRecord = allPlayRecords[key]; const playRecord = allPlayRecords[key];
const currentEpisode = playRecord?.index; const currentEpisode = playRecord?.index;
return { return {
id, id,
source, source,
title: fav.title, title: fav.title,
year: fav.year, year: fav.year,
poster: fav.cover, poster: fav.cover,
episodes: fav.total_episodes, episodes: fav.total_episodes,
source_name: fav.source_name, source_name: fav.source_name,
currentEpisode, currentEpisode,
search_title: fav?.search_title, search_title: fav?.search_title,
origin: fav?.origin, origin: fav?.origin,
} as FavoriteItem; } as FavoriteItem;
}); });
setFavoriteItems(sorted); setFavoriteItems(sorted);
}, []); },
[]
);
// 当切换到收藏夹时加载收藏数据(使用 ref 防止重复加载) // 当切换到收藏夹时加载收藏数据(使用 ref 防止重复加载)
useEffect(() => { useEffect(() => {
@@ -256,30 +259,30 @@ function HomeClient() {
<ScrollableRow> <ScrollableRow>
{loading {loading
? // 加载状态显示灰色占位数据 ? // 加载状态显示灰色占位数据
Array.from({ length: 8 }).map((_, index) => ( Array.from({ length: 8 }).map((_, index) => (
<div <div
key={index} key={index}
className='min-w-[96px] w-24 sm:min-w-[180px] sm:w-44' className='min-w-[96px] w-24 sm:min-w-[180px] sm:w-44'
> >
<div className='aspect-[2/3] bg-gray-200 dark:bg-gray-700 rounded-lg animate-pulse mb-2' /> <div className='aspect-[2/3] bg-gray-200 dark:bg-gray-700 rounded-lg animate-pulse mb-2' />
<div className='h-4 bg-gray-200 dark:bg-gray-700 rounded animate-pulse w-3/4' /> <div className='h-4 bg-gray-200 dark:bg-gray-700 rounded animate-pulse w-3/4' />
</div> </div>
)) ))
: hotMovies.map((movie) => ( : hotMovies.map((movie) => (
<div <div
key={movie.id} key={movie.id}
className='min-w-[96px] w-24 sm:min-w-[180px] sm:w-44' className='min-w-[96px] w-24 sm:min-w-[180px] sm:w-44'
> >
<VideoCard <VideoCard
id={movie.id} id={movie.id}
poster={movie.poster} poster={movie.poster}
title={movie.title} title={movie.title}
year={movie.year} year={movie.year}
type='movie' type='movie'
from='douban' from='douban'
/> />
</div> </div>
))} ))}
</ScrollableRow> </ScrollableRow>
</section> </section>
@@ -300,29 +303,29 @@ function HomeClient() {
<ScrollableRow> <ScrollableRow>
{loading {loading
? Array.from({ length: 8 }).map((_, index) => ( ? Array.from({ length: 8 }).map((_, index) => (
<div <div
key={index} key={index}
className='min-w-[96px] w-24 sm:min-w-[180px] sm:w-44' className='min-w-[96px] w-24 sm:min-w-[180px] sm:w-44'
> >
<div className='aspect-[2/3] bg-gray-200 dark:bg-gray-700 rounded-lg animate-pulse mb-2' /> <div className='aspect-[2/3] bg-gray-200 dark:bg-gray-700 rounded-lg animate-pulse mb-2' />
<div className='h-4 bg-gray-200 dark:bg-gray-700 rounded animate-pulse w-3/4' /> <div className='h-4 bg-gray-200 dark:bg-gray-700 rounded animate-pulse w-3/4' />
</div> </div>
)) ))
: hotTvShows.map((tvShow) => ( : hotTvShows.map((tvShow) => (
<div <div
key={tvShow.id} key={tvShow.id}
className='min-w-[96px] w-24 sm:min-w-[180px] sm:w-44' className='min-w-[96px] w-24 sm:min-w-[180px] sm:w-44'
> >
<VideoCard <VideoCard
id={tvShow.id} id={tvShow.id}
poster={tvShow.poster} poster={tvShow.poster}
title={tvShow.title} title={tvShow.title}
year={tvShow.year} year={tvShow.year}
type='tv' type='tv'
from='douban' from='douban'
/> />
</div> </div>
))} ))}
</ScrollableRow> </ScrollableRow>
</section> </section>
@@ -343,29 +346,29 @@ function HomeClient() {
<ScrollableRow> <ScrollableRow>
{loading {loading
? Array.from({ length: 8 }).map((_, index) => ( ? Array.from({ length: 8 }).map((_, index) => (
<div <div
key={index} key={index}
className='min-w-[96px] w-24 sm:min-w-[180px] sm:w-44' className='min-w-[96px] w-24 sm:min-w-[180px] sm:w-44'
> >
<div className='aspect-[2/3] bg-gray-200 dark:bg-gray-700 rounded-lg animate-pulse mb-2' /> <div className='aspect-[2/3] bg-gray-200 dark:bg-gray-700 rounded-lg animate-pulse mb-2' />
<div className='h-4 bg-gray-200 dark:bg-gray-700 rounded animate-pulse w-3/4' /> <div className='h-4 bg-gray-200 dark:bg-gray-700 rounded animate-pulse w-3/4' />
</div> </div>
)) ))
: hotVarietyShows.map((varietyShow) => ( : hotVarietyShows.map((varietyShow) => (
<div <div
key={varietyShow.id} key={varietyShow.id}
className='min-w-[96px] w-24 sm:min-w-[180px] sm:w-44' className='min-w-[96px] w-24 sm:min-w-[180px] sm:w-44'
> >
<VideoCard <VideoCard
id={varietyShow.id} id={varietyShow.id}
poster={varietyShow.poster} poster={varietyShow.poster}
title={varietyShow.title} title={varietyShow.title}
year={varietyShow.year} year={varietyShow.year}
type='tv' type='tv'
from='douban' from='douban'
/> />
</div> </div>
))} ))}
</ScrollableRow> </ScrollableRow>
</section> </section>
@@ -414,9 +417,9 @@ function HomeClient() {
// 找到当前星期对应的番剧数据,并过滤掉没有图片的 // 找到当前星期对应的番剧数据,并过滤掉没有图片的
const todayAnimes = const todayAnimes =
bangumiCalendarData.find( bangumiCalendarData
(item) => item.weekday.en === currentWeekday .find((item) => item.weekday.en === currentWeekday)
)?.items.filter((anime) => anime.images) || []; ?.items.filter((anime) => anime.images) || [];
return todayAnimes.map((anime, index) => ( return todayAnimes.map((anime, index) => (
<div <div
+18 -8
View File
@@ -130,18 +130,28 @@ function PlayPageClient() {
console.log('使用缓存的去广告代码'); console.log('使用缓存的去广告代码');
} }
// 异步从服务器获取最新版本号,检查是否需要更新 // 第一步:先只获取版本号,检查是否需要更新
const response = await fetch('/api/ad-filter'); const versionResponse = await fetch('/api/ad-filter');
if (!response.ok) { if (!versionResponse.ok) {
console.warn('获取去广告代码配置失败,使用缓存'); console.warn('获取去广告代码版本失败,使用缓存');
return; return;
} }
const { code, version } = await response.json(); const { version } = await versionResponse.json();
// 如果版本号不一致或没有缓存,更新缓存 // 如果版本号不一致或没有缓存,才获取完整代码
if (!cachedVersion || parseInt(cachedVersion) !== version) { if (!cachedVersion || parseInt(cachedVersion) !== version) {
console.log('检测到去广告代码更新,更新本地缓存'); console.log('检测到去广告代码更新(版本 ' + version + '),获取最新代码');
// 第二步:获取完整代码
const fullResponse = await fetch('/api/ad-filter?full=true');
if (!fullResponse.ok) {
console.warn('获取完整去广告代码失败,使用缓存');
return;
}
const { code } = await fullResponse.json();
if (code) { if (code) {
localStorage.setItem('custom_ad_filter_code_cache', code); localStorage.setItem('custom_ad_filter_code_cache', code);
localStorage.setItem('custom_ad_filter_version_cache', version.toString()); localStorage.setItem('custom_ad_filter_version_cache', version.toString());
@@ -152,7 +162,7 @@ function PlayPageClient() {
localStorage.removeItem('custom_ad_filter_version_cache'); localStorage.removeItem('custom_ad_filter_version_cache');
} }
} else { } else {
console.log('去广告代码已是最新版本'); console.log('去广告代码已是最新版本(版本 ' + version + '');
} }
} catch (error) { } catch (error) {
console.error('获取去广告代码配置失败:', error); console.error('获取去广告代码配置失败:', error);