去广告增强

This commit is contained in:
mtvpls
2026-01-23 00:54:08 +08:00
parent 05ea826f54
commit ea0ebcd8ce
5 changed files with 114 additions and 54 deletions
+38 -5
View File
@@ -8429,18 +8429,51 @@ const CustomAdFilterConfig = ({
const defaultAdFilterCode = `function filterAdsFromM3U8(type: string, m3u8Content: string): string { const defaultAdFilterCode = `function filterAdsFromM3U8(type: string, m3u8Content: string): string {
if (!m3u8Content) return ''; if (!m3u8Content) return '';
// 广告关键字列表
const adKeywords = [
'sponsor',
'/ad/',
'/ads/',
'advert',
'advertisement',
'/adjump',
'redtraffic'
];
// 按行分割M3U8内容 // 按行分割M3U8内容
const lines = m3u8Content.split('\\n'); const lines = m3u8Content.split('\\n');
const filteredLines = []; const filteredLines = [];
let nextdelete = false; let i = 0;
for (let i = 0; i < lines.length; i++) { while (i < lines.length) {
const line = lines[i]; const line = lines[i];
// 只过滤#EXT-X-DISCONTINUITY标识 // 跳过 #EXT-X-DISCONTINUITY 标识
if (!line.includes('#EXT-X-DISCONTINUITY')) { if (line.includes('#EXT-X-DISCONTINUITY')) {
filteredLines.push(line); i++;
continue;
} }
// 如果是 EXTINF 行,检查下一行 URL 是否包含广告关键字
if (line.includes('#EXTINF:')) {
// 检查下一行 URL 是否包含广告关键字
if (i + 1 < lines.length) {
const nextLine = lines[i + 1];
const containsAdKeyword = adKeywords.some(keyword =>
nextLine.toLowerCase().includes(keyword.toLowerCase())
);
if (containsAdKeyword) {
// 跳过 EXTINF 行和 URL 行
i += 2;
continue;
}
}
}
// 保留当前行
filteredLines.push(line);
i++;
} }
return filteredLines.join('\\n'); return filteredLines.join('\\n');
+1
View File
@@ -3,6 +3,7 @@ import { NextResponse } from 'next/server';
import { getConfig } from '@/lib/config'; import { getConfig } from '@/lib/config';
export const runtime = 'nodejs'; export const runtime = 'nodejs';
export const dynamic = 'force-dynamic'; // 禁用缓存
/** /**
* GET /api/ad-filter * GET /api/ad-filter
+34 -20
View File
@@ -107,37 +107,51 @@ export async function GET(request: Request) {
function filterAdsFromM3U8Default(type: string, m3u8Content: string): string { function filterAdsFromM3U8Default(type: string, m3u8Content: string): string {
if (!m3u8Content) return ''; if (!m3u8Content) return '';
// 广告关键字列表
const adKeywords = [
'sponsor',
'/ad/',
'/ads/',
'advert',
'advertisement',
'/adjump',
'redtraffic'
];
// 按行分割M3U8内容 // 按行分割M3U8内容
const lines = m3u8Content.split('\n'); const lines = m3u8Content.split('\n');
const filteredLines = []; const filteredLines = [];
let nextdelete = false; let i = 0;
for (let i = 0; i < lines.length; i++) { while (i < lines.length) {
const line = lines[i]; const line = lines[i];
if (nextdelete) { // 跳过 #EXT-X-DISCONTINUITY 标识
nextdelete = false; if (line.includes('#EXT-X-DISCONTINUITY')) {
i++;
continue; continue;
} }
// 只过滤#EXT-X-DISCONTINUITY标识 // 如果是 EXTINF 行,检查下一行 URL 是否包含广告关键字
if (!line.includes('#EXT-X-DISCONTINUITY')) { if (line.includes('#EXTINF:')) {
if ( // 检查下一行 URL 是否包含广告关键字
type === 'ruyi' && if (i + 1 < lines.length) {
(line.includes('EXTINF:5.640000') || const nextLine = lines[i + 1];
line.includes('EXTINF:2.960000') || const containsAdKeyword = adKeywords.some(keyword =>
line.includes('EXTINF:3.480000') || nextLine.toLowerCase().includes(keyword.toLowerCase())
line.includes('EXTINF:4.000000') || );
line.includes('EXTINF:0.960000') ||
line.includes('EXTINF:10.000000') ||
line.includes('EXTINF:1.266667'))
) {
nextdelete = true;
continue;
}
filteredLines.push(line); if (containsAdKeyword) {
// 跳过 EXTINF 行和 URL 行
i += 2;
continue;
}
}
} }
// 保留当前行
filteredLines.push(line);
i++;
} }
return filteredLines.join('\n'); return filteredLines.join('\n');
+4
View File
@@ -84,6 +84,7 @@ export default async function RootLayout({
let aiDefaultMessageWithVideo = ''; let aiDefaultMessageWithVideo = '';
let enableMovieRequest = true; let enableMovieRequest = true;
let webLiveEnabled = false; let webLiveEnabled = false;
let customAdFilterVersion = 0;
let customCategories = [] as { let customCategories = [] as {
name: string; name: string;
type: 'movie' | 'tv'; type: 'movie' | 'tv';
@@ -130,6 +131,8 @@ export default async function RootLayout({
enableMovieRequest = config.SiteConfig.EnableMovieRequest ?? true; enableMovieRequest = config.SiteConfig.EnableMovieRequest ?? true;
// 网络直播功能配置 // 网络直播功能配置
webLiveEnabled = config.WebLiveEnabled ?? false; webLiveEnabled = config.WebLiveEnabled ?? false;
// 自定义去广告代码版本号
customAdFilterVersion = config.SiteConfig?.CustomAdFilterVersion || 0;
// 检查是否启用了 OpenList 功能 // 检查是否启用了 OpenList 功能
openListEnabled = !!( openListEnabled = !!(
config.OpenListConfig?.Enabled && config.OpenListConfig?.Enabled &&
@@ -186,6 +189,7 @@ export default async function RootLayout({
AI_DEFAULT_MESSAGE_WITH_VIDEO: aiDefaultMessageWithVideo, AI_DEFAULT_MESSAGE_WITH_VIDEO: aiDefaultMessageWithVideo,
ENABLE_MOVIE_REQUEST: enableMovieRequest, ENABLE_MOVIE_REQUEST: enableMovieRequest,
WEB_LIVE_ENABLED: webLiveEnabled, WEB_LIVE_ENABLED: webLiveEnabled,
CUSTOM_AD_FILTER_VERSION: customAdFilterVersion,
}; };
return ( return (
+37 -29
View File
@@ -245,14 +245,8 @@ function PlayPageClient() {
console.log('使用缓存的去广告代码'); console.log('使用缓存的去广告代码');
} }
// 第一步:先只获取版本号,检查是否需要更新 // 从 window.RUNTIME_CONFIG 获取版本号
const versionResponse = await fetch('/api/ad-filter'); const version = (window as any).RUNTIME_CONFIG?.CUSTOM_AD_FILTER_VERSION || 0;
if (!versionResponse.ok) {
console.warn('获取去广告代码版本失败,使用缓存');
return;
}
const { version } = await versionResponse.json();
// 如果版本号为 0,说明去广告未设置,清空缓存并跳过 // 如果版本号为 0,说明去广告未设置,清空缓存并跳过
if (version === 0) { if (version === 0) {
@@ -267,7 +261,7 @@ function PlayPageClient() {
if (!cachedVersion || parseInt(cachedVersion) !== version) { if (!cachedVersion || parseInt(cachedVersion) !== version) {
console.log('检测到去广告代码更新(版本 ' + version + '),获取最新代码'); console.log('检测到去广告代码更新(版本 ' + version + '),获取最新代码');
// 第二步:获取完整代码 // 获取完整代码
const fullResponse = await fetch('/api/ad-filter?full=true'); const fullResponse = await fetch('/api/ad-filter?full=true');
if (!fullResponse.ok) { if (!fullResponse.ok) {
console.warn('获取完整去广告代码失败,使用缓存'); console.warn('获取完整去广告代码失败,使用缓存');
@@ -2499,37 +2493,51 @@ function PlayPageClient() {
// 默认去广告规则 // 默认去广告规则
if (!m3u8Content) return ''; if (!m3u8Content) return '';
// 广告关键字列表
const adKeywords = [
'sponsor',
'/ad/',
'/ads/',
'advert',
'advertisement',
'/adjump',
'redtraffic'
];
// 按行分割M3U8内容 // 按行分割M3U8内容
const lines = m3u8Content.split('\n'); const lines = m3u8Content.split('\n');
const filteredLines = []; const filteredLines = [];
let nextdelete = false; let i = 0;
for (let i = 0; i < lines.length; i++) { while (i < lines.length) {
const line = lines[i]; const line = lines[i];
if (nextdelete) { // 跳过 #EXT-X-DISCONTINUITY 标识
nextdelete = false; if (line.includes('#EXT-X-DISCONTINUITY')) {
i++;
continue; continue;
} }
// 只过滤#EXT-X-DISCONTINUITY标识 // 如果是 EXTINF 行,检查下一行 URL 是否包含广告关键字
if (!line.includes('#EXT-X-DISCONTINUITY')) { if (line.includes('#EXTINF:')) {
if ( // 检查下一行 URL 是否包含广告关键字
type == 'ruyi' && if (i + 1 < lines.length) {
(line.includes('EXTINF:5.640000') || const nextLine = lines[i + 1];
line.includes('EXTINF:2.960000') || const containsAdKeyword = adKeywords.some(keyword =>
line.includes('EXTINF:3.480000') || nextLine.toLowerCase().includes(keyword.toLowerCase())
line.includes('EXTINF:4.000000') || );
line.includes('EXTINF:0.960000') ||
line.includes('EXTINF:10.000000') ||
line.includes('EXTINF:1.266667'))
) {
nextdelete = true;
continue;
}
filteredLines.push(line); if (containsAdKeyword) {
// 跳过 EXTINF 行和 URL 行
i += 2;
continue;
}
}
} }
// 保留当前行
filteredLines.push(line);
i++;
} }
return filteredLines.join('\n'); return filteredLines.join('\n');