diff --git a/app/ui/epg/epg.py b/app/ui/epg/epg.py
index 23689b22..f02089f4 100644
--- a/app/ui/epg/epg.py
+++ b/app/ui/epg/epg.py
@@ -36,6 +36,7 @@ import shutil
import urllib.request
from datetime import datetime
from enum import Enum
+from itertools import chain
from urllib.error import HTTPError, URLError
from urllib.parse import quote
@@ -141,8 +142,9 @@ class FavEpgCache(EpgCache):
GLib.timeout_add_seconds(self._settings.epg_update_interval, self.update_epg_data, priority=GLib.PRIORITY_LOW)
def reset(self) -> None:
- self._is_run = False
- GLib.timeout_add_seconds(self._settings.epg_update_interval, self.init)
+ if self._is_run:
+ self._is_run = False
+ GLib.timeout_add_seconds(self._settings.epg_update_interval, self.init)
def update_epg_data(self):
if self._src is EpgSource.HTTP:
@@ -166,7 +168,7 @@ class FavEpgCache(EpgCache):
services = self._app.current_services
names = {services[s].service for s in self._app.current_bouquets.get(self._current_bq, [])}
for name, events in self._reader.get_current_events(names).items():
- ev = max(events, key=lambda x: x.start, default=None)
+ ev = min(events, key=lambda x: x.start, default=None)
if ev:
self.events[name] = ev
@@ -177,6 +179,61 @@ class FavEpgCache(EpgCache):
return [EpgEvent()]
+class TabEpgCache(EpgCache):
+
+ def __init__(self, app):
+ super().__init__(app)
+ self.init()
+
+ def init(self):
+ self._is_run = True
+ url = self._settings.epg_xml_source
+ gz_file = f"{self._settings.profile_data_path}epg{os.sep}epg.gz"
+ self._reader = XmlTvReader(gz_file, url)
+
+ if os.path.isfile(gz_file):
+ # Difference calculation between the current time and file modification.
+ dif = datetime.now() - datetime.fromtimestamp(os.path.getmtime(gz_file))
+ # We will update daily. -> Temporarily!!!
+ if dif.days > 0 and not self._canceled:
+ task = BGTaskWidget(self._app, "Downloading EPG...", self._reader.download, self.process_data, )
+ self._app.emit("add-background-task", task)
+ else:
+ self.process_data()
+ else:
+ if not self._canceled:
+ task = BGTaskWidget(self._app, "Downloading EPG...", self._reader.download, self.process_data, )
+ self._app.emit("add-background-task", task)
+
+ def process_data(self):
+ self._app.wait_dialog.show()
+
+ def process():
+ self._reader.parse()
+ self.update_epg_data()
+ self._app.wait_dialog.hide()
+
+ t = BGTaskWidget(self._app, "Processing XMLTV data...", process, )
+ self._app.emit("add-background-task", t)
+
+ def reset(self) -> None:
+ pass
+
+ def update_epg_data(self) -> bool:
+ services = self._app.current_services
+ names = {services[s].service for s in self._app.current_bouquets.get(self._current_bq, [])}
+ for name, events in self._reader.get_current_events(names).items():
+ self.events[name] = events
+
+ return self._is_run
+
+ def get_current_event(self, service_name) -> EpgEvent:
+ pass
+
+ def get_current_events(self, service_name) -> list[EpgEvent]:
+ return self.events.get(service_name, [])
+
+
class EpgSettingsPopover(Gtk.Popover):
def __init__(self, app, **kwarg):
@@ -288,7 +345,10 @@ class EpgTool(Gtk.Box):
def __init__(self, app, **kwargs):
super().__init__(**kwargs)
- self._current_bq = None
+ self._epg_cache = None
+ self._src = EpgSource.HTTP
+ self._current_bq = app.current_bouquet
+
self._app = app
self._app.connect("fav-changed", self.on_service_changed)
self._app.connect("profile-changed", self.on_profile_changed)
@@ -300,7 +360,8 @@ class EpgTool(Gtk.Box):
"on_epg_filter_changed": self.on_epg_filter_changed,
"on_epg_filter_toggled": self.on_epg_filter_toggled,
"on_view_query_tooltip": self.on_view_query_tooltip,
- "on_multi_epg_toggled": self.on_multi_epg_toggled}
+ "on_multi_epg_toggled": self.on_multi_epg_toggled,
+ "on_xmltv_toggled": self.on_xmltv_toggled}
builder = get_builder(f"{UI_RESOURCES_PATH}epg{SEP}tab.glade", handlers)
@@ -334,7 +395,7 @@ class EpgTool(Gtk.Box):
p_count = len(paths)
if p_count == 1:
- dialog = TimerTool.TimerDialog(self._app.app_window, TimerTool.TimerAction.EVENT, model[paths][-1])
+ dialog = TimerTool.TimerDialog(self._app.app_window, TimerTool.TimerAction.EVENT, model[paths][-1] or {})
response = dialog.run()
if response == Gtk.ResponseType.OK:
gen = self.write_timers_list([dialog.get_request()])
@@ -373,7 +434,10 @@ class EpgTool(Gtk.Box):
self.on_timer_add()
def on_service_changed(self, app, srv):
- if app.page is Page.EPG:
+ if app.page is not Page.EPG:
+ return
+
+ if self._src is EpgSource.HTTP:
ref = app.get_service_ref_data(srv)
if not ref:
return
@@ -384,21 +448,36 @@ class EpgTool(Gtk.Box):
scroll_to(path, self._view) if path else None
else:
self._app.wait_dialog.show()
- self._app.send_http_request(HttpAPI.Request.EPG, quote(ref), self.update_epg_data)
+ self._app.send_http_request(HttpAPI.Request.EPG, quote(ref), self.update_http_epg_data)
+ else:
+ if self._multi_epg_button.get_active():
+ path = next((r.path for r in self._model if r[-1].get("e2eventservicename", None) == srv.service), None)
+ scroll_to(path, self._view) if path else None
+ else:
+ self.update_xmltv_epg_data([srv.service])
def on_profile_changed(self, app, prf):
- self.update_epg_data()
+ self.update_http_epg_data()
@run_idle
- def update_epg_data(self, epg=None):
- self._event_count_label.set_text("0")
- self._model.clear()
+ def update_http_epg_data(self, epg=None):
+ self.clear()
if epg:
list(map(self._model.append, (self.get_event(e) for e in epg.get("event_list", [])
if e.get("e2eventid", "").isdigit())))
self._event_count_label.set_text(str(len(self._model)))
self._app.wait_dialog.hide()
+ def update_xmltv_epg_data(self, names):
+ self.clear()
+ events = chain.from_iterable(self._epg_cache.get_current_events(n) for n in names)
+ [self._model.append(e) for e in events]
+ self._event_count_label.set_text(str(len(self._model)))
+
+ def clear(self):
+ self._model.clear()
+ self._event_count_label.set_text("0")
+
@staticmethod
def get_event(event, show_day=True):
s_name = event.get("e2eventservicename", "")
@@ -450,8 +529,13 @@ class EpgTool(Gtk.Box):
path, pos = dst
model = view.get_model()
data = model[path][-1]
+ if not data:
+ return False
+
desc = data.get("e2eventdescription", "") or ""
ext_desc = data.get("e2eventdescriptionextended", "") or ""
+ if not any((desc, ext_desc)):
+ return False
tooltip.set_text(ext_desc if ext_desc else desc)
view.set_tooltip_row(tooltip, path)
@@ -459,12 +543,19 @@ class EpgTool(Gtk.Box):
return True
def on_multi_epg_toggled(self, button):
- self._model.clear()
- self._event_count_label.set_text("0")
+ self.clear()
if button.get_active():
self.get_multi_epg()
+ def on_xmltv_toggled(self, button):
+ if button.get_active():
+ self._src = EpgSource.XML
+ if self._epg_cache is None:
+ self._epg_cache = TabEpgCache(self._app)
+ else:
+ self._src = EpgSource.HTTP
+
def on_bouquet_changed(self, app, bq):
self._current_bq = bq
if app.page is Page.EPG and self._multi_epg_button.get_active():
@@ -474,14 +565,18 @@ class EpgTool(Gtk.Box):
if not self._current_bq:
return
- self._app.wait_dialog.show()
- bq = self._app.current_bouquet_files.get(self._current_bq, None)
- api = self._app.http_api
+ if self._src is EpgSource.HTTP:
+ self._app.wait_dialog.show()
+ bq = self._app.current_bouquet_files.get(self._current_bq, None)
+ api = self._app.http_api
- if bq and api:
- tm = datetime.now().timestamp()
- req = quote(f'FROM BOUQUET "userbouquet.{bq}.{self._current_bq.split(":")[-1]}"&time={tm}')
- api.send(HttpAPI.Request.EPG_MULTI, f'1:7:1:0:0:0:0:0:0:0:{req}', self.update_epg_data, timeout=15)
+ if bq and api:
+ tm = datetime.now().timestamp()
+ req = quote(f'FROM BOUQUET "userbouquet.{bq}.{self._current_bq.split(":")[-1]}"&time={tm}')
+ api.send(HttpAPI.Request.EPG_MULTI, f'1:7:1:0:0:0:0:0:0:0:{req}', self.update_http_epg_data, timeout=15)
+ else:
+ srvs = self._app.current_services
+ self.update_xmltv_epg_data(srvs[s].service for s in self._app.current_bouquets.get(self._current_bq, []))
class EpgDialog:
diff --git a/app/ui/epg/tab.glade b/app/ui/epg/tab.glade
index 1c395937..bde549b2 100644
--- a/app/ui/epg/tab.glade
+++ b/app/ui/epg/tab.glade
@@ -110,11 +110,13 @@ Author: Dmitriy Yefremov
True
@@ -196,6 +198,27 @@ Author: Dmitriy Yefremov
2
+
+
+
+ False
+ True
+ end
+ 4
+
+
False
@@ -354,6 +377,7 @@ Author: Dmitriy Yefremov
1
diff --git a/app/ui/timers.py b/app/ui/timers.py
index 1b4a750a..7754422e 100644
--- a/app/ui/timers.py
+++ b/app/ui/timers.py
@@ -236,15 +236,15 @@ class TimerTool(Gtk.Box):
TimerTool.set_repetition_flags(int(self._timer_data.get("e2repeated", "0")), self._days_buttons)
def set_timer_from_event_data(self):
- self._timer_name_entry.set_text(self._timer_data.get("e2eventtitle", ""))
- self._timer_desc_entry.set_text(self._timer_data.get("e2eventdescription", ""))
- self._timer_service_entry.set_text(self._timer_data.get("e2eventservicename", ""))
- self._timer_service_ref_entry.set_text(self._timer_data.get("e2eventservicereference", ""))
- self._timer_event_id_entry.set_text(self._timer_data.get("e2eventid", ""))
+ self._timer_name_entry.set_text(self._timer_data.get("e2eventtitle", None) or "")
+ self._timer_desc_entry.set_text(self._timer_data.get("e2eventdescription", None) or "")
+ self._timer_service_entry.set_text(self._timer_data.get("e2eventservicename", None) or "")
+ self._timer_service_ref_entry.set_text(self._timer_data.get("e2eventservicereference", None) or "")
+ self._timer_event_id_entry.set_text(self._timer_data.get("e2eventid", None) or "")
self._timer_action_combo_box.set_active_id("1")
self._timer_after_combo_box.set_active_id("3")
- start_time = int(self._timer_data.get("e2eventstart", "0"))
- self.set_time_data(start_time, start_time + int(self._timer_data.get("e2eventduration", "0")))
+ start_time = int(self._timer_data.get("e2eventstart", "0") or "0")
+ self.set_time_data(start_time, start_time + int(self._timer_data.get("e2eventduration", "0") or "0"))
def set_time_data(self, start_time, end_time):
""" Sets values for time widgets. """