UNPKG

playercast

Version:

Cast to media player and control playback remotely

183 lines (143 loc) 3.62 kB
const fs = require('fs'); const express = require('express'); const bodyParser = require('body-parser'); const debug = require('debug')('playercast:server'); const { WSServer } = require('./websocket'); const player = require('./player'); const helper = require('./helper'); const keymap = require('./keymap'); const terminal = require('./terminal'); const noop = () => {}; module.exports = { transmitter: function(opts, cb) { cb = cb || noop; this.ws = null; var called = false; debug(`Creating file server on port ${opts.port}`); const callOnce = function(err) { if(called) return; called = true; if(!err) debug('Server successfully created '); cb(err); } const app = express(); app.use(bodyParser.json()); const configServer = () => { app.get('/cast', (req, res) => this._serveFile('fullPath', req, res)); app.get('/subs', (req, res) => this._serveFile('subsPath', req, res)); app.get('/cover', (req, res) => this._serveFile('coverPath', req, res)); app.get('/*', (req, res) => res.sendStatus(404)); app.post('/*', (req, res) => res.sendStatus(404)); var server = app.listen(opts.port, callOnce); server.on('error', callOnce); this.ws = new WSServer(server); this.ws.castData = opts; if(debug.enabled) debug(`Assigned cast data: ${JSON.stringify(this.ws.castData)}`); } if(opts.isUrl || opts.subsPath) { opts.mediaData = {}; return configServer(); } terminal.writeLine('Analyzing media file...'); helper.findSubsOrCover(opts.filePath, (err, result) => { if(err) { opts.mediaData = {}; return configServer(); } if(result.subsPath) opts.subsPath = result.subsPath; if(result.coverPath) opts.coverPath = result.coverPath; opts.mediaData = result; configServer(); }); }, _serveFile: function(pathType, req, res) { const filePath = this.ws.castData[pathType]; res.setHeader('Access-Control-Allow-Origin', '*'); if(!filePath) return res.sendStatus(204); fs.access(filePath, fs.constants.F_OK, (err) => { if(err) { terminal.writeError(err); return res.sendStatus(404); } res.sendFile(filePath, (err, pipe) => { if(!err) return; if(err.code === 'EISDIR') return req.next(); if( err.code !== 'ECONNABORTED' && err.syscall !== 'write' ) { /* Some players make requests for chunks over range */ if(!err.name || err.name !== 'RangeNotSatisfiableError') debug(err); req.next(); } }); }); }, receiver: function(port, cb) { cb = cb || noop; var called = false; debug(`Creating API server on port ${port}`); const callOnce = function(err) { if(called) return; called = true; if(!err) debug('Server successfully created'); cb(err); } const app = express(); app.use(bodyParser.json()); app.get('/api/*', onGet); app.post('/api/*', onPost); app.get('/*', (req, res) => res.sendStatus(404)); app.post('/*', (req, res) => res.sendStatus(404)); var server = app.listen(port, callOnce); server.on('error', callOnce); } } function onGet(req, res) { switch(req.params[0]) { case 'attach': return res.send({ host: player.getServerAddress() }); break; default: break; } res.sendStatus(404); } function onPost(req, res) { switch(req.params[0]) { case 'connect': player.changeHost(req.body); break; case 'remote': if(!req.body || !req.body.action) return res.sendStatus(404); keymap.extRemote(req.body, player); break; default: return res.sendStatus(404); } res.sendStatus(200); }