mirror of
https://github.com/fHDHR/fHDHR_NextPVR.git
synced 2025-12-06 16:56:57 -05:00
commit
bd3d494a97
@ -1,11 +1,7 @@
|
|||||||
from gevent.pywsgi import WSGIServer
|
from gevent.pywsgi import WSGIServer
|
||||||
from flask import (Flask, send_from_directory, request, Response,
|
from flask import Flask, send_from_directory, request, abort, Response, stream_with_context
|
||||||
abort, stream_with_context)
|
|
||||||
import requests
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
from . import fHDHRdevice
|
from . import fHDHRdevice
|
||||||
from fHDHR.fHDHRerrors import TunerError
|
|
||||||
|
|
||||||
|
|
||||||
class HDHR_Hub():
|
class HDHR_Hub():
|
||||||
@ -23,6 +19,7 @@ class HDHR_Hub():
|
|||||||
self.lineupstatusjson = fHDHRdevice.Lineup_Status_JSON(settings, origserv)
|
self.lineupstatusjson = fHDHRdevice.Lineup_Status_JSON(settings, origserv)
|
||||||
self.images = fHDHRdevice.imageHandler(settings, epghandling)
|
self.images = fHDHRdevice.imageHandler(settings, epghandling)
|
||||||
self.tuners = fHDHRdevice.Tuners(settings)
|
self.tuners = fHDHRdevice.Tuners(settings)
|
||||||
|
self.watch = fHDHRdevice.WatchStream(settings, origserv, self.tuners)
|
||||||
self.station_scan = fHDHRdevice.Station_Scan(settings, origserv)
|
self.station_scan = fHDHRdevice.Station_Scan(settings, origserv)
|
||||||
self.xmltv = fHDHRdevice.xmlTV_XML(settings, epghandling)
|
self.xmltv = fHDHRdevice.xmlTV_XML(settings, epghandling)
|
||||||
self.htmlerror = fHDHRdevice.HTMLerror(settings)
|
self.htmlerror = fHDHRdevice.HTMLerror(settings)
|
||||||
@ -68,6 +65,9 @@ class HDHR_Hub():
|
|||||||
def get_image(self, request_args):
|
def get_image(self, request_args):
|
||||||
return self.images.get_image(request_args)
|
return self.images.get_image(request_args)
|
||||||
|
|
||||||
|
def get_stream(self, request_args):
|
||||||
|
return self.watch.get_stream(request_args)
|
||||||
|
|
||||||
|
|
||||||
hdhr = HDHR_Hub()
|
hdhr = HDHR_Hub()
|
||||||
|
|
||||||
@ -147,74 +147,10 @@ class HDHR_HTTP_Server():
|
|||||||
|
|
||||||
@app.route('/watch', methods=['GET'])
|
@app.route('/watch', methods=['GET'])
|
||||||
def watch():
|
def watch():
|
||||||
|
|
||||||
if 'method' in list(request.args.keys()) and 'channel' in list(request.args.keys()):
|
if 'method' in list(request.args.keys()) and 'channel' in list(request.args.keys()):
|
||||||
|
return Response(stream_with_context(hdhr.get_stream(request.args)))
|
||||||
method = str(request.args["method"])
|
else:
|
||||||
channel_id = str(request.args["channel"])
|
abort(503)
|
||||||
|
|
||||||
try:
|
|
||||||
hdhr.tuner_grab()
|
|
||||||
except TunerError:
|
|
||||||
print("A " + method + " stream request for channel " +
|
|
||||||
str(channel_id) + " was rejected do to a lack of available tuners.")
|
|
||||||
abort(503)
|
|
||||||
|
|
||||||
print("Attempting a " + method + " stream request for channel " + str(channel_id))
|
|
||||||
|
|
||||||
channelUri = hdhr.origserv.get_channel_stream(channel_id)
|
|
||||||
# print("Proxy URL determined as " + str(channelUri))
|
|
||||||
|
|
||||||
if method == "direct":
|
|
||||||
chunksize = int(hdhr.config.dict["direct_stream"]['chunksize'])
|
|
||||||
|
|
||||||
req = requests.get(channelUri, stream=True)
|
|
||||||
|
|
||||||
def generate():
|
|
||||||
try:
|
|
||||||
for chunk in req.iter_content(chunk_size=chunksize):
|
|
||||||
yield chunk
|
|
||||||
except GeneratorExit:
|
|
||||||
req.close()
|
|
||||||
print("Connection Closed.")
|
|
||||||
hdhr.tuner_close()
|
|
||||||
|
|
||||||
return Response(generate(), content_type=req.headers['content-type'], direct_passthrough=True)
|
|
||||||
|
|
||||||
elif method == "ffmpeg":
|
|
||||||
|
|
||||||
bytes_per_read = int(hdhr.config.dict["ffmpeg"]["bytes_per_read"])
|
|
||||||
|
|
||||||
ffmpeg_command = [hdhr.config.dict["ffmpeg"]["ffmpeg_path"],
|
|
||||||
"-i", channelUri,
|
|
||||||
"-c", "copy",
|
|
||||||
"-f", "mpegts",
|
|
||||||
"-nostats", "-hide_banner",
|
|
||||||
"-loglevel", "warning",
|
|
||||||
"pipe:stdout"
|
|
||||||
]
|
|
||||||
|
|
||||||
ffmpeg_proc = subprocess.Popen(ffmpeg_command, stdout=subprocess.PIPE)
|
|
||||||
|
|
||||||
def generate():
|
|
||||||
try:
|
|
||||||
while True:
|
|
||||||
videoData = ffmpeg_proc.stdout.read(bytes_per_read)
|
|
||||||
if not videoData:
|
|
||||||
break
|
|
||||||
try:
|
|
||||||
yield videoData
|
|
||||||
except Exception as e:
|
|
||||||
ffmpeg_proc.terminate()
|
|
||||||
ffmpeg_proc.communicate()
|
|
||||||
print("Connection Closed: " + str(e))
|
|
||||||
except GeneratorExit:
|
|
||||||
ffmpeg_proc.terminate()
|
|
||||||
ffmpeg_proc.communicate()
|
|
||||||
print("Connection Closed.")
|
|
||||||
hdhr.tuner_close()
|
|
||||||
|
|
||||||
return Response(stream_with_context(generate()), mimetype="audio/mpeg")
|
|
||||||
|
|
||||||
@app.route('/lineup.post', methods=['POST'])
|
@app.route('/lineup.post', methods=['POST'])
|
||||||
def lineup_post():
|
def lineup_post():
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
# pylama:ignore=W0611
|
# pylama:ignore=W0611
|
||||||
from .tuners import Tuners
|
from .tuners import Tuners
|
||||||
from .images import imageHandler
|
from .images import imageHandler
|
||||||
|
from .watch import WatchStream
|
||||||
from .station_scan import Station_Scan
|
from .station_scan import Station_Scan
|
||||||
|
|
||||||
from .discover_json import Discover_JSON
|
from .discover_json import Discover_JSON
|
||||||
|
|||||||
84
fHDHR/fHDHRweb/fHDHRdevice/watch.py
Normal file
84
fHDHR/fHDHRweb/fHDHRdevice/watch.py
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
import subprocess
|
||||||
|
|
||||||
|
from fHDHR.fHDHRerrors import TunerError
|
||||||
|
import fHDHR.tools
|
||||||
|
|
||||||
|
|
||||||
|
class WatchStream():
|
||||||
|
|
||||||
|
def __init__(self, settings, origserv, tuners):
|
||||||
|
self.config = settings
|
||||||
|
self.origserv = origserv
|
||||||
|
self.tuners = tuners
|
||||||
|
self.web = fHDHR.tools.WebReq()
|
||||||
|
|
||||||
|
def direct_stream(self, channelUri):
|
||||||
|
chunksize = int(self.tuners.config.dict["direct_stream"]['chunksize'])
|
||||||
|
|
||||||
|
req = self.web.session.get(channelUri, stream=True)
|
||||||
|
|
||||||
|
def generate():
|
||||||
|
try:
|
||||||
|
for chunk in req.iter_content(chunk_size=chunksize):
|
||||||
|
yield chunk
|
||||||
|
except GeneratorExit:
|
||||||
|
req.close()
|
||||||
|
print("Connection Closed.")
|
||||||
|
self.tuners.tuner_close()
|
||||||
|
|
||||||
|
return generate()
|
||||||
|
|
||||||
|
def ffmpeg_stream(self, channelUri):
|
||||||
|
bytes_per_read = int(self.config.dict["ffmpeg"]["bytes_per_read"])
|
||||||
|
|
||||||
|
ffmpeg_command = [self.config.dict["ffmpeg"]["ffmpeg_path"],
|
||||||
|
"-i", channelUri,
|
||||||
|
"-c", "copy",
|
||||||
|
"-f", "mpegts",
|
||||||
|
"-nostats", "-hide_banner",
|
||||||
|
"-loglevel", "warning",
|
||||||
|
"pipe:stdout"
|
||||||
|
]
|
||||||
|
|
||||||
|
ffmpeg_proc = subprocess.Popen(ffmpeg_command, stdout=subprocess.PIPE)
|
||||||
|
|
||||||
|
def generate():
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
videoData = ffmpeg_proc.stdout.read(bytes_per_read)
|
||||||
|
if not videoData:
|
||||||
|
break
|
||||||
|
try:
|
||||||
|
yield videoData
|
||||||
|
except Exception as e:
|
||||||
|
ffmpeg_proc.terminate()
|
||||||
|
ffmpeg_proc.communicate()
|
||||||
|
print("Connection Closed: " + str(e))
|
||||||
|
except GeneratorExit:
|
||||||
|
ffmpeg_proc.terminate()
|
||||||
|
ffmpeg_proc.communicate()
|
||||||
|
print("Connection Closed.")
|
||||||
|
self.tuners.tuner_close()
|
||||||
|
return generate()
|
||||||
|
|
||||||
|
def get_stream(self, request_args):
|
||||||
|
|
||||||
|
method = str(request_args["method"])
|
||||||
|
channel_id = str(request_args["channel"])
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.tuners.tuner_grab()
|
||||||
|
except TunerError:
|
||||||
|
print("A " + method + " stream request for channel " +
|
||||||
|
str(channel_id) + " was rejected do to a lack of available tuners.")
|
||||||
|
return
|
||||||
|
|
||||||
|
print("Attempting a " + method + " stream request for channel " + str(channel_id))
|
||||||
|
|
||||||
|
channelUri = self.origserv.get_channel_stream(channel_id)
|
||||||
|
# print("Proxy URL determined as " + str(channelUri))
|
||||||
|
|
||||||
|
if method == "ffmpeg":
|
||||||
|
return self.ffmpeg_stream(channelUri)
|
||||||
|
elif method == "direct":
|
||||||
|
return self.direct_stream(channelUri)
|
||||||
@ -3,3 +3,4 @@ gevent
|
|||||||
flask
|
flask
|
||||||
image
|
image
|
||||||
xmltodict
|
xmltodict
|
||||||
|
m3u8
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user