├── .gitignore ├── LICENSE ├── README.md ├── example └── index.html ├── package-lock.json ├── package.json └── server.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .idea 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Viktor Khokhryakov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | WebSocket live backend for DPlayer 2 | ================================== 3 | 4 | [DPlayer](https://github.com/DIYgod/DPlayer) 5 | 6 | Usage 7 | ----- 8 | 9 | - `npm i`. 10 | - `node server.js --port=1207`. 11 | 12 | See `example/index.html` for more info. 13 | -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | DPlayer Demo 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dplayer-live-backend", 3 | "version": "0.1.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "async-limiter": { 8 | "version": "1.0.0", 9 | "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", 10 | "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" 11 | }, 12 | "minimist": { 13 | "version": "1.2.0", 14 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", 15 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" 16 | }, 17 | "safe-buffer": { 18 | "version": "5.1.1", 19 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", 20 | "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" 21 | }, 22 | "ultron": { 23 | "version": "1.1.1", 24 | "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", 25 | "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" 26 | }, 27 | "ws": { 28 | "version": "3.3.2", 29 | "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.2.tgz", 30 | "integrity": "sha512-t+WGpsNxhMR4v6EClXS8r8km5ZljKJzyGhJf7goJz9k5Ye3+b5Bvno5rjqPuIBn5mnn5GBb7o8IrIWHxX1qOLQ==", 31 | "requires": { 32 | "async-limiter": "1.0.0", 33 | "safe-buffer": "5.1.1", 34 | "ultron": "1.1.1" 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dplayer-live-backend", 3 | "version": "0.1.0", 4 | "description": "WebSocket live backend for DPlayer", 5 | "main": "server.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "MIT", 11 | "dependencies": { 12 | "minimist": "^1.2.0", 13 | "ws": "3.3.2" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | var WebSocket = new require('ws'); 2 | 3 | var argv = require('minimist')(process.argv.slice(2), {string: ['port'], default: {port: 1207}}); 4 | 5 | var server = new WebSocket.Server({ 6 | clientTracking: true, 7 | port: argv['port'] 8 | }, function () { 9 | console.log('WebSocket server started on port: ' + argv['port']); 10 | }); 11 | 12 | var shutdown = function () { 13 | console.log('Received kill signal, shutting down gracefully.'); 14 | 15 | server.close(function () { 16 | console.log('Closed out remaining connections.'); 17 | process.exit(); 18 | }); 19 | 20 | setTimeout(function () { 21 | console.error('Could not close connections in time, forcefully shutting down'); 22 | process.exit(); 23 | }, 10 * 1000); 24 | }; 25 | 26 | process.on('SIGTERM', shutdown); 27 | process.on('SIGINT', shutdown); 28 | 29 | server.on('error', function (err) { 30 | console.log(err); 31 | }); 32 | 33 | var hexColorRegExp = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/; 34 | var typeRegExp = /^(top|bottom|right)$/; 35 | var msgMinInterval = 500; 36 | var lastMsgTimestamps = {}; 37 | 38 | server.on('connection', function (ws, req) { 39 | var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress; 40 | ws.on('message', function (message) { 41 | var time = Date.now(); 42 | if (lastMsgTimestamps[ip] && lastMsgTimestamps[ip] - time < msgMinInterval) { 43 | return; 44 | } 45 | try { 46 | message = JSON.parse(message); 47 | if (!hexColorRegExp.test(message.color) || !typeRegExp.test(message.type) || !message.text) { 48 | return; 49 | } 50 | var msg = { 51 | text: message.text.substr(0, 255), 52 | color: message.color, 53 | type: message.type 54 | }; 55 | } catch (e) { 56 | return; 57 | } 58 | 59 | console.log(msg); 60 | lastMsgTimestamps[ip] = time; 61 | 62 | var data = JSON.stringify(msg); 63 | 64 | server.clients.forEach(function (client) { 65 | if (client !== ws && client.readyState === WebSocket.OPEN) { 66 | client.send(data, function (err) { 67 | err && console.log(err); 68 | }); 69 | } 70 | }); 71 | }); 72 | ws.on('error', console.log); 73 | }); 74 | 75 | setInterval(function () { 76 | var time = Date.now(); 77 | Object.keys(lastMsgTimestamps).forEach(function (key) { 78 | if (time - lastMsgTimestamps[key] > msgMinInterval) { 79 | delete lastMsgTimestamps[key]; 80 | } 81 | }); 82 | }, 5000); 83 | --------------------------------------------------------------------------------