diff --git a/platypush/plugins/media/__init__.py b/platypush/plugins/media/__init__.py index fd7895ec..6c3b88a0 100644 --- a/platypush/plugins/media/__init__.py +++ b/platypush/plugins/media/__init__.py @@ -10,7 +10,7 @@ import urllib.parse from platypush.config import Config from platypush.context import get_plugin from platypush.plugins import Plugin, action -from platypush.utils import get_ip_or_hostname +from platypush.utils import get_ip_or_hostname, is_process_alive class PlayerState(enum.Enum): STOP = 'stop' @@ -42,8 +42,8 @@ class MediaPlugin(Plugin): # Default port for the local resources HTTP streaming service _default_streaming_port = 8989 - _local_stream_bin = os.path.join(os.path.dirname(__file__), 'bin', - 'localstream') + # setup.py install will place localstream in PATH + _local_stream_bin = 'localstream' _NOT_IMPLEMENTED_ERR = NotImplementedError( 'This method must be implemented in a derived class') @@ -360,7 +360,7 @@ class MediaPlugin(Plugin): self._streaming_proc = subprocess.Popen( [self._local_stream_bin, media, str(self._streaming_port)], - stdin=subprocess.PIPE, stdout=subprocess.PIPE + stdout=subprocess.PIPE, stderr=subprocess.STDOUT ) threading.Thread(target=self._streaming_process_monitor(media)).start() @@ -388,9 +388,24 @@ class MediaPlugin(Plugin): if not self._streaming_proc: return + while True: + if not self._streaming_proc or not \ + is_process_alive(self._streaming_proc.pid): + break + + line = self._streaming_proc.stdout.readline().decode().strip() + if not line: + continue + + if line.startswith('Listening on'): + break + + self.logger.info('Message from streaming service: {}'.format(line)) + self._streaming_proc.wait() try: self.stop_streaming() except: pass + self.logger.info('Streaming service terminated') return _thread diff --git a/platypush/plugins/media/bin/localstream b/platypush/plugins/media/bin/localstream index 39dd79e1..8703bb1d 100755 --- a/platypush/plugins/media/bin/localstream +++ b/platypush/plugins/media/bin/localstream @@ -1,71 +1,14 @@ -#!/usr/bin/env node +#!/bin/bash -// Requires: -// - express (`npm install express`) -// - mime-types (`npm install mime-types`) +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -const express = require('express') -const fs = require('fs') -const path = require('path') -const process = require('process') -const mime = require('mime-types') -const app = express() +if [ -d "$HOME/node_modules" ]; then + export NODE_PATH=$HOME/node_modules:$NODE_PATH +fi -function parseArgv() { - let file = undefined - let port = 8989 +file=$1 +port= +[ ! -z "$2" ] && port=$2 - if (process.argv.length < 3) { - throw Error(`Usage: ${process.argv[0]} ${process.argv[1]} [port=${port}]`) - } +node $DIR/localstream.js "$file" $port - file = process.argv[2] - - if (process.argv.length > 3) { - port = parseInt(process.argv[3]) - } - - return { file: file, port: port } -} - -let args = parseArgv() - -app.get('/video', function(req, res) { - const path = args.file - const ext = args.file.split('.').pop() - const stat = fs.statSync(path) - const fileSize = stat.size - const range = req.headers.range - const mimeType = mime.lookup(ext) - - if (range) { - const parts = range.replace(/bytes=/, "").split("-") - const start = parseInt(parts[0], 10) - const end = parts[1] - ? parseInt(parts[1], 10) - : fileSize-1 - - const chunksize = (end-start)+1 - const file = fs.createReadStream(path, {start, end}) - const head = { - 'Content-Range': `bytes ${start}-${end}/${fileSize}`, - 'Accept-Ranges': 'bytes', - 'Content-Length': chunksize, - 'Content-Type': mimeType, - } - - res.writeHead(206, head) - file.pipe(res) - } else { - const head = { - 'Content-Length': fileSize, - 'Content-Type': mimeType, - } - res.writeHead(200, head) - fs.createReadStream(path).pipe(res) - } -}) - -app.listen(args.port, function () { - console.log(`Listening on port ${args.port}`) -}) diff --git a/platypush/plugins/media/bin/localstream.js b/platypush/plugins/media/bin/localstream.js new file mode 100755 index 00000000..39dd79e1 --- /dev/null +++ b/platypush/plugins/media/bin/localstream.js @@ -0,0 +1,71 @@ +#!/usr/bin/env node + +// Requires: +// - express (`npm install express`) +// - mime-types (`npm install mime-types`) + +const express = require('express') +const fs = require('fs') +const path = require('path') +const process = require('process') +const mime = require('mime-types') +const app = express() + +function parseArgv() { + let file = undefined + let port = 8989 + + if (process.argv.length < 3) { + throw Error(`Usage: ${process.argv[0]} ${process.argv[1]} [port=${port}]`) + } + + file = process.argv[2] + + if (process.argv.length > 3) { + port = parseInt(process.argv[3]) + } + + return { file: file, port: port } +} + +let args = parseArgv() + +app.get('/video', function(req, res) { + const path = args.file + const ext = args.file.split('.').pop() + const stat = fs.statSync(path) + const fileSize = stat.size + const range = req.headers.range + const mimeType = mime.lookup(ext) + + if (range) { + const parts = range.replace(/bytes=/, "").split("-") + const start = parseInt(parts[0], 10) + const end = parts[1] + ? parseInt(parts[1], 10) + : fileSize-1 + + const chunksize = (end-start)+1 + const file = fs.createReadStream(path, {start, end}) + const head = { + 'Content-Range': `bytes ${start}-${end}/${fileSize}`, + 'Accept-Ranges': 'bytes', + 'Content-Length': chunksize, + 'Content-Type': mimeType, + } + + res.writeHead(206, head) + file.pipe(res) + } else { + const head = { + 'Content-Length': fileSize, + 'Content-Type': mimeType, + } + res.writeHead(200, head) + fs.createReadStream(path).pipe(res) + } +}) + +app.listen(args.port, function () { + console.log(`Listening on port ${args.port}`) +}) diff --git a/setup.py b/setup.py index b4e2e2ad..f1188716 100755 --- a/setup.py +++ b/setup.py @@ -49,7 +49,8 @@ setup( 'platydock=platypush.platydock:main', ], }, - scripts = ['bin/platyvenv'], + scripts = ['bin/platyvenv', 'platypush/plugins/media/bin/localstream.js', + 'platypush/plugins/media/bin/localstream'], # data_files = [ # ('/etc/platypush', ['platypush/config.example.yaml']) # ],