mirror of
https://github.com/DYefremov/DemonEditor.git
synced 2026-01-28 18:30:09 +01:00
added basic http api skeleton
This commit is contained in:
@@ -1,13 +1,14 @@
|
||||
import json
|
||||
import os
|
||||
import socket
|
||||
import time
|
||||
import urllib
|
||||
from enum import Enum
|
||||
from ftplib import FTP, error_perm
|
||||
from telnetlib import Telnet
|
||||
from urllib.error import HTTPError, URLError
|
||||
from urllib.parse import urlencode
|
||||
from urllib.request import urlopen, HTTPPasswordMgrWithDefaultRealm, HTTPBasicAuthHandler, build_opener, install_opener
|
||||
from xml.dom.minidom import parse
|
||||
|
||||
from app.commons import log
|
||||
from app.properties import Profile
|
||||
@@ -29,6 +30,12 @@ class DownloadType(Enum):
|
||||
WEBTV = 4
|
||||
|
||||
|
||||
class HttpRequestType(Enum):
|
||||
ZAP = "zap?sRef="
|
||||
INFO = "about"
|
||||
SIGNAL = "tunersignal"
|
||||
|
||||
|
||||
class TestException(Exception):
|
||||
pass
|
||||
|
||||
@@ -71,7 +78,7 @@ def upload_data(*, properties, download_type=DownloadType.ALL, remove_unused=Fal
|
||||
callback=None, done_callback=None, use_http=False):
|
||||
data_path = properties["data_dir_path"]
|
||||
host = properties["host"]
|
||||
base_url = "http://{}:{}/web/".format(host, properties.get("http_port", "80"))
|
||||
base_url = "http://{}:{}/api/".format(host, properties.get("http_port", "80"))
|
||||
tn, ht = None, None # telnet, http
|
||||
|
||||
try:
|
||||
@@ -216,12 +223,7 @@ def http(user, password, url, callback):
|
||||
while True:
|
||||
url = yield
|
||||
with urlopen(url, timeout=5) as f:
|
||||
dom = parse(f)
|
||||
msg = None
|
||||
for elem in dom.getElementsByTagName("e2simplexmlresult"):
|
||||
for ch in elem.childNodes:
|
||||
if ch.nodeType == ch.ELEMENT_NODE:
|
||||
msg = "".join(t.nodeValue for t in ch.childNodes if t.nodeType == t.TEXT_NODE)
|
||||
msg = json.load(f).get("message", None)
|
||||
if msg:
|
||||
callback("HTTP: {}\n".format(msg))
|
||||
|
||||
@@ -251,6 +253,27 @@ def telnet(host, port=23, user="", password="", timeout=5):
|
||||
yield
|
||||
|
||||
|
||||
# ***************** http api *******************#
|
||||
|
||||
def http_request(host, port, user, password):
|
||||
base_url = "http://{}:{}/api/".format(host, port)
|
||||
init_auth(user, password, base_url)
|
||||
while True:
|
||||
req_type, ref = yield
|
||||
url = base_url
|
||||
if req_type is HttpRequestType.ZAP:
|
||||
url = base_url + "zap?sRef={}".format(urllib.parse.quote(ref))
|
||||
elif req_type is HttpRequestType.INFO:
|
||||
url = base_url + HttpRequestType.INFO.value
|
||||
elif req_type is HttpRequestType.SIGNAL:
|
||||
url = base_url + HttpRequestType.SIGNAL.value
|
||||
|
||||
try:
|
||||
with urlopen(url, timeout=5) as f:
|
||||
yield json.load(f)
|
||||
except (URLError, HTTPError):
|
||||
yield None
|
||||
|
||||
# ***************** Connections testing *******************#
|
||||
|
||||
|
||||
@@ -265,18 +288,12 @@ def test_ftp(host, port, user, password, timeout=5):
|
||||
def test_http(host, port, user, password, timeout=5):
|
||||
try:
|
||||
params = urlencode({"text": "Connection test", "type": 2, "timeout": timeout})
|
||||
url = "http://{}:{}/web/message?{}".format(host, port, params)
|
||||
url = "http://{}:{}/api/message?{}".format(host, port, params)
|
||||
# authentication
|
||||
init_auth(user, password, url)
|
||||
|
||||
with urlopen(url, timeout=5) as f:
|
||||
dom = parse(f)
|
||||
msg = ""
|
||||
for elem in dom.getElementsByTagName("e2simplexmlresult"):
|
||||
for ch in elem.childNodes:
|
||||
if ch.nodeType == ch.ELEMENT_NODE:
|
||||
msg = "".join(t.nodeValue for t in ch.childNodes if t.nodeType == t.TEXT_NODE)
|
||||
return msg
|
||||
return json.load(f).get("message", "")
|
||||
except (URLError, HTTPError) as e:
|
||||
raise TestException(e)
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ from functools import lru_cache
|
||||
from gi.repository import GLib
|
||||
|
||||
from app.commons import run_idle, log, run_task, run_with_delay
|
||||
from app.connections import http_request, HttpRequestType
|
||||
from app.eparser import get_blacklist, write_blacklist, parse_m3u
|
||||
from app.eparser import get_services, get_bouquets, write_bouquets, write_services, Bouquets, Bouquet, Service
|
||||
from app.eparser.ecommons import CAS, Flag
|
||||
@@ -161,6 +162,9 @@ class MainAppWindow:
|
||||
self._player = None
|
||||
self._full_screen = False
|
||||
self._drawing_area_xid = None
|
||||
# http api
|
||||
self._http_api = None
|
||||
self._monitor_signal = False
|
||||
|
||||
builder = Gtk.Builder()
|
||||
builder.set_translation_domain("demon-editor")
|
||||
@@ -191,9 +195,16 @@ class MainAppWindow:
|
||||
self._player_frame = builder.get_object("player_frame")
|
||||
self._header_bar = builder.get_object("header_bar")
|
||||
self._bq_name_label = builder.get_object("bq_name_label")
|
||||
# Status bar
|
||||
self._ip_label = builder.get_object("ip_label")
|
||||
self._ip_label.set_text(self._options.get(self._profile).get("host"))
|
||||
self.update_profile_label()
|
||||
self._receiver_info_box = builder.get_object("receiver_info_box")
|
||||
self._receiver_info_label = builder.get_object("receiver_info_label")
|
||||
self._signal_box = builder.get_object("signal_box")
|
||||
self._service_name_label = builder.get_object("service_name_label")
|
||||
self._signal_level_bar = builder.get_object("signal_level_bar")
|
||||
self.init_http_api()
|
||||
# Dynamically active elements depending on the selected view
|
||||
self._tool_elements = {k: builder.get_object(k) for k in self._DYNAMIC_ELEMENTS}
|
||||
self._cas_label = builder.get_object("cas_label")
|
||||
@@ -949,6 +960,7 @@ class MainAppWindow:
|
||||
self.update_services_counts()
|
||||
|
||||
self.update_profile_label()
|
||||
self.init_http_api()
|
||||
|
||||
def on_tree_view_key_press(self, view, event):
|
||||
""" Handling keystrokes on press """
|
||||
@@ -1208,6 +1220,7 @@ class MainAppWindow:
|
||||
|
||||
@run_idle
|
||||
def on_player_play(self, item=None):
|
||||
self.on_zap()
|
||||
url = self.get_stream_url()
|
||||
self.update_player_buttons()
|
||||
if not url:
|
||||
@@ -1305,6 +1318,80 @@ class MainAppWindow:
|
||||
self._status_bar_box.set_visible(full)
|
||||
self._player_tool_bar.set_visible(full)
|
||||
|
||||
# ************************ HTTP API ****************************#
|
||||
@run_task
|
||||
def init_http_api(self):
|
||||
if self._http_api:
|
||||
self._http_api.close()
|
||||
self._http_api = None
|
||||
|
||||
prp = self._options.get(self._profile)
|
||||
if prp is Profile.NEUTRINO_MP:
|
||||
self.update_info_boxes_visible(False)
|
||||
return
|
||||
|
||||
self._http_api = http_request(prp.get("host", "127.0.0.1"), prp.get("http_port", "80"),
|
||||
prp.get("http_user", ""), prp.get("http_password", ""))
|
||||
|
||||
next(self._http_api)
|
||||
GLib.timeout_add_seconds(1, self.update_receiver_info)
|
||||
|
||||
@run_idle
|
||||
def on_zap(self):
|
||||
path, column = self._fav_view.get_cursor()
|
||||
if not path or not self._http_api:
|
||||
return
|
||||
|
||||
row = self._fav_model[path][:]
|
||||
srv = self._services.get(row[-2], None)
|
||||
if srv and srv.transponder:
|
||||
ref = srv.picon_id.rstrip(".png").replace("_", ":")
|
||||
req = self._http_api.send((HttpRequestType.ZAP, ref))
|
||||
next(self._http_api)
|
||||
if req and req.get("result", False):
|
||||
GLib.timeout_add_seconds(2, self.update_service_info)
|
||||
|
||||
@run_task
|
||||
def update_receiver_info(self):
|
||||
info = self._http_api.send((HttpRequestType.INFO, None))
|
||||
next(self._http_api)
|
||||
if not info:
|
||||
self._http_api.close()
|
||||
self._http_api = None
|
||||
GLib.idle_add(self.update_info_boxes_visible, False)
|
||||
return
|
||||
|
||||
service_info = info.get("service", None)
|
||||
res_info = info.get("info", None)
|
||||
if res_info:
|
||||
image = res_info.get("friendlyimagedistro", "")
|
||||
image_ver = res_info.get("imagever", "")
|
||||
brand = res_info.get("brand", "")
|
||||
model = res_info.get("model", "")
|
||||
info_text = "{} {} Image: {} {}".format(brand, model, image, image_ver)
|
||||
GLib.idle_add(self._receiver_info_label.set_text, info_text)
|
||||
GLib.idle_add(self._receiver_info_box.set_visible, res_info)
|
||||
|
||||
if service_info:
|
||||
GLib.idle_add(self._service_name_label.set_text, service_info.get("name", ""))
|
||||
GLib.timeout_add_seconds(2, self.update_signal)
|
||||
GLib.idle_add(self._signal_box.set_visible, service_info)
|
||||
|
||||
def update_signal(self):
|
||||
sig = self._http_api.send((HttpRequestType.SIGNAL, None))
|
||||
next(self._http_api)
|
||||
self._signal_level_bar.set_value(sig.get("snr", 0))
|
||||
return self._monitor_signal
|
||||
|
||||
def update_service_info(self):
|
||||
info = self._http_api.send((HttpRequestType.INFO, None))
|
||||
next(self._http_api)
|
||||
if info:
|
||||
service_info = info.get("service", None)
|
||||
if service_info:
|
||||
GLib.idle_add(self._service_name_label.set_text, service_info.get("name", ""))
|
||||
GLib.timeout_add_seconds(1, self.update_signal)
|
||||
|
||||
# ***************** Filter and search *********************#
|
||||
|
||||
def on_filter_toggled(self, toggle_button: Gtk.ToggleToolButton):
|
||||
@@ -1591,6 +1678,11 @@ class MainAppWindow:
|
||||
def get_format_version(self):
|
||||
return 5 if self._options.get(self._profile).get("v5_support", False) else 4
|
||||
|
||||
@run_idle
|
||||
def update_info_boxes_visible(self, visible):
|
||||
self._signal_box.set_visible(visible)
|
||||
self._receiver_info_box.set_visible(visible)
|
||||
|
||||
|
||||
def start_app():
|
||||
MainAppWindow()
|
||||
|
||||
@@ -1897,7 +1897,7 @@ Author: Dmitriy Yefremov
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="services_bar_box">
|
||||
<property name="height_request">22</property>
|
||||
<property name="height_request">26</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="resize_mode">queue</property>
|
||||
@@ -2213,7 +2213,7 @@ Author: Dmitriy Yefremov
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="fav_bar_box">
|
||||
<property name="height_request">20</property>
|
||||
<property name="height_request">24</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">2</property>
|
||||
@@ -2394,7 +2394,7 @@ Author: Dmitriy Yefremov
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="bouquet_bar_box">
|
||||
<property name="height_request">20</property>
|
||||
<property name="height_request">24</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">2</property>
|
||||
@@ -2485,7 +2485,34 @@ Author: Dmitriy Yefremov
|
||||
<property name="height_request">24</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="homogeneous">True</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="receiver_info_box">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="receiver_info_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="tooltip_text" translatable="yes">Receiver info</property>
|
||||
<property name="margin_left">10</property>
|
||||
<property name="label" translatable="yes">Receiver info</property>
|
||||
<attributes>
|
||||
<attribute name="size" value="8000"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="ip_status_box">
|
||||
<property name="visible">True</property>
|
||||
@@ -2525,19 +2552,68 @@ Author: Dmitriy Yefremov
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="padding">5</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="signal_box">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">end</property>
|
||||
<property name="spacing">5</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="service_name_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="tooltip_text" translatable="yes">Current service</property>
|
||||
<property name="label" translatable="yes">Service name</property>
|
||||
<property name="justify">fill</property>
|
||||
<property name="xalign">1</property>
|
||||
<attributes>
|
||||
<attribute name="size" value="8000"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLevelBar" id="signal_level_bar">
|
||||
<property name="width_request">70</property>
|
||||
<property name="height_request">10</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="tooltip_text" translatable="yes">Tuner signal</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="margin_right">10</property>
|
||||
<property name="max_value">100</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<style>
|
||||
<class name="primary-toolbar"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
|
||||
Reference in New Issue
Block a user