Files
myplayer-vue/src/components/videoPlayer.vue
2025-12-29 15:40:42 +08:00

230 lines
5.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div ref="videoRef" class="dplayer-container"></div>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount, watch } from 'vue';
import DPlayer from 'dplayer';
import Hls from 'hls.js';
const videoRef = ref(null);
const player = ref(null);
const hlsInstance = ref(null);
const props = defineProps({
autoplay: { type: Boolean, default: false },
videoUrl: { type: String, required: true },
danmaku: { type: Object, default: () => ({}) }
});
// 判断是否为 HLS 格式
const isHlsUrl = (url) => {
return url.includes('.m3u8') || url.includes('hls') || url.includes('application/x-mpegURL');
};
// 清理 HLS 实例
const cleanupHls = () => {
if (hlsInstance.value) {
try {
hlsInstance.value.destroy();
} catch (e) {
console.warn('清理 HLS 实例时出错:', e);
}
hlsInstance.value = null;
}
};
// 创建播放器配置
const createPlayerOptions = (url) => {
const proxyUrl = `/proxy?url=${encodeURIComponent(url)}`;
const isHls = isHlsUrl(url);
console.log('视频 URL:', url);
console.log('是否为 HLS 格式:', isHls);
console.log('代理 URL:', proxyUrl);
const options = {
container: videoRef.value,
autoplay: props.autoplay,
video: {},
danmaku: props.danmaku
};
if (isHls && Hls.isSupported()) {
// HLS 格式使用 customHls
options.video = {
url: proxyUrl,
type: 'customHls',
customType: {
customHls: function (video, player) {
cleanupHls(); // 清理旧的实例
const hls = new Hls({
maxBufferLength: 20,
maxMaxBufferLength: 60,
enableWorker: true,
lowLatencyMode: false
});
hlsInstance.value = hls;
hls.loadSource(video.src);
hls.attachMedia(video);
// 错误处理
hls.on(Hls.Events.ERROR, (event, data) => {
console.error('HLS 错误:', data);
if (data.fatal) {
switch (data.type) {
case Hls.ErrorTypes.NETWORK_ERROR:
console.error('网络错误,尝试恢复...');
hls.startLoad();
break;
case Hls.ErrorTypes.MEDIA_ERROR:
console.error('媒体错误,尝试恢复...');
hls.recoverMediaError();
break;
default:
console.error('致命错误,无法恢复');
hls.destroy();
break;
}
}
});
hls.on(Hls.Events.MANIFEST_PARSED, () => {
console.log('HLS 清单解析完成');
if (props.autoplay) {
video.play().catch(err => {
console.warn('自动播放失败:', err);
});
}
});
}
}
};
} else {
// 普通视频格式MP4等
options.video = {
url: proxyUrl,
type: 'auto' // 让 DPlayer 自动检测类型
};
}
return options;
};
onMounted(() => {
try {
const playerOptions = createPlayerOptions(props.videoUrl);
player.value = new DPlayer(playerOptions);
player.value.on('play', () => {
console.log('播放:', props.videoUrl);
});
player.value.on('pause', () => {
console.log('暂停');
});
player.value.on('ended', () => {
console.log('播放结束');
});
player.value.on('error', (error) => {
console.error('播放器错误:', error);
});
player.value.on('loadstart', () => {
console.log('开始加载视频');
});
player.value.on('canplay', () => {
console.log('视频可以播放');
});
} catch (error) {
console.error('初始化播放器失败:', error);
}
});
watch(() => props.videoUrl, (newUrl) => {
if (player.value && newUrl) {
console.log('切换视频到:', newUrl);
try {
cleanupHls(); // 清理旧的 HLS 实例
const isHls = isHlsUrl(newUrl);
const proxyUrl = `/proxy?url=${encodeURIComponent(newUrl)}`;
if (isHls && Hls.isSupported()) {
// HLS 格式切换
player.value.switchVideo({
url: proxyUrl,
type: 'customHls',
customType: {
customHls: function (video, player) {
cleanupHls();
const hls = new Hls({
maxBufferLength: 20,
maxMaxBufferLength: 60,
enableWorker: true
});
hlsInstance.value = hls;
hls.loadSource(video.src);
hls.attachMedia(video);
hls.on(Hls.Events.ERROR, (event, data) => {
console.error('HLS 错误:', data);
if (data.fatal) {
switch (data.type) {
case Hls.ErrorTypes.NETWORK_ERROR:
hls.startLoad();
break;
case Hls.ErrorTypes.MEDIA_ERROR:
hls.recoverMediaError();
break;
default:
hls.destroy();
break;
}
}
});
}
}
});
} else {
// 普通视频格式切换
player.value.switchVideo({
url: proxyUrl,
type: 'auto'
});
}
} catch (error) {
console.error('切换视频失败:', error);
}
}
});
// 销毁时清理播放器和 HLS 实例
onBeforeUnmount(() => {
cleanupHls();
if (player.value) {
try {
player.value.destroy();
} catch (e) {
console.warn('销毁播放器时出错:', e);
}
player.value = null;
}
});
</script>
<style scoped>
.dplayer-container {
width: 100%;
height: 100%;
}
</style>