Vitepress中添加DPlayer支持
安装dplayer
bash
npm install dplayer
添加dplayer组件
在.vitepress/theme/components
中新建DPlayer.vue
文件
vue
<template>
<div ref="dplayerContainer" class="dplayer-container"></div>
</template>
<script type="application/javascript">
import { onMounted, ref } from 'vue';
/* 弹幕支持 */
function createApiBackend (url, onMessage) {
var ws;
var connect = function () {
ws = new WebSocket(url);
ws.onmessage = function (event) {
onMessage(JSON.parse(event.data));
};
ws.onclose = function () {
// Try to reconnect in 5 seconds
setTimeout(connect, 5000);
};
};
var connected = false;
window.addEventListener('beforeunload', function () {
ws.onclose = null;
ws.close();
});
return {
read: function (options) {
if (connected) {
return;
}
connected = true;
connect();
options.success();
},
send: function (options) {
ws.send(JSON.stringify(options.data));
options.success();
}
};
}
export default {
name: 'DPlayerComponent',
props: {
options: {
type: Object,
required: true
},
websocketUrl: {
type: String,
required: true
}
},
setup(props) {
const dplayerContainer = ref(null);
onMounted(async () => {
if (typeof window !== 'undefined') {
const { default: DPlayer } = await import('dplayer');
const dp = new DPlayer({
container: dplayerContainer.value,
...props.options,
autoplay: true,
danmaku: true,
volume: 0,
apiBackend: createApiBackend(props.websocketUrl, function (dan) {
dp.danmaku.draw(dan);
}),
});
}});
return {
dplayerContainer
};
}
};
</script>
<style scoped>
.dplayer-container {
width: 100%; /* 调整宽度 */
height: 100%; /* 调整高度 */
margin-top: 20px; /* 调整上部空间 */
}
</style>
注册组件
在.vitepress/theme/index.ts
中注册组件
ts
import { defineAsyncComponent } from 'vue'
const DPlayerComponent = defineAsyncComponent(() =>
import('./components/DPlayer.vue')
);
export default {
...
enhanceApp({ app, router }: EnhanceAppContext) {
app.component('DPlayerComponent', DPlayerComponent);
...
}
}
在.vitepress/config.mts
中添加header
ts
export default defineConfig ({
...
head: [
['link', { rel: 'stylesheet', href: 'https://cdn.jsdelivr.net/npm/dplayer/dist/DPlayer.min.css' }],
['script', { src: 'https://cdn.jsdelivr.net/npm/hls.js/dist/hls.min.js' }],
['script', { src: 'https://cdn.jsdelivr.net/npm/dplayer/dist/DPlayer.min.js' }]
]
...
})
使用组件
在markdown
中引入组件
md
<DPlayerComponent :options="{
video: {
url: '/Endlessdreams.webm',
pic: ''
},
live: false
// video: {
// url: 'hls/test/index.m3u8',
// type: 'hls'
// }
}" websocketUrl="path_to_danmaku"
/>
弹幕服务器
在服务器上新建文件夹,并安装ws
bash
npm install ws minimist
创建server.js
文件
js
var WebSocket = new require('ws');
var argv = require('minimist')(process.argv.slice(2), {string: ['port'], default: {port: 1207}});
var server = new WebSocket.Server({
clientTracking: true,
port: argv['port']
}, function () {
console.log('WebSocket server started on port: ' + argv['port']);
});
var shutdown = function () {
console.log('Received kill signal, shutting down gracefully.');
server.close(function () {
console.log('Closed out remaining connections.');
process.exit();
});
setTimeout(function () {
console.error('Could not close connections in time, forcefully shutting down');
process.exit();
}, 10 * 1000);
};
process.on('SIGTERM', shutdown);
process.on('SIGINT', shutdown);
server.on('error', function (err) {
console.log(err);
});
//var hexColorRegExp = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;
var hexColorRegExp = /^\d{8}$/
var typeRegExp = /^(0|1|2)$/;
var msgMinInterval = 500;
var lastMsgTimestamps = {};
server.on('connection', function (ws, req) {
var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
console.log(ip)
ws.on('message', function (message) {
console.log(typeof message)
var time = Date.now();
if (lastMsgTimestamps[ip] && lastMsgTimestamps[ip] - time < msgMinInterval) {
console.log(2)
return;
}
try {
message = JSON.parse(message);
if (!hexColorRegExp.test(message.color) || !typeRegExp.test(message.type) || !message.text) {
console.log(1)
return;
}
var msg = {
text: message.text.substr(0, 255),
color: message.color,
type: message.type
};
} catch (e) {
return;
}
console.log(msg);
lastMsgTimestamps[ip] = time;
var data = JSON.stringify(msg);
server.clients.forEach(function (client) {
if (client !== ws && client.readyState === WebSocket.OPEN) {
client.send(data, function (err) {
err && console.log(err);
});
}
});
});
ws.on('error', console.log);
});
setInterval(function () {
var time = Date.now();
Object.keys(lastMsgTimestamps).forEach(function (key) {
if (time - lastMsgTimestamps[key] > msgMinInterval) {
delete lastMsgTimestamps[key];
}
});
}, 5000);
然后启动server.js
bash
node server.js > rundanmu.log 2>&1 &
在nginx中配置反向代理
nginx
location /websocket {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_pass http://127.0.0.1:1207;
}
之后就可以使用https://domain/websocket
连接弹幕服务器了