feat: disable flv live
This commit is contained in:
@@ -32,7 +32,6 @@
|
||||
"bs58": "^6.0.0",
|
||||
"clsx": "^2.0.0",
|
||||
"crypto-js": "^4.2.0",
|
||||
"flv.js": "^1.6.2",
|
||||
"framer-motion": "^12.18.1",
|
||||
"he": "^1.2.0",
|
||||
"hls.js": "^1.6.10",
|
||||
|
||||
37
pnpm-lock.yaml
generated
37
pnpm-lock.yaml
generated
@@ -47,9 +47,6 @@ importers:
|
||||
crypto-js:
|
||||
specifier: ^4.2.0
|
||||
version: 4.2.0
|
||||
flv.js:
|
||||
specifier: ^1.6.2
|
||||
version: 1.6.2
|
||||
framer-motion:
|
||||
specifier: ^12.18.1
|
||||
version: 12.18.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
@@ -2630,9 +2627,6 @@ packages:
|
||||
es6-object-assign@1.1.0:
|
||||
resolution: {integrity: sha512-MEl9uirslVwqQU369iHNWZXsI8yaZYGg/D65aOgZkeyFJwHYSxilf7rQzXKI7DdDuBPrBXbfk3sl9hJhmd5AUw==}
|
||||
|
||||
es6-promise@4.2.8:
|
||||
resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==}
|
||||
|
||||
escalade@3.2.0:
|
||||
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
|
||||
engines: {node: '>=6'}
|
||||
@@ -2887,9 +2881,6 @@ packages:
|
||||
flatted@3.3.3:
|
||||
resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==}
|
||||
|
||||
flv.js@1.6.2:
|
||||
resolution: {integrity: sha512-xre4gUbX1MPtgQRKj2pxJENp/RnaHaxYvy3YToVVCrSmAWUu85b9mug6pTXF6zakUjNP2lFWZ1rkSX7gxhB/2A==}
|
||||
|
||||
for-each@0.3.5:
|
||||
resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -5133,9 +5124,6 @@ packages:
|
||||
webpack-cli:
|
||||
optional: true
|
||||
|
||||
webworkify-webpack@2.1.5:
|
||||
resolution: {integrity: sha512-2akF8FIyUvbiBBdD+RoHpoTbHMQF2HwjcxfDvgztAX5YwbZNyrtfUMgvfgFVsgDhDPVTlkbb5vyasqDHfIDPQw==}
|
||||
|
||||
whatwg-encoding@1.0.5:
|
||||
resolution: {integrity: sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==}
|
||||
|
||||
@@ -8210,8 +8198,6 @@ snapshots:
|
||||
|
||||
es6-object-assign@1.1.0: {}
|
||||
|
||||
es6-promise@4.2.8: {}
|
||||
|
||||
escalade@3.2.0: {}
|
||||
|
||||
escape-string-regexp@2.0.0: {}
|
||||
@@ -8234,8 +8220,8 @@ snapshots:
|
||||
'@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@4.9.5)
|
||||
eslint: 8.57.1
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0)(eslint@8.57.1)
|
||||
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.9.5))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1)
|
||||
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.9.5))(eslint@8.57.1))(eslint@8.57.1)
|
||||
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.9.5))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.9.5))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1)
|
||||
eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1)
|
||||
eslint-plugin-react: 7.37.5(eslint@8.57.1)
|
||||
eslint-plugin-react-hooks: 5.0.0-canary-7118f5dd7-20230705(eslint@8.57.1)
|
||||
@@ -8258,7 +8244,7 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0)(eslint@8.57.1):
|
||||
eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.9.5))(eslint@8.57.1))(eslint@8.57.1):
|
||||
dependencies:
|
||||
'@nolyfill/is-core-module': 1.0.39
|
||||
debug: 4.4.1(supports-color@9.4.0)
|
||||
@@ -8269,22 +8255,22 @@ snapshots:
|
||||
tinyglobby: 0.2.14
|
||||
unrs-resolver: 1.9.0
|
||||
optionalDependencies:
|
||||
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.9.5))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1)
|
||||
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.9.5))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.9.5))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.9.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1):
|
||||
eslint-module-utils@2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.9.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.9.5))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1):
|
||||
dependencies:
|
||||
debug: 3.2.7
|
||||
optionalDependencies:
|
||||
'@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@4.9.5)
|
||||
eslint: 8.57.1
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0)(eslint@8.57.1)
|
||||
eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.9.5))(eslint@8.57.1))(eslint@8.57.1)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.9.5))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1):
|
||||
eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.9.5))(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.9.5))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1):
|
||||
dependencies:
|
||||
'@rtsao/scc': 1.1.0
|
||||
array-includes: 3.1.9
|
||||
@@ -8295,7 +8281,7 @@ snapshots:
|
||||
doctrine: 2.1.0
|
||||
eslint: 8.57.1
|
||||
eslint-import-resolver-node: 0.3.9
|
||||
eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.9.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1)
|
||||
eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.9.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.31.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.9.5))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1)
|
||||
hasown: 2.0.2
|
||||
is-core-module: 2.16.1
|
||||
is-glob: 4.0.3
|
||||
@@ -8553,11 +8539,6 @@ snapshots:
|
||||
|
||||
flatted@3.3.3: {}
|
||||
|
||||
flv.js@1.6.2:
|
||||
dependencies:
|
||||
es6-promise: 4.2.8
|
||||
webworkify-webpack: 2.1.5
|
||||
|
||||
for-each@0.3.5:
|
||||
dependencies:
|
||||
is-callable: 1.2.7
|
||||
@@ -11146,8 +11127,6 @@ snapshots:
|
||||
- esbuild
|
||||
- uglify-js
|
||||
|
||||
webworkify-webpack@2.1.5: {}
|
||||
|
||||
whatwg-encoding@1.0.5:
|
||||
dependencies:
|
||||
iconv-lite: 0.4.24
|
||||
|
||||
@@ -35,6 +35,9 @@ export async function GET(request: NextRequest) {
|
||||
}
|
||||
|
||||
const contentType = response.headers.get('Content-Type');
|
||||
if (response.body) {
|
||||
response.body.cancel();
|
||||
}
|
||||
if (contentType?.includes('video/mp4')) {
|
||||
return NextResponse.json({ success: true, type: 'mp4' }, { status: 200 });
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ import PageLayout from '@/components/PageLayout';
|
||||
declare global {
|
||||
interface HTMLVideoElement {
|
||||
hls?: any;
|
||||
flv?: any;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +67,7 @@ function LivePageClient() {
|
||||
// 播放器相关
|
||||
const [videoUrl, setVideoUrl] = useState('');
|
||||
const [isVideoLoading, setIsVideoLoading] = useState(false);
|
||||
const [unsupportedType, setUnsupportedType] = useState<string | null>(null);
|
||||
|
||||
// 切换直播源状态
|
||||
const [isSwitchingSource, setIsSwitchingSource] = useState(false);
|
||||
@@ -350,6 +350,12 @@ function LivePageClient() {
|
||||
// 设置切换状态,锁住频道切换器
|
||||
setIsSwitchingSource(true);
|
||||
|
||||
// 首先销毁当前播放器
|
||||
cleanupPlayer();
|
||||
|
||||
// 重置不支持的类型状态
|
||||
setUnsupportedType(null);
|
||||
|
||||
// 清空节目单信息
|
||||
setEpgData(null);
|
||||
|
||||
@@ -371,6 +377,12 @@ function LivePageClient() {
|
||||
// 如果正在切换直播源,则禁用频道切换
|
||||
if (isSwitchingSource) return;
|
||||
|
||||
// 首先销毁当前播放器
|
||||
cleanupPlayer();
|
||||
|
||||
// 重置不支持的类型状态
|
||||
setUnsupportedType(null);
|
||||
|
||||
setCurrentChannel(channel);
|
||||
setVideoUrl(channel.url);
|
||||
|
||||
@@ -404,6 +416,9 @@ function LivePageClient() {
|
||||
|
||||
// 清理播放器资源的统一函数
|
||||
const cleanupPlayer = () => {
|
||||
// 重置不支持的类型状态
|
||||
setUnsupportedType(null);
|
||||
|
||||
if (artPlayerRef.current) {
|
||||
try {
|
||||
// 先暂停播放
|
||||
@@ -419,10 +434,22 @@ function LivePageClient() {
|
||||
artPlayerRef.current.video.hls = null;
|
||||
}
|
||||
|
||||
// 销毁 FLV 实例
|
||||
// 销毁 FLV 实例 - 增强清理逻辑
|
||||
if (artPlayerRef.current.video && artPlayerRef.current.video.flv) {
|
||||
artPlayerRef.current.video.flv.destroy();
|
||||
artPlayerRef.current.video.flv = null;
|
||||
try {
|
||||
// 先停止加载
|
||||
if (artPlayerRef.current.video.flv.unload) {
|
||||
artPlayerRef.current.video.flv.unload();
|
||||
}
|
||||
// 销毁播放器
|
||||
artPlayerRef.current.video.flv.destroy();
|
||||
// 确保引用被清空
|
||||
artPlayerRef.current.video.flv = null;
|
||||
} catch (flvError) {
|
||||
console.warn('FLV实例销毁时出错:', flvError);
|
||||
// 强制清空引用
|
||||
artPlayerRef.current.video.flv = null;
|
||||
}
|
||||
}
|
||||
|
||||
// 移除所有事件监听器
|
||||
@@ -607,32 +634,6 @@ function LivePageClient() {
|
||||
});
|
||||
}
|
||||
|
||||
async function flvLoader(video: HTMLVideoElement, url: string) {
|
||||
try {
|
||||
const flvjs = await import('flv.js');
|
||||
const flv = flvjs.default as any;
|
||||
|
||||
if (!flv.isSupported()) {
|
||||
console.error('Flv.js 未支持');
|
||||
return;
|
||||
}
|
||||
|
||||
if (video.flv) {
|
||||
video.flv.destroy();
|
||||
}
|
||||
|
||||
const flvPlayer = flv.createPlayer({
|
||||
type: 'flv',
|
||||
url: url,
|
||||
});
|
||||
flvPlayer.attachMediaElement(video);
|
||||
flvPlayer.load();
|
||||
video.flv = flvPlayer;
|
||||
} catch (error) {
|
||||
console.error('加载 Flv.js 失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// 播放器初始化
|
||||
useEffect(() => {
|
||||
const preload = async () => {
|
||||
@@ -666,18 +667,25 @@ function LivePageClient() {
|
||||
type = precheckResult.type;
|
||||
}
|
||||
|
||||
const customType = type === 'flv' ? {
|
||||
flv: flvLoader,
|
||||
} : type === 'mp4' ? {} : {
|
||||
m3u8: m3u8Loader,
|
||||
};
|
||||
// 如果不是 m3u8 类型,设置不支持的类型并返回
|
||||
if (type !== 'm3u8') {
|
||||
setUnsupportedType(type);
|
||||
setIsVideoLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// 重置不支持的类型
|
||||
setUnsupportedType(null);
|
||||
|
||||
const customType = { m3u8: m3u8Loader };
|
||||
const targetUrl = `/api/proxy/m3u8?url=${encodeURIComponent(videoUrl)}&moontv-source=${currentSourceRef.current?.key || ''}`;
|
||||
try {
|
||||
// 创建新的播放器实例
|
||||
Artplayer.USE_RAF = true;
|
||||
|
||||
artPlayerRef.current = new Artplayer({
|
||||
container: artRef.current,
|
||||
url: `/api/proxy/m3u8?url=${encodeURIComponent(videoUrl)}&moontv-source=${currentSourceRef.current?.key || ''}`,
|
||||
url: targetUrl,
|
||||
poster: currentChannel.logo,
|
||||
volume: 0.7,
|
||||
isLive: true, // 设置为直播模式
|
||||
@@ -746,10 +754,9 @@ function LivePageClient() {
|
||||
});
|
||||
|
||||
if (artPlayerRef.current?.video) {
|
||||
const finalUrl = `/api/proxy/m3u8?url=${encodeURIComponent(videoUrl)}`;
|
||||
ensureVideoSource(
|
||||
artPlayerRef.current.video as HTMLVideoElement,
|
||||
finalUrl
|
||||
targetUrl
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1029,6 +1036,36 @@ function LivePageClient() {
|
||||
className='bg-black w-full h-full rounded-xl overflow-hidden shadow-lg border border-white/0 dark:border-white/30'
|
||||
></div>
|
||||
|
||||
{/* 不支持的直播类型提示 */}
|
||||
{unsupportedType && (
|
||||
<div className='absolute inset-0 bg-black/90 backdrop-blur-sm rounded-xl flex items-center justify-center z-[600] transition-all duration-300'>
|
||||
<div className='text-center max-w-md mx-auto px-6'>
|
||||
<div className='relative mb-8'>
|
||||
<div className='relative mx-auto w-24 h-24 bg-gradient-to-r from-orange-500 to-red-600 rounded-2xl shadow-2xl flex items-center justify-center transform hover:scale-105 transition-transform duration-300'>
|
||||
<div className='text-white text-4xl'>⚠️</div>
|
||||
<div className='absolute -inset-2 bg-gradient-to-r from-orange-500 to-red-600 rounded-2xl opacity-20 animate-pulse'></div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='space-y-4'>
|
||||
<h3 className='text-xl font-semibold text-white'>
|
||||
暂不支持的直播类型
|
||||
</h3>
|
||||
<div className='bg-orange-500/20 border border-orange-500/30 rounded-lg p-4'>
|
||||
<p className='text-orange-300 font-medium'>
|
||||
当前直播源类型:<span className='text-white font-bold'>{unsupportedType.toUpperCase()}</span>
|
||||
</p>
|
||||
<p className='text-orange-200 text-sm mt-2'>
|
||||
目前仅支持 M3U8 格式的直播流
|
||||
</p>
|
||||
</div>
|
||||
<p className='text-sm text-gray-300'>
|
||||
请尝试其他频道
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 视频加载蒙层 */}
|
||||
{isVideoLoading && (
|
||||
<div className='absolute inset-0 bg-black/85 backdrop-blur-sm rounded-xl flex items-center justify-center z-[500] transition-all duration-300'>
|
||||
|
||||
Reference in New Issue
Block a user