diff --git a/app/tools/epg.py b/app/tools/epg.py index d3b1d093..d807c0f5 100644 --- a/app/tools/epg.py +++ b/app/tools/epg.py @@ -54,8 +54,8 @@ except ModuleNotFoundError: else: DETECT_ENCODING = True -EpgEvent = namedtuple("EpgEvent", ["service_name", "title", "time", "desc", "event_data"]) -EpgEvent.__new__.__defaults__ = ("N/A", "N/A", "N/A", "N/A", None) # For Python3 < 3.7 +EpgEvent = namedtuple("EpgEvent", ["service_name", "title", "start", "end", "length", "desc", "event_data"]) +EpgEvent.__new__.__defaults__ = ("N/A", "N/A", 0, 0, 0, "N/A", None) # For Python3 < 3.7 class Reader(metaclass=abc.ABCMeta): diff --git a/app/ui/epg/epg.py b/app/ui/epg/epg.py index b7a095fd..494d5250 100644 --- a/app/ui/epg/epg.py +++ b/app/ui/epg/epg.py @@ -203,6 +203,7 @@ class EpgTool(Gtk.Box): self._app = app self._app.connect("fav-changed", self.on_service_changed) self._app.connect("bouquet-changed", self.on_bouquet_changed) + self._app.connect("filter-toggled", self.on_filter_toggled) handlers = {"on_epg_press": self.on_epg_press, "on_timer_add": self.on_timer_add, @@ -217,12 +218,24 @@ class EpgTool(Gtk.Box): self._model = builder.get_object("epg_model") self._filter_model = builder.get_object("epg_filter_model") self._filter_model.set_visible_func(self.epg_filter_function) + self._filter_button = builder.get_object("epg_filter_button") self._filter_entry = builder.get_object("epg_filter_entry") self._multi_epg_button = builder.get_object("multi_epg_button") self._event_count_label = builder.get_object("event_count_label") self.pack_start(builder.get_object("epg_frame"), True, True, 0) - # Custom sort function. - self._view.get_model().set_sort_func(2, self.time_sort_func, 2) + # Custom data functions. + renderer = builder.get_object("epg_start_renderer") + column = builder.get_object("epg_start_column") + column.set_cell_data_func(renderer, self.start_data_func) + renderer = builder.get_object("epg_end_renderer") + column = builder.get_object("epg_end_column") + column.set_cell_data_func(renderer, self.end_data_func) + renderer = builder.get_object("epg_length_renderer") + column = builder.get_object("epg_length_column") + column.set_cell_data_func(renderer, self.duration_data_func) + # Time formats. + self._time_fmt = "%a %x - %H:%M" + self._duration_fmt = f"%-Hh %Mm" self.show() @@ -290,18 +303,25 @@ class EpgTool(Gtk.Box): @staticmethod def get_event(event, show_day=True): - t_str = f"{'%a, ' if show_day else ''}%x, %H:%M" s_name = event.get("e2eventservicename", "") title = event.get("e2eventtitle", "") or "" desc = event.get("e2eventdescription", "") or "" desc = desc.strip() + start, duration = int(event.get("e2eventstart", "0")), int(event.get("e2eventduration", "0")) - start = int(event.get("e2eventstart", "0")) - start_time = datetime.fromtimestamp(start) - end_time = datetime.fromtimestamp(start + int(event.get("e2eventduration", "0"))) - ev_time = f"{start_time.strftime(t_str)} - {end_time.strftime('%H:%M')}" + return EpgEvent(s_name, title, start, start + duration, duration, desc, event) - return EpgEvent(s_name, title, ev_time, desc, event) + def start_data_func(self, column, renderer, model, itr, data): + value = datetime.fromtimestamp(model.get_value(itr, Column.EPG_START)) + renderer.set_property("text", value.strftime(self._time_fmt)) + + def end_data_func(self, column, renderer, model, itr, data): + value = datetime.fromtimestamp(model.get_value(itr, Column.EPG_END)) + renderer.set_property("text", value.strftime(self._time_fmt)) + + def duration_data_func(self, column, renderer, model, itr, data): + value = datetime.utcfromtimestamp(model.get_value(itr, Column.EPG_LENGTH)) + renderer.set_property("text", value.strftime(self._duration_fmt)) def on_epg_filter_changed(self, entry): self._filter_model.refilter() @@ -312,15 +332,18 @@ class EpgTool(Gtk.Box): def epg_filter_function(self, model, itr, data): txt = self._filter_entry.get_text().upper() - return next((s for s in model.get(itr, 0, 1, 2, 3) if txt in s.upper()), False) - - def time_sort_func(self, model, iter1, iter2, column): - """ Custom sort function for time column. """ - event1 = model.get_value(iter1, 4) - event2 = model.get_value(iter2, 4) - - return int(event1.get("e2eventstart", "0")) - int(event2.get("e2eventstart", "0")) + return next((s for s in model.get(itr, + Column.EPG_SERVICE, + Column.EPG_TITLE, + Column.EPG_DESC) if txt in s.upper()), False) + def on_filter_toggled(self, app, value): + if self._app.page is Page.EPG: + active = not self._filter_button.get_active() + self._filter_button.set_active(active) + if active: + self._filter_entry.grab_focus() + def on_view_query_tooltip(self, view, x, y, keyboard_mode, tooltip): dst = view.get_dest_row_at_pos(x, y) if not dst: diff --git a/app/ui/epg/tab.glade b/app/ui/epg/tab.glade index e14e7868..6a61dcca 100644 --- a/app/ui/epg/tab.glade +++ b/app/ui/epg/tab.glade @@ -40,8 +40,12 @@ Author: Dmitriy Yefremov - - + + + + + + @@ -277,7 +281,7 @@ Author: Dmitriy Yefremov True True both - 3 + 6 @@ -325,21 +329,61 @@ Author: Dmitriy Yefremov - + True fixed - 210 + 150 50 - Time - 0.49000000953674316 + Start time + 0.49 2 - + + 5 + 0.49 + + + 2 + + + + + + + True + fixed + 150 + 50 + End time + 0.49 + 3 + + 5 0.49000000953674316 - 2 + 3 + + + + + + + True + fixed + 100 + 50 + Length + 0.49 + 4 + + + 5 + 0.49000000953674316 + + + 4 @@ -352,13 +396,13 @@ Author: Dmitriy Yefremov Description True 0.49000000953674316 - 3 + 5 end - 3 + 5 diff --git a/app/ui/main.py b/app/ui/main.py index 7f53baf6..38d8d7ac 100644 --- a/app/ui/main.py +++ b/app/ui/main.py @@ -570,6 +570,8 @@ class Application(Gtk.Application): self._epg_menu_button = builder.get_object("epg_menu_button") self._epg_menu_button.connect("realize", lambda b: b.set_popover(EpgSettingsPopover(self))) self.bind_property("is_enigma", self._epg_menu_button, "sensitive") + self._epg_start_time_fmt = "%a, %H:%M" + self._epg_end_time_fmt = "%H:%M" # Hiding for Neutrino. self.bind_property("is_enigma", builder.get_object("services_button_box"), "visible") # Setting the last size of the window if it was saved. @@ -1147,10 +1149,16 @@ class Application(Gtk.Application): event = self._epg_cache.get_current_event(srv_name) if event: + if event.start: + start = datetime.fromtimestamp(event.start).strftime(self._epg_start_time_fmt) + end = datetime.fromtimestamp(event.end).strftime(self._epg_end_time_fmt) + sep = "-" + else: + start, end, sep = "", "", "" # https://docs.gtk.org/Pango/pango_markup.html renderer.set_property("markup", (f'{escape(srv_name)}\n\n' f'{escape(event.title)}\n' - f'{event.time}')) + f'{start} {sep} {end}')) return False return True diff --git a/app/ui/uicommons.py b/app/ui/uicommons.py index f26dc6a0..7a228045 100644 --- a/app/ui/uicommons.py +++ b/app/ui/uicommons.py @@ -269,6 +269,14 @@ class Column(IntEnum): IPTV_FAV_ID = 5 IPTV_PICON_ID = 6 IPTV_TOOLTIP = 7 + # EPG view + EPG_SERVICE = 0 + EPG_TITLE = 1 + EPG_START = 2 + EPG_END = 3 + EPG_LENGTH = 4 + EPG_DESC = 5 + EPG_DATA = 6 def __index__(self): """ Overridden to get the index in slices directly """