Skip to content

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连接弹幕服务器了

基于 MIT 许可发布

本站访客数 人次 本站总访问量