mirror of
https://github.com/DYefremov/DemonEditor.git
synced 2025-12-22 00:19:40 +01:00
bouquets gen improvement
This commit is contained in:
@@ -3248,7 +3248,7 @@ class Application(Gtk.Application):
|
||||
if self._s_type is not SettingsType.ENIGMA_2:
|
||||
self.show_error_message("Not allowed in this context!")
|
||||
return
|
||||
ServicesUpdateDialog(self._main_window, self._settings, self.on_import_data_from_web).show()
|
||||
ServicesUpdateDialog(self).show()
|
||||
|
||||
@run_idle
|
||||
def on_import_data_from_web(self, services, bouquets=None):
|
||||
@@ -3890,7 +3890,7 @@ class Application(Gtk.Application):
|
||||
return self.show_error_message("Data loading in progress!")
|
||||
|
||||
model, paths = view.get_selection().get_selected_rows()
|
||||
if is_only_one_item_selected(paths, self._main_window):
|
||||
if is_only_one_item_selected(paths, self):
|
||||
model_name = get_base_model(model).get_name()
|
||||
if model_name == self.FAV_MODEL:
|
||||
srv_type = model.get_value(model.get_iter(paths), Column.FAV_TYPE)
|
||||
@@ -4229,8 +4229,7 @@ class Application(Gtk.Application):
|
||||
self.show_error_message("No bouquets config is loaded. Load or create a new config!")
|
||||
return
|
||||
|
||||
gen_bouquets(self._services_view, self._bouquets_view, self._main_window, g_type, self._s_type,
|
||||
self.append_bouquet)
|
||||
gen_bouquets(self, g_type)
|
||||
|
||||
# ***************** Alternatives ********************* #
|
||||
|
||||
|
||||
@@ -39,8 +39,8 @@ import os
|
||||
import re
|
||||
import shutil
|
||||
import unicodedata
|
||||
from collections import defaultdict
|
||||
from functools import lru_cache
|
||||
from itertools import groupby
|
||||
from pathlib import Path
|
||||
from urllib.parse import unquote
|
||||
|
||||
@@ -546,13 +546,13 @@ def remove_picons(settings, picon_ids, picons):
|
||||
shutil.move(src, backup_path + p_id)
|
||||
|
||||
|
||||
def is_only_one_item_selected(paths, transient):
|
||||
def is_only_one_item_selected(paths, app):
|
||||
if len(paths) > 1:
|
||||
show_dialog(DialogType.ERROR, transient, "Please, select only one item!")
|
||||
app.show_error_message("Please, select only one item!")
|
||||
return False
|
||||
|
||||
if not paths:
|
||||
show_dialog(DialogType.ERROR, transient, "No selected item!")
|
||||
app.show_error_message("No selected item!")
|
||||
return False
|
||||
|
||||
return True
|
||||
@@ -574,47 +574,89 @@ def get_picon_file_name(service_name):
|
||||
|
||||
# ***************** Bouquets ********************* #
|
||||
|
||||
def gen_bouquets(view, bq_view, transient, gen_type, s_type, callback):
|
||||
def gen_bouquets(app, gen_type):
|
||||
""" Auto-generate and append list of bouquets. """
|
||||
model, paths = view.get_selection().get_selected_rows()
|
||||
single_types = (BqGenType.SAT, BqGenType.PACKAGE, BqGenType.TYPE)
|
||||
if gen_type in single_types:
|
||||
if not is_only_one_item_selected(paths, transient):
|
||||
return
|
||||
model, paths = app.services_view.get_selection().get_selected_rows()
|
||||
single_types = {BqGenType.SAT, BqGenType.PACKAGE, BqGenType.TYPE}
|
||||
if gen_type in single_types and not is_only_one_item_selected(paths, app):
|
||||
return
|
||||
|
||||
fav_id_index = Column.SRV_FAV_ID
|
||||
index = Column.SRV_TYPE
|
||||
if gen_type in (BqGenType.PACKAGE, BqGenType.EACH_PACKAGE):
|
||||
index = Column.SRV_PACKAGE
|
||||
elif gen_type in (BqGenType.SAT, BqGenType.EACH_SAT):
|
||||
index = Column.SRV_POS
|
||||
|
||||
# Splitting services [caching] by column value.
|
||||
s_data = defaultdict(list)
|
||||
for row in model:
|
||||
s_data[row[index]].append(BouquetService(None, BqServiceType.DEFAULT, row[fav_id_index], 0))
|
||||
ids = {row[Column.SRV_FAV_ID] for row in model}
|
||||
services = [v for k, v in app.current_services.items() if k in ids]
|
||||
|
||||
bq_type = BqType.BOUQUET.value if s_type is SettingsType.NEUTRINO_MP else BqType.TV.value
|
||||
bq_index = 0 if s_type is SettingsType.ENIGMA_2 else 1
|
||||
bq_root_iter = bq_view.get_model().get_iter(bq_index)
|
||||
srv = Service(*model[paths][:Column.SRV_TOOLTIP])
|
||||
cond = srv.package if gen_type is BqGenType.PACKAGE else srv.pos if gen_type is BqGenType.SAT else srv.service_type
|
||||
bq_view.expand_row(Gtk.TreePath(bq_index), 0)
|
||||
|
||||
if gen_type is BqGenType.TYPE and cond == "Data":
|
||||
msg = f"{get_message('Selected type:')} '{cond}'\n\n{get_message('Are you sure?')}"
|
||||
if show_dialog(DialogType.QUESTION, app.app_window, msg) != Gtk.ResponseType.OK:
|
||||
return
|
||||
|
||||
def grouper(s):
|
||||
data = s[index]
|
||||
return data if data else "None"
|
||||
|
||||
services = {k: list(v) for k, v in groupby(sorted(services, key=grouper), key=grouper)}
|
||||
|
||||
bq_view = app.bouquets_view
|
||||
bq_type = BqType.TV.value if app.is_enigma else BqType.BOUQUET.value
|
||||
bq_index = 0 if app.is_enigma else 1
|
||||
bq_root_iter = bq_view.get_model().get_iter(bq_index)
|
||||
|
||||
bq_names = get_bouquets_names(bq_view.get_model())
|
||||
|
||||
if gen_type in single_types:
|
||||
if cond in bq_names:
|
||||
show_dialog(DialogType.ERROR, transient, "A bouquet with that name exists!")
|
||||
else:
|
||||
callback(Bouquet(cond, bq_type, s_data.get(cond)), bq_root_iter)
|
||||
app.show_error_message("A bouquet with that name exists!")
|
||||
return
|
||||
|
||||
bq_services = get_services_type_groups(services.get(cond, []))
|
||||
if app.is_enigma:
|
||||
if srv.service_type == "Radio":
|
||||
bq_index = 1
|
||||
bq_type = BqType.RADIO.value
|
||||
bq_root_iter = bq_view.get_model().get_iter(bq_index)
|
||||
bq_view.expand_row(Gtk.TreePath(bq_index), 1)
|
||||
bq_services = bq_services.get("Radio", [])
|
||||
else:
|
||||
bq_view.expand_row(Gtk.TreePath(bq_index), 0)
|
||||
bq_services = bq_services.get("Data" if srv.service_type == "Data" else "TV", [])
|
||||
app.append_bouquet(Bouquet(cond, bq_type, get_bouquet_services(bq_services)), bq_root_iter)
|
||||
else:
|
||||
bq_view.expand_row(Gtk.TreePath(bq_index), 0)
|
||||
# We add a bouquet only if the given name is missing [keys - names]!
|
||||
if gen_type is BqGenType.EACH_SAT:
|
||||
bq_names = sorted(s_data.keys() - bq_names, key=get_pos_num, reverse=True)
|
||||
bq_names = sorted(services.keys() - bq_names, key=get_pos_num, reverse=True)
|
||||
else:
|
||||
bq_names = sorted(s_data.keys() - bq_names)
|
||||
[callback(Bouquet(name, BqType.TV.value, s_data.get(name)), bq_root_iter) for name in bq_names]
|
||||
bq_names = sorted(services.keys() - bq_names)
|
||||
|
||||
tv_bqs = []
|
||||
radio_bqs = []
|
||||
for n in bq_names:
|
||||
bqs = services.get(n, [])
|
||||
# TV and Radio separation.
|
||||
bq_grp = get_services_type_groups(bqs)
|
||||
tv_bq = bq_grp.get("TV", [])
|
||||
tv_bqs.append(Bouquet(n, BqType.TV.value, get_bouquet_services(tv_bq))) if tv_bq else None
|
||||
radio_bq = bq_grp.get("Radio", [])
|
||||
radio_bqs.append(Bouquet(n, BqType.RADIO.value, get_bouquet_services(radio_bq))) if radio_bq else None
|
||||
|
||||
[app.append_bouquet(b, bq_root_iter) for b in tv_bqs]
|
||||
if app.is_enigma:
|
||||
bq_root_iter = bq_view.get_model().get_iter(bq_index + 1)
|
||||
bq_view.expand_row(Gtk.TreePath(bq_index + 1), 0)
|
||||
[app.append_bouquet(b, bq_root_iter) for b in radio_bqs]
|
||||
|
||||
|
||||
def get_bouquet_services(services):
|
||||
services.sort(key=lambda s: s.service)
|
||||
return [BouquetService(None, BqServiceType.DEFAULT, s.fav_id, 0) for s in services]
|
||||
|
||||
|
||||
def get_bouquets_names(model):
|
||||
@@ -630,12 +672,28 @@ def get_bouquets_names(model):
|
||||
return bouquets_names
|
||||
|
||||
|
||||
def get_services_type_groups(services):
|
||||
""" Returns services grouped by main types [TV, Radio, Data]. -> dict """
|
||||
|
||||
def type_grouper(s):
|
||||
s_type = s.service_type
|
||||
|
||||
if s_type == "Data":
|
||||
return s_type
|
||||
elif s_type == "Radio":
|
||||
return s_type
|
||||
else:
|
||||
return "TV"
|
||||
|
||||
return {k: list(v) for k, v in groupby(sorted(services, key=type_grouper), key=type_grouper)}
|
||||
|
||||
|
||||
# ***************** Others ********************* #
|
||||
|
||||
def copy_reference(view, app):
|
||||
""" Copying picon id to clipboard. """
|
||||
model, paths = view.get_selection().get_selected_rows()
|
||||
if not is_only_one_item_selected(paths, app.app_window):
|
||||
if not is_only_one_item_selected(paths, app):
|
||||
return
|
||||
|
||||
target = app.get_target_view(view)
|
||||
|
||||
@@ -46,7 +46,7 @@ from app.eparser.satxml import get_pos_str
|
||||
from app.settings import USE_HEADER_BAR, Settings, CONFIG_PATH
|
||||
from app.tools.satellites import SatellitesParser, SatelliteSource, ServicesParser
|
||||
from ..dialogs import show_dialog, DialogType, get_message, get_builder
|
||||
from ..main_helper import append_text_to_tview, get_base_model, on_popup_menu
|
||||
from ..main_helper import append_text_to_tview, get_base_model, on_popup_menu, get_services_type_groups
|
||||
from ..search import SearchProvider
|
||||
from ..uicommons import Gtk, Gdk, UI_RESOURCES_PATH, HeaderBar
|
||||
|
||||
@@ -814,10 +814,10 @@ class SatellitesUpdateDialog(UpdateDialog):
|
||||
class ServicesUpdateDialog(UpdateDialog):
|
||||
""" Dialog for updating services from the Web. """
|
||||
|
||||
def __init__(self, transient, settings, callback):
|
||||
super().__init__(transient=transient, settings=settings, title="Services update")
|
||||
def __init__(self, app):
|
||||
super().__init__(transient=app.app_window, settings=app.app_settings, title="Services update")
|
||||
|
||||
self._callback = callback
|
||||
self._callback = app.on_import_data_from_web
|
||||
self._satellite_paths = {}
|
||||
self._transponders = {}
|
||||
self._services = {}
|
||||
@@ -956,7 +956,7 @@ class ServicesUpdateDialog(UpdateDialog):
|
||||
else:
|
||||
bouquets = None
|
||||
if self._source_box.get_active_id() == SatelliteSource.KINGOFSAT.name:
|
||||
bouquets = self.get_bouquets(srvs, services)
|
||||
bouquets = self.get_bouquets([srv._replace(fav_id=srvs[i].fav_id) for i, srv in enumerate(services)])
|
||||
|
||||
def c_filter(s):
|
||||
try:
|
||||
@@ -968,21 +968,30 @@ class ServicesUpdateDialog(UpdateDialog):
|
||||
|
||||
self.is_download = False
|
||||
|
||||
def get_bouquets(self, prepared, services):
|
||||
bouquets = []
|
||||
services = [srv._replace(fav_id=prepared[i].fav_id) for i, srv in enumerate(services)]
|
||||
def get_bouquets(self, services):
|
||||
type_groups = get_services_type_groups(services)
|
||||
tv_bouquets, radio_bouquets = [], []
|
||||
|
||||
tv_services = sorted(type_groups.get("TV", []), key=lambda s: s.service)
|
||||
rd_services = sorted(type_groups.get("Radio", []), key=lambda s: s.service)
|
||||
no_lb = "No Category"
|
||||
|
||||
if self._kos_bq_groups_switch.get_active():
|
||||
self.gen_bouquet_group(services, bouquets, lambda s: s[4] or "")
|
||||
self.gen_bouquet_group(tv_services, tv_bouquets, lambda s: s[4] or no_lb)
|
||||
self.gen_bouquet_group(rd_services, radio_bouquets, lambda s: s[4] or no_lb, bq_type=BqType.RADIO.value)
|
||||
|
||||
if self._kos_bq_lang_switch.get_active():
|
||||
self.gen_bouquet_group(services, bouquets, lambda s: s[5] or "")
|
||||
lb = "" if no_lb in {b.name for b in tv_bouquets} else "No Region"
|
||||
self.gen_bouquet_group(tv_services, tv_bouquets, lambda s: s[5] or lb)
|
||||
lb = "" if no_lb in {b.name for b in radio_bouquets} else "No Region"
|
||||
self.gen_bouquet_group(rd_services, radio_bouquets, lambda s: s[5] or lb, bq_type=BqType.RADIO.value)
|
||||
|
||||
return Bouquets("", BqType.TV.value, bouquets),
|
||||
return Bouquets("", BqType.TV.value, tv_bouquets), Bouquets("", BqType.RADIO.value, radio_bouquets)
|
||||
|
||||
def gen_bouquet_group(self, services, bouquets, grouper):
|
||||
def gen_bouquet_group(self, services, bouquets, grouper, bq_type=BqType.TV.value):
|
||||
""" Generates bouquets depending on <grouper>. """
|
||||
s_type = BqServiceType.DEFAULT
|
||||
[bouquets.append(Bouquet(name=g[0], type=BqType.TV.name,
|
||||
[bouquets.append(Bouquet(name=g[0], type=bq_type,
|
||||
services=[BouquetService(None, s_type, s.fav_id, 0) for s in g[1]])) for g in
|
||||
groupby(sorted(services, key=grouper), key=grouper) if g[0]]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user