From 107e2d88c2f6be229c7a1e311e785f3821bc6fc2 Mon Sep 17 00:00:00 2001 From: deathbybandaid Date: Thu, 4 Feb 2021 09:19:50 -0500 Subject: [PATCH] test --- LICENSE | 13 ++++ README.md | 22 +++++- __init__.py | 11 +++ plugin.json | 5 ++ requirements.txt | 0 stream/__init__.py | 168 +++++++++++++++++++++++++++++++++++++++++++ stream/plugin.json | 3 + web/__init__.py | 11 +++ web/plugin.json | 3 + web/webwatch.html | 11 +++ web/webwatch_html.py | 26 +++++++ webwatch_conf.json | 9 +++ 12 files changed, 281 insertions(+), 1 deletion(-) create mode 100644 LICENSE create mode 100644 __init__.py create mode 100644 plugin.json create mode 100644 requirements.txt create mode 100644 stream/__init__.py create mode 100644 stream/plugin.json create mode 100644 web/__init__.py create mode 100644 web/plugin.json create mode 100644 web/webwatch.html create mode 100644 web/webwatch_html.py create mode 100644 webwatch_conf.json diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..130e443 --- /dev/null +++ b/LICENSE @@ -0,0 +1,13 @@ +DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + Version 2, December 2004 + +Copyright (C) 2017 Sam Zick + +Everyone is permitted to copy and distribute verbatim or modified +copies of this license document, and changing it is allowed as long +as the name is changed. + +DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. You just DO WHAT THE FUCK YOU WANT TO. diff --git a/README.md b/README.md index 15802cc..2943782 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,22 @@ -# fHDHR_plugin_web_watch +

fHDHR web Plugin Watch Logo

+ +Welcome to the world of streaming content as a DVR device! We use some fancy python here to achieve a system of: + +**f**un +**H**ome +**D**istribution +**H**iatus +**R**ecreation + +fHDHR is labeled as beta until we reach v1.0.0 + +Join us in `#fHDHR `_ on Freenode. + +# Installation + +1) Review Installation guide located at [Docs](https://github.com/fHDHR/fHDHR/blob/main/docs/README.md) + +2) Insert this plugin into the `plugins` directory of fHDHR using `git clone` or downloading a release zip file. + +3) Adjust your configuration file with the below settings: diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..cf95536 --- /dev/null +++ b/__init__.py @@ -0,0 +1,11 @@ + +from .plutotv_html import PlutoTV_HTML + + +class Plugin_OBJ(): + + def __init__(self, fhdhr, plugin_utils): + self.fhdhr = fhdhr + self.plugin_utils = plugin_utils + + self.plutotv_html = PlutoTV_HTML(fhdhr, plugin_utils) diff --git a/plugin.json b/plugin.json new file mode 100644 index 0000000..af52a02 --- /dev/null +++ b/plugin.json @@ -0,0 +1,5 @@ +{ + "name":"webwatch", + "version":"v0.6.0-beta", + "type":"origin" +} diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e69de29 diff --git a/stream/__init__.py b/stream/__init__.py new file mode 100644 index 0000000..22f74a1 --- /dev/null +++ b/stream/__init__.py @@ -0,0 +1,168 @@ +import os +import sys +import subprocess + +from fHDHR.exceptions import TunerError + + +def setup(plugin): + + # Check config for ffmpeg path + ffmpeg_path = None + if plugin.config.dict["webwatch"]["ffmpeg_path"]: + # verify path is valid + if os.path.isfile(plugin.config.dict["webwatch"]["ffmpeg_path"]): + ffmpeg_path = plugin.config.dict["webwatch"]["ffmpeg_path"] + else: + plugin.logger.warning("Failed to find ffmpeg at %s." % plugin.config.dict["webwatch"]["ffmpeg_path"]) + + if not ffmpeg_path: + plugin.logger.info("Attempting to find ffmpeg in PATH.") + if plugin.config.internal["versions"]["Operating System"]["version"] in ["Linux", "Darwin"]: + find_ffmpeg_command = ["which", "ffmpeg"] + elif plugin.config.internal["versions"]["Operating System"]["version"] in ["Windows"]: + find_ffmpeg_command = ["where", "ffmpeg"] + + ffmpeg_proc = subprocess.Popen(find_ffmpeg_command, stdout=subprocess.PIPE) + ffmpeg_path = ffmpeg_proc.stdout.read().decode().strip("\n") + ffmpeg_proc.terminate() + ffmpeg_proc.communicate() + ffmpeg_proc.kill() + if not ffmpeg_path: + ffmpeg_path = None + elif ffmpeg_path.isspace(): + ffmpeg_path = None + + if ffmpeg_path: + plugin.config.dict["webwatch"]["ffmpeg_path"] = ffmpeg_path + + if ffmpeg_path: + ffmpeg_command = [ffmpeg_path, "-version", "pipe:stdout"] + try: + ffmpeg_proc = subprocess.Popen(ffmpeg_command, stdout=subprocess.PIPE) + ffmpeg_version = ffmpeg_proc.stdout.read().decode().split("version ")[1].split(" ")[0] + except FileNotFoundError: + ffmpeg_version = None + except PermissionError: + ffmpeg_version = None + finally: + ffmpeg_proc.terminate() + ffmpeg_proc.communicate() + ffmpeg_proc.kill() + + if not ffmpeg_version: + ffmpeg_version = "Missing" + plugin.logger.warning("Failed to find ffmpeg.") + + plugin.config.register_version("ffmpeg", ffmpeg_version, "env") + + +class Plugin_OBJ(): + + def __init__(self, fhdhr, plugin_utils, stream_args, tuner): + self.fhdhr = fhdhr + self.plugin_utils = plugin_utils + self.stream_args = stream_args + self.tuner = tuner + + if self.plugin_utils.config.internal["versions"]["ffmpeg"]["version"] == "Missing": + raise TunerError("806 - Tune Failed: FFMPEG Missing") + + self.bytes_per_read = int(plugin_utils.config.dict["streaming"]["bytes_per_read"]) + self.ffmpeg_command = self.ffmpeg_command_assemble(stream_args) + + def get(self): + + ffmpeg_proc = subprocess.Popen(self.ffmpeg_command, stdout=subprocess.PIPE) + + def generate(): + try: + while self.tuner.tuner_lock.locked(): + + chunk = ffmpeg_proc.stdout.read(self.bytes_per_read) + if not chunk: + break + # raise TunerError("807 - No Video Data") + yield chunk + chunk_size = int(sys.getsizeof(chunk)) + self.tuner.add_downloaded_size(chunk_size) + self.plugin_utils.logger.info("Connection Closed: Tuner Lock Removed") + + except GeneratorExit: + self.plugin_utils.logger.info("Connection Closed.") + except Exception as e: + self.plugin_utils.logger.info("Connection Closed: %s" % e) + finally: + ffmpeg_proc.terminate() + ffmpeg_proc.communicate() + ffmpeg_proc.kill() + self.plugin_utils.logger.info("Connection Closed: Tuner Lock Removed") + if hasattr(self.fhdhr.origins.origins_dict[self.tuner.origin], "close_stream"): + self.fhdhr.origins.origins_dict[self.tuner.origin].close_stream(self.tuner.number, self.stream_args) + self.tuner.close() + # raise TunerError("806 - Tune Failed") + + return generate() + + def ffmpeg_command_assemble(self, stream_args): + ffmpeg_command = [ + self.plugin_utils.config.dict["webwatch"]["ffmpeg_path"], + "-i", stream_args["stream_info"]["url"], + ] + ffmpeg_command.extend(self.ffmpeg_headers(stream_args)) + ffmpeg_command.extend(self.ffmpeg_duration(stream_args)) + ffmpeg_command.extend(self.transcode_profiles(stream_args)) + ffmpeg_command.extend(self.ffmpeg_loglevel()) + ffmpeg_command.extend(["pipe:stdout"]) + return ffmpeg_command + + def ffmpeg_headers(self, stream_args): + ffmpeg_command = [] + if stream_args["stream_info"]["headers"]: + headers_string = "" + if len(list(stream_args["stream_info"]["headers"].keys())) > 1: + for x in list(stream_args["stream_info"]["headers"].keys()): + headers_string += "%s: %s\r\n" % (x, stream_args["stream_info"]["headers"][x]) + else: + for x in list(stream_args["stream_info"]["headers"].keys()): + headers_string += "%s: %s" % (x, stream_args["stream_info"]["headers"][x]) + ffmpeg_command.extend(["-headers", '\"%s\"' % headers_string]) + return ffmpeg_command + + def ffmpeg_duration(self, stream_args): + ffmpeg_command = [] + if stream_args["duration"]: + ffmpeg_command.extend(["-t", str(stream_args["duration"])]) + else: + ffmpeg_command.extend( + [ + "-reconnect", "1", + "-reconnect_at_eof", "1", + "-reconnect_streamed", "1", + "-reconnect_delay_max", "2", + ] + ) + + return ffmpeg_command + + def ffmpeg_loglevel(self): + ffmpeg_command = [] + log_level = self.plugin_utils.config.dict["logging"]["level"].lower() + + loglevel_dict = { + "debug": "debug", + "info": "info", + "error": "error", + "warning": "warning", + "critical": "fatal", + } + if log_level not in ["info", "debug"]: + ffmpeg_command.extend(["-nostats", "-hide_banner"]) + ffmpeg_command.extend(["-loglevel", loglevel_dict[log_level]]) + return ffmpeg_command + + def transcode_profiles(self, stream_args): + + ffmpeg_command = ["-vcodec", "libx264", "-pix_fmt", "yuv420p"] + + return ffmpeg_command diff --git a/stream/plugin.json b/stream/plugin.json new file mode 100644 index 0000000..cc7518d --- /dev/null +++ b/stream/plugin.json @@ -0,0 +1,3 @@ +{ + "type":"alt_stream" +} diff --git a/web/__init__.py b/web/__init__.py new file mode 100644 index 0000000..3464a6d --- /dev/null +++ b/web/__init__.py @@ -0,0 +1,11 @@ + +from .webwatch_html import Watch_HTML + + +class Plugin_OBJ(): + + def __init__(self, fhdhr, plugin_utils): + self.fhdhr = fhdhr + self.plugin_utils = plugin_utils + + self.webwatch_html = Watch_HTML(fhdhr, plugin_utils) diff --git a/web/plugin.json b/web/plugin.json new file mode 100644 index 0000000..0a5a6e1 --- /dev/null +++ b/web/plugin.json @@ -0,0 +1,3 @@ +{ + "type":"web" +} diff --git a/web/webwatch.html b/web/webwatch.html new file mode 100644 index 0000000..c70bbac --- /dev/null +++ b/web/webwatch.html @@ -0,0 +1,11 @@ +{% extends "base.html" %} + +{% block content %} + +

fHDHR Channel Watch

+ + + +{% endblock %} diff --git a/web/webwatch_html.py b/web/webwatch_html.py new file mode 100644 index 0000000..eca8364 --- /dev/null +++ b/web/webwatch_html.py @@ -0,0 +1,26 @@ +from flask import request, render_template, session + + +class Watch_HTML(): + endpoints = ["/webwatch", "/webwatch.html"] + endpoint_name = "page_webwatch_html" + endpoint_access_level = 0 + pretty_name = "Watch" + endpoint_category = "pages" + + def __init__(self, fhdhr, plugin_utils): + self.fhdhr = fhdhr + + def __call__(self, *args): + return self.get(*args) + + def get(self, *args): + + base_url = request.url_root[:-1] + + origin = self.fhdhr.origins.valid_origins[0] + channel_id = [x["id"] for x in self.fhdhr.device.channels.get_channels(origin)][0] + + watch_url = '%s/api/tuners?method=stream&channel=%s&origin=%s' % (base_url, channel_id, origin) + + return render_template('webwatch.html', request=request, session=session, fhdhr=self.fhdhr, watch_url=watch_url) diff --git a/webwatch_conf.json b/webwatch_conf.json new file mode 100644 index 0000000..dc9ea1c --- /dev/null +++ b/webwatch_conf.json @@ -0,0 +1,9 @@ +{ + "webwatch":{ + "ffmpeg_path":{ + "value": "none", + "config_file": true, + "config_web": true + } + } +}