forked from platypush/platypush
Fixed localstream executable
This commit is contained in:
parent
687e9e32f9
commit
10e45123c4
4 changed files with 101 additions and 71 deletions
|
@ -10,7 +10,7 @@ import urllib.parse
|
||||||
from platypush.config import Config
|
from platypush.config import Config
|
||||||
from platypush.context import get_plugin
|
from platypush.context import get_plugin
|
||||||
from platypush.plugins import Plugin, action
|
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):
|
class PlayerState(enum.Enum):
|
||||||
STOP = 'stop'
|
STOP = 'stop'
|
||||||
|
@ -42,8 +42,8 @@ class MediaPlugin(Plugin):
|
||||||
# Default port for the local resources HTTP streaming service
|
# Default port for the local resources HTTP streaming service
|
||||||
_default_streaming_port = 8989
|
_default_streaming_port = 8989
|
||||||
|
|
||||||
_local_stream_bin = os.path.join(os.path.dirname(__file__), 'bin',
|
# setup.py install will place localstream in PATH
|
||||||
'localstream')
|
_local_stream_bin = 'localstream'
|
||||||
|
|
||||||
_NOT_IMPLEMENTED_ERR = NotImplementedError(
|
_NOT_IMPLEMENTED_ERR = NotImplementedError(
|
||||||
'This method must be implemented in a derived class')
|
'This method must be implemented in a derived class')
|
||||||
|
@ -360,7 +360,7 @@ class MediaPlugin(Plugin):
|
||||||
|
|
||||||
self._streaming_proc = subprocess.Popen(
|
self._streaming_proc = subprocess.Popen(
|
||||||
[self._local_stream_bin, media, str(self._streaming_port)],
|
[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()
|
threading.Thread(target=self._streaming_process_monitor(media)).start()
|
||||||
|
@ -388,9 +388,24 @@ class MediaPlugin(Plugin):
|
||||||
if not self._streaming_proc:
|
if not self._streaming_proc:
|
||||||
return
|
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()
|
self._streaming_proc.wait()
|
||||||
try: self.stop_streaming()
|
try: self.stop_streaming()
|
||||||
except: pass
|
except: pass
|
||||||
|
self.logger.info('Streaming service terminated')
|
||||||
|
|
||||||
return _thread
|
return _thread
|
||||||
|
|
||||||
|
|
|
@ -1,71 +1,14 @@
|
||||||
#!/usr/bin/env node
|
#!/bin/bash
|
||||||
|
|
||||||
// Requires:
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
|
||||||
// - express (`npm install express`)
|
|
||||||
// - mime-types (`npm install mime-types`)
|
|
||||||
|
|
||||||
const express = require('express')
|
if [ -d "$HOME/node_modules" ]; then
|
||||||
const fs = require('fs')
|
export NODE_PATH=$HOME/node_modules:$NODE_PATH
|
||||||
const path = require('path')
|
fi
|
||||||
const process = require('process')
|
|
||||||
const mime = require('mime-types')
|
|
||||||
const app = express()
|
|
||||||
|
|
||||||
function parseArgv() {
|
file=$1
|
||||||
let file = undefined
|
port=
|
||||||
let port = 8989
|
[ ! -z "$2" ] && port=$2
|
||||||
|
|
||||||
if (process.argv.length < 3) {
|
node $DIR/localstream.js "$file" $port
|
||||||
throw Error(`Usage: ${process.argv[0]} ${process.argv[1]} <media_file> [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}`)
|
|
||||||
})
|
|
||||||
|
|
71
platypush/plugins/media/bin/localstream.js
Executable file
71
platypush/plugins/media/bin/localstream.js
Executable file
|
@ -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]} <media_file> [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}`)
|
||||||
|
})
|
3
setup.py
3
setup.py
|
@ -49,7 +49,8 @@ setup(
|
||||||
'platydock=platypush.platydock:main',
|
'platydock=platypush.platydock:main',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
scripts = ['bin/platyvenv'],
|
scripts = ['bin/platyvenv', 'platypush/plugins/media/bin/localstream.js',
|
||||||
|
'platypush/plugins/media/bin/localstream'],
|
||||||
# data_files = [
|
# data_files = [
|
||||||
# ('/etc/platypush', ['platypush/config.example.yaml'])
|
# ('/etc/platypush', ['platypush/config.example.yaml'])
|
||||||
# ],
|
# ],
|
||||||
|
|
Loading…
Reference in a new issue