Compare commits

...

38 Commits

Author SHA1 Message Date
DYefremov
9a5884cc9a it *.mo file update 2023-03-06 16:49:55 +03:00
mapi68
115237a10f Italian translation update (#163) 2023-03-06 16:46:29 +03:00
DYefremov
994bd0ee1c Russian, Belarusian and German translations update 2023-03-05 14:01:02 +03:00
DYefremov
27e5b373a3 version update 2023-03-04 20:43:15 +03:00
DYefremov
43c05b1739 fix namespace for web import 2023-03-04 20:00:13 +03:00
DYefremov
bd96c286e9 option skip c-band for web import dialog 2023-03-04 18:15:16 +03:00
DYefremov
1bded41eab close options button for import dialog 2023-03-04 16:00:41 +03:00
DYefremov
5f0f51679c sat list init on update dialog start 2023-03-04 12:28:10 +03:00
DYefremov
380bb3150b updated it *.mo file 2023-03-04 11:15:23 +03:00
mapi68
d1a7a486a2 Italian translation update (#162) 2023-03-04 11:07:52 +03:00
DYefremov
1be167bec3 sorting by pos on bouquets generation 2023-03-04 00:27:37 +03:00
DYefremov
dd3e88589c Russian, Belarusian and German translations update 2023-03-03 17:38:29 +03:00
DYefremov
c5a2df6d7d prevent duplicate for web import 2023-03-03 12:04:04 +03:00
DYefremov
c9fc3803c7 fix FEC value for web import 2023-03-03 10:49:06 +03:00
DYefremov
6afd518cfc fix adding duplicates to the main list 2023-03-03 10:36:46 +03:00
DYefremov
02a51c9b56 bouquets generation for kos web source 2023-03-02 17:50:31 +03:00
DYefremov
c96cfa0e1b category and lang for kingofsat 2023-03-01 23:02:11 +03:00
DYefremov
08bc4ff4c4 bouquets only option for import dialog 2023-03-01 13:36:20 +03:00
DYefremov
ae2b78e990 README update 2023-02-28 00:23:00 +03:00
DYefremov
88be9fe49c updated it *.mo file 2023-02-27 23:48:01 +03:00
mapi68
9dae9b7219 Italian translation update (#161) 2023-02-27 23:42:58 +03:00
DYefremov
f296a6c90b paths normalization in settings 2023-02-27 23:40:41 +03:00
DYefremov
0486776d83 minor fix 2023-02-27 10:31:20 +03:00
DYefremov
3e6146d825 .gitignore update 2023-02-23 16:31:03 +03:00
audi06_19
9b97341e70 add .gitignore and Turkish translation update (#160)
* add .gitignore

* Update: Turkish translation update
2023-02-23 14:36:34 +03:00
DYefremov
41714136e6 README update 2023-02-23 14:31:56 +03:00
DYefremov
f781cbb9f6 bump version 2023-02-23 11:05:50 +03:00
DYefremov
177be7679b added version for extensions 2023-02-22 13:43:24 +03:00
DYefremov
a65914a48c duplicate removal support for the fav list (#159) 2023-02-22 11:55:34 +03:00
DYefremov
e3ffc2e24b playback fix for empty list 2023-02-22 11:46:11 +03:00
DYefremov
79415c69c5 minor refactoring 2023-02-21 15:39:22 +03:00
DYefremov
54c4e02cee bump version 2023-02-18 21:15:50 +03:00
DYefremov
f580c5d83c added header bar option on macOS 2023-02-18 18:35:09 +03:00
DYefremov
e0cbdb2f8d header bar option refactoring 2023-02-18 11:30:06 +03:00
DYefremov
839855c076 reworking of the program options tab 2023-02-18 09:37:05 +03:00
audi06_19
87db39590b Update: Turkish translation update (#158) 2023-02-18 08:28:41 +03:00
DYefremov
ebe58903e5 corrected service type setting for IPTV 2023-02-17 21:51:35 +03:00
DYefremov
ff8d4e5321 fix ref assignment from XML source (#154) 2023-02-17 20:17:17 +03:00
43 changed files with 968 additions and 501 deletions

4
.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
*.pyc
*.pyo
*__pycache__
.idea

View File

@@ -26,7 +26,9 @@ Experimental support of Neutrino-MP or others on the same basis (BPanther, etc).
[<img src="https://user-images.githubusercontent.com/7511379/141684475-4511ea4f-b152-42d5-b9c8-f3e1e9a160d0.png" width="480"/>](https://user-images.githubusercontent.com/7511379/141684475-4511ea4f-b152-42d5-b9c8-f3e1e9a160d0.png)
* Ability to view EPG and manage timers (via HTTP API).
* Simple FTP client (experimental).
[<img src="https://user-images.githubusercontent.com/7511379/141681165-5679c331-72e7-4044-b365-dcdb30b1433c.png" width="480"/>](https://user-images.githubusercontent.com/7511379/141681165-5679c331-72e7-4044-b365-dcdb30b1433c.png)
[<img src="https://user-images.githubusercontent.com/7511379/141681165-5679c331-72e7-4044-b365-dcdb30b1433c.png" width="480"/>](https://user-images.githubusercontent.com/7511379/141681165-5679c331-72e7-4044-b365-dcdb30b1433c.png)
**To increase program functionality you can use [extensions](https://github.com/DYefremov/demoneditor-extensions).**
#### Keyboard shortcuts
* **Ctrl + X** - only in bouquet list.
@@ -108,7 +110,7 @@ just load your data via *"File/Open"* and press *"Save"*. When importing separat
**The built-in Telnet client does not support ANSI escape sequences!**
For streams playback, this app supports [VLC](https://www.videolan.org/vlc/), [MPV](https://mpv.io/) and [GStreamer](https://gstreamer.freedesktop.org/). Depending on your distro, you may need to install additional packages and libraries.
For streams playback, this app supports [VLC](https://www.videolan.org/vlc/), [MPV](https://mpv.io/) and [GStreamer](https://gstreamer.freedesktop.org/). Depending on your distro, you may need to install additional packages and libraries.
#### Command line arguments:
* **-l** - write logs to file.
* **-d on/off** - turn on/off debug mode. Allows to display more information in the logs.

View File

@@ -2,7 +2,7 @@
#
# The MIT License (MIT)
#
# Copyright (c) 2018-2022 Dmitriy Yefremov
# Copyright (c) 2018-2023 Dmitriy Yefremov
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -38,7 +38,7 @@ from app.ui.uicommons import IPTV_ICON
# url, description, urlkey, account, usrname, psw, s_type, iconsrc, iconsrc_b, group
NEUTRINO_FAV_ID_FORMAT = "{}::{}::{}::{}::{}::{}::{}::{}::{}::{}"
ENIGMA2_FAV_ID_FORMAT = " {}:{}:{}:{:X}:{:X}:{:X}:{:X}:0:0:0:{}:{}\n#DESCRIPTION {}\n"
ENIGMA2_FAV_ID_FORMAT = " {}:{}:{:X}:{:X}:{:X}:{:X}:{:X}:0:0:0:{}:{}\n#DESCRIPTION {}\n"
MARKER_FORMAT = " 1:64:{}:0:0:0:0:0:0:0::{}\n#DESCRIPTION {}\n"
PICON_FORMAT = "{}_{}_{:X}_{:X}_{:X}_{:X}_{:X}_0_0_0.png"

View File

@@ -48,6 +48,8 @@ IS_DARWIN = sys.platform == "darwin"
IS_WIN = sys.platform == "win32"
IS_LINUX = sys.platform == "linux"
USE_HEADER_BAR = int(bool(os.environ.get("GNOME_DESKTOP_SESSION_ID")))
class Defaults(Enum):
""" Default program settings """
@@ -427,7 +429,7 @@ class Settings:
@default_data_path.setter
def default_data_path(self, value):
self._settings["default_data_path"] = value
self._settings["default_data_path"] = Settings.normalize_path(value)
@property
def default_backup_path(self):
@@ -435,7 +437,7 @@ class Settings:
@default_backup_path.setter
def default_backup_path(self, value):
self._settings["default_backup_path"] = value
self._settings["default_backup_path"] = Settings.normalize_path(value)
@property
def default_picon_path(self):
@@ -443,7 +445,7 @@ class Settings:
@default_picon_path.setter
def default_picon_path(self, value):
self._settings["default_picon_path"] = value
self._settings["default_picon_path"] = Settings.normalize_path(value)
@property
def profile_data_path(self):
@@ -479,7 +481,7 @@ class Settings:
@recordings_path.setter
def recordings_path(self, value):
self._settings["recordings_path"] = value
self._settings["recordings_path"] = Settings.normalize_path(value)
# ******** Streaming ********* #
@@ -702,6 +704,14 @@ class Settings:
# *********** Appearance *********** #
@property
def use_header_bar(self):
return self._settings.get("use_header_bar", USE_HEADER_BAR)
@use_header_bar.setter
def use_header_bar(self, value):
self._settings["use_header_bar"] = value
@property
def list_font(self):
return self._settings.get("list_font", "")
@@ -936,6 +946,10 @@ class Settings:
with open(CONFIG_FILE, "w", encoding="utf-8") as config_file:
json.dump(config, config_file, indent=" ")
@staticmethod
def normalize_path(path):
return f"{os.path.normpath(path)}{SEP}"
if __name__ == "__main__":
pass

View File

@@ -2,7 +2,7 @@
#
# The MIT License (MIT)
#
# Copyright (c) 2018-2022 Dmitriy Yefremov
# Copyright (c) 2018-2023 Dmitriy Yefremov
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -429,7 +429,7 @@ class SatellitesParser(HTMLParser):
class ServicesParser(HTMLParser):
""" Services parser for LYNGSAT source. """
def __init__(self, source=SatelliteSource.LYNGSAT, entities=False, separator=' '):
def __init__(self, source=SatelliteSource.LYNGSAT, entities=False, separator=' ', lang=None):
HTMLParser.__init__(self)
@@ -452,6 +452,12 @@ class ServicesParser(HTMLParser):
self._KING_TR_PAT = re.compile((r"(DVB-S[2]?)\s?(?:T2-MI,\s+PLP\s+(\d+))?.*"
r"?(?:PLS:\s+(Root|Gold|Combo)\+(\d+))?"
r"\s+(.*PSK).*?(?:.*Stream\s+(\d+))?.*"))
self._lang = "en"
if lang:
langs = {"en", "fr", "nl", "de", "se", "no", "pt", "es", "it", "pl",
"cz", "gr", "fi", "ar", "tr", "ru", "sc", "ro", "hu", "sq"}
lang, _, _ = lang.partition("_")
self._lang = lang if lang in langs else self._lang
self._parse_html_entities = entities
self._separator = separator
@@ -580,7 +586,7 @@ class ServicesParser(HTMLParser):
if len(r) == 13 and SatellitesParser.POS_PAT.match(r[0].text):
t_cell = r[4]
if t_cell.url and t_cell.url.startswith("tp.php?tp="):
t_cell.url = f"https://en.kingofsat.net/{t_cell.url}"
t_cell.url = f"https://{self._lang}.kingofsat.net/{t_cell.url}"
t_cell.text = f"{r[2].text} {r[3].text} {r[6].text} {r[8].text}"
trs.append(t_cell)
return trs
@@ -730,11 +736,12 @@ class ServicesParser(HTMLParser):
s_type = self._S_TYPES.get(s_type, "3")
_s_type = SERVICE_TYPE.get(s_type, SERVICE_TYPE.get("3"))
reg, grp = r[3].text, r[4].text
name, pkg, cas, sid, v_pid, a_pid = r[2].text, r[5].text, r[6].text, r[7].text, None, None
flags, sid, fav_id, picon_id, data_id = self.get_service_data(s_type, pkg, sid, tid, nid, nsp,
v_pid, a_pid, cas, use_pids)
services.append(Service(flags, "s", None, name, None, None, pkg, _s_type, None, picon_id,
services.append(Service(flags, "s", None, name, reg, grp, pkg, _s_type, None, picon_id,
sid, str(freq), sr, pol, fec, sys, pos, data_id, fav_id, multi_tr or tr))
return services
@@ -743,9 +750,9 @@ class ServicesParser(HTMLParser):
""" Returns converted transponder data. """
sys = get_key_by_value(SYSTEM, sys)
mod = get_key_by_value(MODULATION, mod)
fec = get_key_by_value(FEC, fec)
fec = get_key_by_value(FEC, fec) or "0"
# For negative (West) positions: 3600 - numeric position value!!!
namespace = f"{3600 - pos if pos < 0 else pos:04x}0000"
namespace = f"{3600 - abs(pos) if pos < 0 else pos:04x}0000"
tr_flag = 1
roll_off = 0 # 35% DVB-S2/DVB-S (default)
pilot = 2 # Auto

View File

@@ -75,13 +75,13 @@
<section>
<item>
<attribute name="label" translatable="yes">Settings</attribute>
<attribute name="action">app.on_settings</attribute>
<attribute name="action">app.preferences</attribute>
</item>
</section>
<section>
<item>
<attribute name="label" translatable="yes">Exit</attribute>
<attribute name="action">app.on_close_app</attribute>
<attribute name="action">app.quit</attribute>
</item>
</section>
</submenu>
@@ -156,6 +156,11 @@
<attribute name="label" translatable="yes">Alternate layout</attribute>
<attribute name="action">app.set_alternate_layout</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Alternate window title</attribute>
<attribute name="action">app.set_alternate_title</attribute>
<attribute name="hidden-when">action-disabled</attribute>
</item>
</section>
</submenu>
<submenu id="tools_menu">
@@ -193,7 +198,7 @@
<section>
<item>
<attribute name="label" translatable="yes">About</attribute>
<attribute name="action">app.on_about_app</attribute>
<attribute name="action">app.about</attribute>
</item>
</section>
</submenu>
@@ -202,19 +207,19 @@
<section>
<item>
<attribute name="label" translatable="yes">About</attribute>
<attribute name="action">app.on_about_app</attribute>
<attribute name="action">app.about</attribute>
</item>
</section>
<section>
<item>
<attribute name="label" translatable="yes">Settings</attribute>
<attribute name="action">app.on_settings</attribute>
<attribute name="action">app.preferences</attribute>
</item>
</section>
<section>
<item>
<attribute name="label" translatable="yes">Exit</attribute>
<attribute name="action">app.on_close_app</attribute>
<attribute name="action">app.quit</attribute>
</item>
</section>
</menu>
@@ -372,6 +377,11 @@
<attribute name="label" translatable="yes">Alternate layout</attribute>
<attribute name="action">app.set_alternate_layout</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Alternate window title</attribute>
<attribute name="action">app.set_alternate_title</attribute>
<attribute name="hidden-when">action-disabled</attribute>
</item>
</section>
</submenu>
<submenu>

View File

@@ -36,10 +36,10 @@ from enum import Enum
from pathlib import Path
from app.commons import run_idle, get_size_from_bytes
from app.settings import SettingsType, SEP, IS_DARWIN
from app.settings import SettingsType, SEP
from app.ui.dialogs import show_dialog, DialogType, get_builder
from app.ui.main_helper import append_text_to_tview
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, KeyboardKey, MOD_MASK, IS_GNOME_SESSION, HeaderBar
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, KeyboardKey, MOD_MASK, HeaderBar
class RestoreType(Enum):
@@ -77,7 +77,7 @@ class BackupDialog:
self._message_label = builder.get_object("message_label")
self._file_count_label = builder.get_object("file_count_label")
if IS_GNOME_SESSION or IS_DARWIN:
if self._settings.use_header_bar:
header_bar = HeaderBar()
self._dialog_window.set_titlebar(header_bar)

View File

@@ -40,7 +40,7 @@ Author: Dmitriy Yefremov
<property name="icon_name">system-help</property>
<property name="type_hint">normal</property>
<property name="program_name">DemonEditor</property>
<property name="version">3.4.0 Beta</property>
<property name="version">3.5.0 Beta</property>
<property name="copyright">2018-2023 Dmitriy Yefremov
</property>
<property name="comments" translatable="yes">Enigma2 channel and satellite list editor.</property>

View File

@@ -2,7 +2,7 @@
#
# The MIT License (MIT)
#
# Copyright (c) 2018-2022 Dmitriy Yefremov
# Copyright (c) 2018-2023 Dmitriy Yefremov
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -34,8 +34,8 @@ from functools import lru_cache
from pathlib import Path
from app.commons import run_idle
from app.settings import SEP, IS_WIN
from .uicommons import Gtk, UI_RESOURCES_PATH, TEXT_DOMAIN, IS_GNOME_SESSION
from app.settings import SEP, IS_WIN, USE_HEADER_BAR
from .uicommons import Gtk, UI_RESOURCES_PATH, TEXT_DOMAIN
class Dialog(Enum):
@@ -157,7 +157,7 @@ def get_file_chooser_dialog(transient, text, settings, action_type, file_filter,
def get_input_dialog(transient, text):
builder, dialog = get_dialog_from_xml(DialogType.INPUT, transient, use_header=IS_GNOME_SESSION)
builder, dialog = get_dialog_from_xml(DialogType.INPUT, transient, use_header=USE_HEADER_BAR)
entry = builder.get_object("input_entry")
entry.set_text(text if text else "")
response = dialog.run()
@@ -223,9 +223,9 @@ def get_builder(path, handlers=None, use_str=False, objects=None, tag="property"
if use_str:
if objects:
builder.add_objects_from_string(get_dialogs_string(path, tag).format(use_header=IS_GNOME_SESSION), objects)
builder.add_objects_from_string(get_dialogs_string(path, tag).format(use_header=USE_HEADER_BAR), objects)
else:
builder.add_from_string(get_dialogs_string(path, tag).format(use_header=IS_GNOME_SESSION))
builder.add_from_string(get_dialogs_string(path, tag).format(use_header=USE_HEADER_BAR))
else:
if objects:
builder.add_objects_from_string(get_dialogs_string(path, tag), objects)

View File

@@ -43,13 +43,13 @@ from gi.repository import GLib
from app.commons import run_idle, run_task, run_with_delay
from app.connections import download_data, DownloadType, HttpAPI
from app.eparser.ecommons import BouquetService, BqServiceType
from app.settings import SEP, EpgSource, IS_DARWIN, IS_WIN
from app.settings import SEP, EpgSource, IS_WIN
from app.tools.epg import EPG, ChannelsParser, EpgEvent, XmlTvReader
from app.ui.dialogs import get_message, show_dialog, DialogType, get_builder
from app.ui.tasks import BGTaskWidget
from app.ui.timers import TimerTool
from ..main_helper import on_popup_menu, update_entry_data, scroll_to, update_toggle_model, update_filter_sat_positions
from ..uicommons import Gtk, Gdk, UI_RESOURCES_PATH, Column, EPG_ICON, KeyboardKey, IS_GNOME_SESSION, Page, HeaderBar
from ..uicommons import Gtk, Gdk, UI_RESOURCES_PATH, Column, EPG_ICON, KeyboardKey, Page, HeaderBar
class RefsSource(Enum):
@@ -197,8 +197,8 @@ class EpgSettingsPopover(Gtk.Popover):
class EpgTool(Gtk.Box):
def __init__(self, app, *args, **kwargs):
super().__init__(*args, **kwargs)
def __init__(self, app, **kwargs):
super().__init__(**kwargs)
self._current_bq = None
self._app = app
@@ -477,7 +477,7 @@ class EpgDialog:
self._update_on_start_switch = builder.get_object("update_on_start_switch")
self._epg_dat_source_box = builder.get_object("epg_dat_source_box")
if IS_GNOME_SESSION or IS_DARWIN:
if self._settings.use_header_bar:
header_bar = HeaderBar(title="EPG", subtitle=get_message("List configuration"))
self._dialog.set_titlebar(header_bar)
builder.get_object("left_action_box").reparent(header_bar)
@@ -676,7 +676,7 @@ class EpgDialog:
data = ":".join(ref_data[3:7])
pos, ch_id = srv.num
pos = pos or " "
self._services_model.append((srv.name, pos, data, "_".join(ref_data), ch_id))
self._services_model.append((srv.name, pos, data, "_".join(ref_data).rstrip("_"), ch_id))
if index % factor == 0:
yield True
@@ -804,7 +804,7 @@ class EpgDialog:
fav_id_data[3:7] = data[-3].split(":")
if data[-2]:
row[Column.FAV_POS] = data[-1]
row[Column.FAV_POS] = data[-2]
p_data = data[-2].split("_")
if p_data:
fav_id_data[2] = p_data[2]

View File

@@ -2,7 +2,7 @@
#
# The MIT License (MIT)
#
# Copyright (c) 2018-2022 Dmitriy Yefremov
# Copyright (c) 2018-2023 Dmitriy Yefremov
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -42,10 +42,10 @@ from gi.repository import GLib
from app.commons import log, run_task, run_idle, get_size_from_bytes
from app.connections import UtfFTP
from app.settings import IS_LINUX, IS_DARWIN, IS_WIN, SEP
from app.settings import IS_LINUX, IS_DARWIN, IS_WIN, SEP, USE_HEADER_BAR
from app.ui.dialogs import show_dialog, DialogType, get_builder, get_message
from app.ui.main_helper import on_popup_menu
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, KeyboardKey, MOD_MASK, IS_GNOME_SESSION, Page
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, KeyboardKey, MOD_MASK, Page
File = namedtuple("File", ["icon", "name", "size", "date", "attr", "extra"])
@@ -529,7 +529,7 @@ class FtpClientBox(Gtk.HBox):
@run_idle
def show_edit_dialog(self, f_path, data):
dialog = TextEditDialog(f_path, IS_GNOME_SESSION)
dialog = TextEditDialog(f_path, USE_HEADER_BAR)
dialog.text = data
ok = Gtk.ResponseType.OK
if dialog.run() == ok and show_dialog(DialogType.QUESTION, self._app.app_window) == ok:
@@ -578,7 +578,7 @@ class FtpClientBox(Gtk.HBox):
log(f"Init attributes error [{attrs}]. Invalid length!")
return
dialog = AttributesDialog(attrs, IS_GNOME_SESSION)
dialog = AttributesDialog(attrs, USE_HEADER_BAR)
ok = Gtk.ResponseType.OK
if dialog.run() == ok and show_dialog(DialogType.QUESTION, self._app.app_window) == ok:
log(self._ftp.sendcmd(f"SITE CHMOD {dialog.permissions} {file}"))

View File

@@ -55,6 +55,113 @@ Author: Dmitriy Yefremov
<property name="icon-name">document-revert-symbolic-rtl</property>
<property name="icon_size">1</property>
</object>
<object class="GtkPopover" id="options_popover">
<property name="can-focus">False</property>
<child>
<object class="GtkBox" id="options_popover_box">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">5</property>
<property name="margin-bottom">5</property>
<property name="orientation">vertical</property>
<property name="spacing">5</property>
<child>
<object class="GtkBox" id="replace_existing_settings_box">
<property name="visible">True</property>
<property name="sensitive" bind-source="bouquets_only_switch" bind-property="active" bind-flags="invert-boolean">True</property>
<property name="can-focus">False</property>
<property name="tooltip-text" translatable="yes">Enables overwriting existing main list services.</property>
<property name="spacing">5</property>
<child>
<object class="GtkLabel" id="replace_existing_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Replace existing</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSwitch" id="replace_existing_switch">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="valign">center</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="bouquets_settings_box">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="tooltip-text" translatable="yes">Enables skipping services import from lamedb.</property>
<property name="spacing">5</property>
<child>
<object class="GtkLabel" id="bouquets_only_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Bouquets data only</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSwitch" id="bouquets_only_switch">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="valign">center</property>
<signal name="state-set" handler="on_bouquets_only_switch" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkModelButton">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="text" translatable="yes">Close</property>
<property name="centered">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</object>
<object class="GtkImage" id="remove_selection_image">
<property name="visible">True</property>
<property name="can-focus">False</property>
@@ -233,30 +340,6 @@ Author: Dmitriy Yefremov
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="spacing">5</property>
<child>
<object class="GtkLabel" id="replace_existing_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Replace existing</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSwitch" id="replace_existing_switch">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="valign">center</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkToggleButton" id="details_button">
<property name="visible">True</property>
@@ -275,6 +358,53 @@ Author: Dmitriy Yefremov
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkMenuButton" id="options_menu_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="direction">none</property>
<property name="popover">options_popover</property>
<child>
<object class="GtkBox" id="options_nutton_box">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="spacing">2</property>
<child>
<object class="GtkImage" id="options_button_image">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="tooltip-text" translatable="yes">Options</property>
<property name="icon-name">applications-system-symbolic</property>
<property name="icon_size">1</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="options_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Options</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>

View File

@@ -37,7 +37,7 @@ from app.eparser.neutrino.bouquets import parse_webtv, parse_bouquets as get_neu
from app.settings import SettingsType, IS_DARWIN, SEP
from app.ui.dialogs import show_dialog, DialogType, get_chooser_dialog, get_message, get_builder
from app.ui.main_helper import on_popup_menu, get_iptv_data
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, KeyboardKey, Column, IS_GNOME_SESSION, Page, HeaderBar
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, KeyboardKey, Column, Page, HeaderBar
def import_bouquet(app, model, path, appender, file_path=None):
@@ -121,6 +121,7 @@ class ImportDialog:
"on_resize": self.on_resize,
"on_main_paned_realize": self.on_main_paned_realize,
"on_visible_page": self.on_visible_page,
"on_bouquets_only_switch": self.on_bouquets_only_switch,
"on_key_press": self.on_key_press}
builder = get_builder(f"{UI_RESOURCES_PATH}imports.glade", handlers)
@@ -144,7 +145,10 @@ class ImportDialog:
self._dialog_window.set_transient_for(app.app_window)
self._info_bar = builder.get_object("info_bar")
self._message_label = builder.get_object("message_label")
# Options.
self._replace_existing_switch = builder.get_object("replace_existing_switch")
self._bouquets_only_switch = builder.get_object("bouquets_only_switch")
self._bouquets_settings_box = builder.get_object("bouquets_settings_box")
# Bouquets page.
self._bq_model = builder.get_object("bq_list_store")
self._bq_view = builder.get_object("bq_view")
@@ -159,7 +163,7 @@ class ImportDialog:
self._sat_model = builder.get_object("sat_list_store")
self._sat_count_label = builder.get_object("sat_count_label")
if IS_GNOME_SESSION or IS_DARWIN:
if self._settings.use_header_bar:
actions_box = builder.get_object("actions_box")
builder.get_object("toolbar_box").set_visible(False)
header_bar = HeaderBar()
@@ -260,7 +264,12 @@ class ImportDialog:
with suppress(ValueError):
bq.remove(b)
self._append(self._bouquets, list(filter(lambda s: s.fav_id not in self._ids, services)))
if self._bouquets_only_switch.get_active():
services = ()
else:
services = list(filter(lambda s: s.fav_id not in self._ids, services))
self._append(self._bouquets, services)
if self._replace_existing_switch.get_active():
self._app.emit("services_update", {s.fav_id: s for s in filter(lambda s: s.fav_id in self._ids, services)})
@@ -408,6 +417,11 @@ class ImportDialog:
def on_visible_page(self, stack, param):
self._page = Page(stack.get_visible_child_name())
self._bouquets_settings_box.set_sensitive(self._page is Page.SERVICES)
def on_bouquets_only_switch(self, switch, state):
if state:
self._replace_existing_switch.set_active(False)
def on_key_press(self, view, event):
""" Handling keystrokes """

View File

@@ -41,15 +41,14 @@ from app.commons import run_idle, run_task, log
from app.eparser.ecommons import BqServiceType, Service
from app.eparser.iptv import (NEUTRINO_FAV_ID_FORMAT, StreamType, ENIGMA2_FAV_ID_FORMAT, get_fav_id, MARKER_FORMAT,
parse_m3u, PICON_FORMAT)
from app.settings import SettingsType, IS_DARWIN
from app.settings import SettingsType
from app.tools.yt import YouTubeException, YouTube
from app.ui.dialogs import Action, show_dialog, DialogType, get_message, get_builder
from app.ui.main_helper import get_iptv_url, on_popup_menu, get_picon_pixbuf
from app.ui.uicommons import (Gtk, Gdk, UI_RESOURCES_PATH, IPTV_ICON, Column, KeyboardKey, get_yt_icon,
IS_GNOME_SESSION, HeaderBar)
from app.ui.uicommons import (Gtk, Gdk, UI_RESOURCES_PATH, IPTV_ICON, Column, KeyboardKey, get_yt_icon, HeaderBar)
_DIGIT_ENTRY_NAME = "digit-entry"
_ENIGMA2_REFERENCE = "{}:{}:{}:{:X}:{:X}:{:X}:{:X}:0:0:0"
_ENIGMA2_REFERENCE = "{}:{}:{:X}:{:X}:{:X}:{:X}:{:X}:0:0:0"
_PATTERN = re.compile("(?:^[\\s]*$|\\D)")
_UI_PATH = UI_RESOURCES_PATH + "iptv.glade"
@@ -198,7 +197,7 @@ class IptvDialog:
self.show_info_message("Unknown stream type {}".format(s_type), Gtk.MessageType.ERROR)
self._srv_id_entry.set_text(data[1])
self._srv_type_entry.set_text(data[2])
self._srv_type_entry.set_text(str(int(data[2], 16)))
self._sid_entry.set_text(str(int(data[3], 16)))
self._tr_id_entry.set_text(str(int(data[4], 16)))
self._net_id_entry.set_text(str(int(data[5], 16)))
@@ -216,7 +215,7 @@ class IptvDialog:
self.on_url_changed(self._url_entry)
self._reference_entry.set_text(_ENIGMA2_REFERENCE.format(self.get_type(),
self._srv_id_entry.get_text(),
self._srv_type_entry.get_text(),
int(self._srv_type_entry.get_text()),
int(self._sid_entry.get_text()),
int(self._tr_id_entry.get_text()),
int(self._net_id_entry.get_text()),
@@ -301,7 +300,7 @@ class IptvDialog:
name = self._name_entry.get_text().strip()
fav_id = ENIGMA2_FAV_ID_FORMAT.format(self.get_type(),
self._srv_id_entry.get_text(),
self._srv_type_entry.get_text(),
int(self._srv_type_entry.get_text()),
int(self._sid_entry.get_text()),
int(self._tr_id_entry.get_text()),
int(self._net_id_entry.get_text()),
@@ -602,7 +601,7 @@ class IptvListConfigurationDialog(IptvListDialog):
st_type = get_stream_type(self._stream_type_combobox)
s_id = "0" if id_default else self._list_srv_id_entry.get_text()
srv_type = "1" if type_default else self._list_srv_type_entry.get_text()
srv_type = int("1" if type_default else self._list_srv_type_entry.get_text())
sid = "0" if sid_auto else self._list_sid_entry.get_text()
tid = "0" if tid_default else f"{int(self._list_tid_entry.get_text()):X}"
nid = "0" if nid_default else f"{int(self._list_nid_entry.get_text()):X}"
@@ -617,12 +616,13 @@ class IptvListConfigurationDialog(IptvListDialog):
if all_default:
data[1], data[2], data[3], data[4], data[5], data[6] = "010000"
else:
data[0], data[1], data[2], data[4], data[5], data[6] = st_type, s_id, srv_type, tid, nid, namespace
data[0], data[1], data[4], data[5], data[6] = st_type, s_id, tid, nid, namespace
data[2] = f"{srv_type:X}"
data[3] = f"{index:X}" if sid_auto else sid
if sid_auto:
params[0] = index
picon_id = PICON_FORMAT.format(st_type, int(s_id), int(srv_type), *params)
picon_id = PICON_FORMAT.format(st_type, int(s_id), srv_type, *params)
data = ":".join(data)
new_fav_id = f"{data}{sep}{desc}"
row[Column.FAV_ID] = new_fav_id
@@ -891,7 +891,7 @@ class YtListImportDialog:
self._import_button.bind_property("sensitive", self._quality_box, "sensitive")
self._receive_button.bind_property("sensitive", self._import_button, "sensitive")
if IS_GNOME_SESSION or IS_DARWIN:
if self._settings.use_header_bar:
header_bar = HeaderBar(title="YouTube", subtitle=get_message("Playlist import"))
self._dialog.set_titlebar(header_bar)
actions_box = builder.get_object("yt_actions_box")

View File

@@ -898,7 +898,7 @@ Author: Dmitriy Yefremov
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="margin_bottom">2</property>
<property name="action_name">app.on_settings</property>
<property name="action_name">app.preferences</property>
<property name="text" translatable="yes">Settings</property>
</object>
<packing>
@@ -949,7 +949,7 @@ Author: Dmitriy Yefremov
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="action_name">app.on_about_app</property>
<property name="action_name">app.about</property>
<property name="text" translatable="yes">About</property>
</object>
<packing>
@@ -963,8 +963,8 @@ Author: Dmitriy Yefremov
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="action_name">app.quit</property>
<property name="text" translatable="yes">Exit</property>
<signal name="clicked" handler="on_close_app" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
@@ -1003,6 +1003,11 @@ Author: Dmitriy Yefremov
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-find-and-replace</property>
</object>
<object class="GtkImage" id="remove_duplicates_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">edit-select-all</property>
</object>
<object class="GtkImage" id="mark_not_in_bq_image">
<property name="visible">True</property>
@@ -1652,7 +1657,7 @@ Author: Dmitriy Yefremov
<object class="GtkLabel" id="app_ver_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label">3.4.0 Beta</property>
<property name="label">3.5.0 Beta</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
@@ -4751,6 +4756,17 @@ Author: Dmitriy Yefremov
<signal name="activate" handler="on_mark_duplicates" swapped="no"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="fav_remove_dup_popup_item">
<property name="label" translatable="yes">Remove duplicates</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="image">remove_duplicates_image</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_remove_duplicates" swapped="no"/>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="fav_popup_separator_3">
<property name="visible">True</property>

View File

@@ -48,7 +48,7 @@ from app.eparser.enigma.bouquets import BqServiceType
from app.eparser.iptv import export_to_m3u, StreamType
from app.eparser.neutrino.bouquets import BqType
from app.settings import (SettingsType, Settings, SettingsException, SettingsReadException,
IS_DARWIN, PlayStreamsMode, IS_LINUX)
IS_DARWIN, PlayStreamsMode, IS_LINUX, USE_HEADER_BAR)
from app.tools.media import Recorder
from app.ui.control import ControlTool
from app.ui.epg.epg import EpgCache, EpgSettingsPopover, EpgDialog, EpgTool
@@ -69,7 +69,7 @@ from .search import SearchProvider
from .service_details_dialog import ServiceDetailsDialog, Action
from .settings_dialog import SettingsDialog
from .uicommons import (Gtk, Gdk, UI_RESOURCES_PATH, LOCKED_ICON, HIDE_ICON, IPTV_ICON, MOVE_KEYS, KeyboardKey, Column,
FavClickMode, MOD_MASK, APP_FONT, Page, IS_GNOME_SESSION, HeaderBar)
FavClickMode, MOD_MASK, APP_FONT, Page, HeaderBar)
from .xml.dialogs import ServicesUpdateDialog
from .xml.edit import SatellitesTool
@@ -98,7 +98,8 @@ class Application(Gtk.Application):
_FAV_ELEMENTS = ("fav_cut_popup_item", "fav_paste_popup_item", "fav_locate_popup_item", "fav_iptv_popup_item",
"fav_insert_marker_popup_item", "fav_insert_space_popup_item", "fav_edit_sub_menu_popup_item",
"fav_edit_popup_item", "fav_picon_popup_item", "fav_copy_popup_item", "fav_add_alt_popup_item",
"fav_epg_configuration_popup_item", "fav_mark_dup_popup_item", "fav_reference_popup_item")
"fav_epg_configuration_popup_item", "fav_mark_dup_popup_item", "fav_remove_dup_popup_item",
"fav_reference_popup_item")
_BOUQUET_ELEMENTS = ("bouquets_new_popup_item", "bouquets_edit_popup_item", "bouquets_cut_popup_item",
"bouquets_copy_popup_item", "bouquets_paste_popup_item", "new_header_button",
@@ -174,6 +175,7 @@ class Application(Gtk.Application):
"on_fav_press": self.on_fav_press,
"on_locate_in_services": self.on_locate_in_services,
"on_mark_duplicates": self.on_mark_duplicates,
"on_remove_duplicates": self.on_remove_duplicates,
"on_services_mark_not_in_bouquets": self.on_services_mark_not_in_bouquets,
"on_services_clear_marked": self.on_services_clear_marked,
"on_services_clear_new_marked": self.on_services_clear_new_marked,
@@ -505,7 +507,7 @@ class Application(Gtk.Application):
# Header bar.
profile_box = builder.get_object("profile_combo_box")
toolbar_box = builder.get_object("toolbar_main_box")
if IS_GNOME_SESSION or IS_DARWIN:
if self._settings.use_header_bar:
header_bar = HeaderBar()
if not IS_DARWIN:
header_bar.pack_start(builder.get_object("file_header_button"))
@@ -647,9 +649,10 @@ class Application(Gtk.Application):
def init_app_menu(self):
builder = get_builder(UI_RESOURCES_PATH + "app_menu.ui", tag="attribute")
if not IS_GNOME_SESSION:
if not USE_HEADER_BAR:
if IS_DARWIN:
self.set_app_menu(builder.get_object("mac_app_menu"))
if not self.get_app_menu():
self.set_app_menu(builder.get_object("mac_app_menu"))
self.set_menubar(builder.get_object("mac_menu_bar"))
else:
self.set_menubar(builder.get_object("menu_bar"))
@@ -704,14 +707,17 @@ class Application(Gtk.Application):
self.set_action(action_name, ac)
def init_actions(self):
# Main actions.
self.set_action("preferences", self.on_settings)
self.set_action("about", self.on_about_app)
self.set_action("quit", self.on_close_app)
# Import.
self.set_action("on_import_bouquet", self.on_import_bouquet)
self.set_action("on_import_bouquets", self.on_import_bouquets)
self.set_action("on_new_configuration", self.on_new_configuration)
self.set_action("on_import_from_web", self.on_import_from_web)
self.set_action("on_settings", self.on_settings)
# Tools.
self.set_action("on_backup_tool_show", self.on_backup_tool_show)
self.set_action("on_about_app", self.on_about_app)
self.set_action("on_close_app", self.on_close_app)
self.set_state_action("on_telnet_show", self.on_telnet_show, False)
self.set_state_action("on_logs_show", self.on_logs_show, False)
# Filter.
@@ -768,9 +774,12 @@ class Application(Gtk.Application):
# Alternate layout.
sa = self.set_state_action("set_alternate_layout", self.set_use_alt_layout, self._settings.alternate_layout)
sa.connect("change-state", self.on_layout_change)
# Header bar for macOS.
sa = self.set_state_action("set_alternate_title", self.set_use_alt_title, self._settings.use_header_bar)
sa.set_enabled(IS_DARWIN)
# Menu bar and playback.
self.set_action("on_playback_close", self._player_box.on_close)
if not IS_GNOME_SESSION:
if not USE_HEADER_BAR:
# We are working with the "hidden-when" submenu attribute. See 'app_menu_.ui' file.
hide_bar_action = Gio.SimpleAction.new("hide_menu_bar", None)
self._player_box.bind_property("visible", hide_bar_action, "enabled", 4)
@@ -804,7 +813,7 @@ class Application(Gtk.Application):
self.set_accels_for_action("app.open_data", ["<primary>o"])
self.set_accels_for_action("app.on_hide", ["<primary>h"])
self.set_accels_for_action("app.on_locked", ["<primary>l"])
self.set_accels_for_action("app.on_close_app", ["<primary>q"])
self.set_accels_for_action("app.quit", ["<primary>q"])
self.set_accels_for_action("app.on_edit", ["<primary>e"])
self.set_accels_for_action("app.on_telnet_show", ["<primary>t"])
self.set_accels_for_action("app.on_logs_show", ["<shift><primary>l"])
@@ -1106,6 +1115,17 @@ class Application(Gtk.Application):
action.set_state(value)
self._settings.alternate_layout = bool(value)
def set_use_alt_title(self, action, value):
action.set_state(value)
value = bool(value)
self._settings.use_header_bar = bool(value)
msg = get_message("Restart the program to apply all changes.")
if value:
warn = "It can cause some problems."
msg = f"{get_message('EXPERIMENTAL!')} {warn} {msg}"
self.show_info_message(msg, Gtk.MessageType.WARNING)
@run_idle
def on_layout_change(self, action, value):
is_alt = bool(value)
@@ -2394,7 +2414,10 @@ class Application(Gtk.Application):
break
def append_services(self, services):
to_add = []
for srv in services:
if srv.fav_id not in self._services:
to_add.append(srv)
# Adding channels to dict with fav_id as keys.
self._services[srv.fav_id] = srv
self.update_services_counts(len(self._services.values()))
@@ -2402,7 +2425,7 @@ class Application(Gtk.Application):
self._services_load_spinner.start()
factor = self.DEL_FACTOR / 4
for index, srv in enumerate(services):
for index, srv in enumerate(to_add):
background = self.get_new_background(srv.flags_cas)
s = srv + (None, background)
self._services_model.append(s)
@@ -3228,23 +3251,23 @@ class Application(Gtk.Application):
ServicesUpdateDialog(self._main_window, self._settings, self.on_import_data_from_web).show()
@run_idle
def on_import_data_from_web(self, services):
def on_import_data_from_web(self, services, bouquets=None):
msg = "Combine with the current data?"
def clb():
self.show_info_message("Done!")
if len(self._services_model) > 0 and show_dialog(DialogType.QUESTION, self._main_window,
msg) == Gtk.ResponseType.OK:
gen = self.append_imported_data([], services)
GLib.idle_add(lambda: next(gen, False), priority=GLib.PRIORITY_LOW)
gen = self.append_imported_data(bouquets or [], services, clb)
else:
gen = self.import_data_from_web(services)
GLib.idle_add(lambda: next(gen, False), priority=GLib.PRIORITY_LOW)
gen = self.import_data_from_web(services, bouquets, clb)
GLib.idle_add(lambda: next(gen, False), priority=GLib.PRIORITY_LOW)
def import_data_from_web(self, services):
def import_data_from_web(self, services, bouquets, callback=None):
self._wait_dialog.show()
if self._app_info_box.get_visible():
yield from self.create_new_configuration(self._s_type)
yield from self.append_services(services)
self.update_sat_positions()
yield True
yield from self.create_new_configuration(self._s_type)
yield from self.append_imported_data(bouquets or [], services, callback)
self._wait_dialog.hide()
# ***************** Export ******************** #
@@ -3369,7 +3392,7 @@ class Application(Gtk.Application):
def on_playback_full_screen(self, box, state):
self._data_paned.set_visible(state)
self._main_window.unfullscreen() if state else self._main_window.fullscreen()
if not IS_GNOME_SESSION:
if not USE_HEADER_BAR:
self._main_window.set_show_menubar(state)
def on_playback_show(self, box):
@@ -4004,6 +4027,26 @@ class Application(Gtk.Application):
if r[Column.FAV_SERVICE] in dup:
r[Column.FAV_BACKGROUND] = self._NEW_COLOR
def on_remove_duplicates(self, item):
exist = set()
to_remove = []
for r in self._fav_model:
fav_id = r[Column.FAV_ID]
if fav_id in exist:
to_remove.append(r.iter)
else:
exist.add(fav_id)
count = len(to_remove)
if count:
if show_dialog(DialogType.QUESTION, self._main_window) != Gtk.ResponseType.OK:
return
gen = self.remove_favs(to_remove, self._fav_model)
GLib.idle_add(lambda: next(gen, False))
self.show_info_message(f"{get_message('Done!')} {get_message('Removed')}: {count}")
else:
self.show_info_message(f"{get_message('Done!')} {get_message('Found')}: {count}")
def on_services_mark_not_in_bouquets(self, item):
if self.is_data_loading():
self.show_error_message("Data loading in progress!")

View File

@@ -33,7 +33,7 @@ __all__ = ("insert_marker", "move_items", "rename", "ViewTarget", "set_flags", "
"is_only_one_item_selected", "gen_bouquets", "BqGenType", "get_selection", "get_service_reference",
"get_model_data", "remove_all_unused_picons", "get_picon_pixbuf", "get_base_itrs", "get_iptv_url",
"get_iptv_data", "update_entry_data", "append_text_to_tview", "on_popup_menu", "get_picon_file_name",
"update_toggle_model", "update_filter_sat_positions", "get_pos_num")
"update_toggle_model", "update_popup_filter_model", "update_filter_sat_positions", "get_pos_num")
import os
import re
@@ -610,8 +610,11 @@ def gen_bouquets(view, bq_view, transient, gen_type, s_type, callback):
callback(Bouquet(cond, bq_type, s_data.get(cond)), bq_root_iter)
else:
# We add a bouquet only if the given name is missing [keys - names]!
for name in sorted(s_data.keys() - bq_names):
callback(Bouquet(name, BqType.TV.value, s_data.get(name)), bq_root_iter)
if gen_type is BqGenType.EACH_SAT:
bq_names = sorted(s_data.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]
def get_bouquets_names(model):
@@ -711,12 +714,16 @@ def update_toggle_model(model, path, toggle):
model.set_value(model.get_iter_first(), 1, False)
def update_filter_sat_positions(model, sat_positions):
""" Updates the values for the satellite positions button model. """
def update_popup_filter_model(model, elements: set):
first = model[model.get_iter_first()][:]
model.clear()
model.append((first[0], True))
sat_positions.discard(first[0])
elements.discard(first[0])
def update_filter_sat_positions(model, sat_positions):
""" Updates the values for the satellite positions button model. """
update_popup_filter_model(model, sat_positions)
list(map(lambda pos: model.append((pos, True)), sorted(sat_positions, key=get_pos_num, reverse=True)))
@@ -755,7 +762,7 @@ def get_iptv_data(fav_id):
data, sep, desc = fav_id.partition("#DESCRIPTION")
data = data.split(":")
if len(data) < 11:
return None, None, desc
return None, desc
return ":".join(data[:10]), unquote(data[10].strip())

View File

@@ -34,17 +34,17 @@ from gi.repository import GLib, GObject, Gio
from app.commons import run_idle, run_with_delay
from app.connections import HttpAPI
from app.eparser.ecommons import BqServiceType
from app.settings import PlayStreamsMode, IS_DARWIN, SettingsType
from app.settings import PlayStreamsMode, IS_DARWIN, SettingsType, USE_HEADER_BAR
from app.tools.media import Player
from app.ui.dialogs import get_builder, get_message
from app.ui.main_helper import get_iptv_url
from app.ui.uicommons import Gtk, Gdk, UI_RESOURCES_PATH, FavClickMode, Column, IS_GNOME_SESSION, Page
from app.ui.uicommons import Gtk, Gdk, UI_RESOURCES_PATH, FavClickMode, Column, Page
class PlayerBox(Gtk.Box):
def __init__(self, app, *args, **kwargs):
super().__init__(*args, **kwargs)
def __init__(self, app, **kwargs):
super().__init__(**kwargs)
# Signals.
GObject.signal_new("playback-full-screen", self, GObject.SIGNAL_RUN_LAST,
GObject.TYPE_PYOBJECT, (GObject.TYPE_PYOBJECT,))
@@ -108,6 +108,9 @@ class PlayerBox(Gtk.Box):
if mode is not FavClickMode.STREAM and not self._app.http_api:
return
if len(self._fav_view.get_model()) == 0:
return
self._fav_view.set_sensitive(False)
if mode is FavClickMode.STREAM:
self.on_play_stream()
@@ -191,7 +194,7 @@ class PlayerBox(Gtk.Box):
video_menu = builder.get_object("video_menu")
subtitle_menu = builder.get_object("subtitle_menu")
if not IS_GNOME_SESSION:
if not USE_HEADER_BAR:
menu_bar = self._app.get_menubar()
menu_bar.insert_section(1, None, audio_menu)
menu_bar.insert_section(2, None, video_menu)

View File

@@ -1671,47 +1671,137 @@ Author: Dmitriy Yefremov
</packing>
</child>
<child>
<object class="GtkFrame" id="load_on_startup_frame">
<object class="GtkFrame" id="program_options_frame">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label-xalign">0</property>
<property name="shadow-type">in</property>
<child>
<object class="GtkBox" id="load_on_startup_box">
<object class="GtkBox" id="program_options_box">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-start">5</property>
<property name="margin-end">5</property>
<property name="margin-top">5</property>
<property name="margin-bottom">5</property>
<property name="orientation">vertical</property>
<property name="spacing">5</property>
<child>
<object class="GtkLabel" id="load_on_startup_label">
<object class="GtkBox" id="load_on_startup_box">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="margin-top">5</property>
<property name="margin-bottom">5</property>
<property name="label" translatable="yes">Load the last open configuration at program startup</property>
<child>
<object class="GtkLabel" id="load_on_startup_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="margin-top">5</property>
<property name="margin-bottom">5</property>
<property name="label" translatable="yes">Load the last open configuration at program startup</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSwitch" id="load_on_startup_switch">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="valign">center</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSwitch" id="load_on_startup_switch">
<object class="GtkBox" id="enable_extensions_box">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="valign">center</property>
<property name="can-focus">False</property>
<property name="tooltip-text" translatable="yes">EXPERIMENTAL!</property>
<child>
<object class="GtkLabel" id="enable_extensions_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="hexpand">True</property>
<property name="label" translatable="yes">Enable extensions support</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSwitch" id="enable_extensions_switch">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="halign">end</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox" id="enable_http_box">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkLabel" id="enable_http_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="hexpand">True</property>
<property name="label" translatable="yes">Enable HTTP API</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSwitch" id="support_http_api_switch">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="halign">end</property>
<signal name="state-set" handler="on_http_mode_switch" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
<child type="label_item">
@@ -1882,59 +1972,6 @@ Author: Dmitriy Yefremov
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkFrame" id="http_frame">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label-xalign">0.019999999552965164</property>
<property name="shadow-type">in</property>
<child>
<object class="GtkBox" id="enable_http_box">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-start">5</property>
<property name="margin-end">5</property>
<property name="margin-top">5</property>
<property name="margin-bottom">5</property>
<child>
<object class="GtkLabel" id="enable_http_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="hexpand">True</property>
<property name="label" translatable="yes">Enable HTTP API</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSwitch" id="support_http_api_switch">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="halign">end</property>
<signal name="state-set" handler="on_http_mode_switch" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
<child type="label_item">
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
</object>
<packing>
<property name="name">program</property>
@@ -3029,45 +3066,6 @@ Author: Dmitriy Yefremov
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox" id="enable_extensions_box">
<property name="visible">True</property>
<property name="sensitive" bind-source="enable_experimental_switch" bind-property="active">False</property>
<property name="can-focus">False</property>
<child>
<object class="GtkLabel" id="enable_extensions_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="hexpand">True</property>
<property name="label" translatable="yes">Enable extensions support</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSwitch" id="enable_extensions_switch">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="halign">end</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkBox" id="yt_dl_box">
<property name="visible">True</property>

View File

@@ -32,10 +32,10 @@ from collections import Counter
from app.commons import run_task, run_idle, log
from app.connections import test_telnet, test_ftp, TestException, test_http, HttpApiException
from app.settings import SettingsType, Settings, PlayStreamsMode, IS_LINUX, SEP, IS_WIN, IS_DARWIN
from app.settings import SettingsType, Settings, PlayStreamsMode, IS_LINUX, SEP, IS_WIN
from app.ui.dialogs import show_dialog, DialogType, get_message, get_chooser_dialog, get_builder
from .main_helper import update_entry_data, scroll_to, get_picon_pixbuf
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, FavClickMode, DEFAULT_ICON, APP_FONT, IS_GNOME_SESSION, HeaderBar
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, FavClickMode, DEFAULT_ICON, APP_FONT, HeaderBar
class SettingsDialog:
@@ -208,7 +208,7 @@ class SettingsDialog:
[self.init_element_style(el, screen, style_provider) for el in self._digit_elems]
self.init_element_style(self._host_field, screen, style_provider)
if IS_GNOME_SESSION or IS_DARWIN:
if self._settings.use_header_bar:
switcher = builder.get_object("main_stack_switcher")
switcher.set_margin_top(0)
switcher.set_margin_bottom(0)
@@ -519,7 +519,6 @@ class SettingsDialog:
if not state:
self._support_ver5_switch.set_active(state)
self._unlimited_buffer_switch.set_active(state)
self._enable_extensions_switch.set_active(state)
self._enable_send_to_switch.set_active(state)
self._enable_yt_dl_switch.set_active(state)

View File

@@ -31,9 +31,10 @@ from datetime import datetime, timedelta
from enum import Enum
from urllib.parse import quote
from app.settings import USE_HEADER_BAR
from app.ui.main_helper import on_popup_menu
from .dialogs import get_builder, get_message, show_dialog, DialogType
from .uicommons import Gtk, Gdk, GLib, UI_RESOURCES_PATH, Page, Column, KeyboardKey, IS_GNOME_SESSION, MOD_MASK
from .uicommons import Gtk, Gdk, GLib, UI_RESOURCES_PATH, Page, Column, KeyboardKey, MOD_MASK
from ..commons import run_idle, log
from ..connections import HttpAPI
from ..eparser.ecommons import BqServiceType
@@ -56,7 +57,7 @@ class TimerTool(Gtk.Box):
class TimerDialog(Gtk.Dialog):
def __init__(self, parent, action=None, timer_data=None, *args, **kwargs):
super().__init__(use_header_bar=IS_GNOME_SESSION, *args, **kwargs)
super().__init__(use_header_bar=USE_HEADER_BAR, *args, **kwargs)
self._action = action or TimerTool.TimerAction.ADD
self._timer_data = timer_data or {}

View File

@@ -2,7 +2,7 @@
#
# The MIT License (MIT)
#
# Copyright (c) 2018-2022 Dmitriy Yefremov
# Copyright (c) 2018-2023 Dmitriy Yefremov
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -52,7 +52,6 @@ TEXT_DOMAIN = "demon-editor"
NOTIFY_IS_INIT = False
APP_FONT = None
IS_GNOME_SESSION = int(bool(os.environ.get("GNOME_DESKTOP_SESSION_ID")))
try:
settings = Settings.get_instance()
@@ -164,6 +163,7 @@ def show_notification(message, timeout=10000, urgency=1):
class HeaderBar(Gtk.HeaderBar):
""" Custom header bar widget. """
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.set_visible(True)

View File

@@ -30,6 +30,8 @@ import concurrent.futures
import os
import re
import time
from collections import OrderedDict
from itertools import groupby
from math import fabs
from gi.repository import GLib
@@ -38,13 +40,14 @@ from app.commons import run_idle, run_task, log
from app.eparser import Satellite, Transponder
from app.eparser.ecommons import (PLS_MODE, get_key_by_value, POLARIZATION, FEC, SYSTEM, MODULATION, Terrestrial, Cable,
T_SYSTEM, BANDWIDTH, CONSTELLATION, T_FEC, GUARD_INTERVAL, TRANSMISSION_MODE,
HIERARCHY, Inversion, C_MODULATION, FEC_DEFAULT, TerTransponder, CableTransponder)
from app.settings import IS_DARWIN
HIERARCHY, Inversion, C_MODULATION, FEC_DEFAULT, TerTransponder, CableTransponder,
Bouquet, BouquetService, BqServiceType, Bouquets, BqType)
from app.settings import USE_HEADER_BAR
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 ..search import SearchProvider
from ..uicommons import Gtk, Gdk, UI_RESOURCES_PATH, IS_GNOME_SESSION, HeaderBar
from ..uicommons import Gtk, Gdk, UI_RESOURCES_PATH, HeaderBar
_DIALOGS_UI_PATH = f"{UI_RESOURCES_PATH}xml{os.sep}dialogs.glade"
@@ -61,7 +64,7 @@ class DVBDialog(Gtk.Dialog):
skip_taskbar_hint=True,
skip_pager_hint=True,
destroy_with_parent=True,
use_header_bar=IS_GNOME_SESSION,
use_header_bar=USE_HEADER_BAR,
window_position=Gtk.WindowPosition.CENTER_ON_PARENT,
buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OK, Gtk.ResponseType.OK),
*args, **kwargs)
@@ -435,6 +438,8 @@ class UpdateDialog:
self._sat_view.bind_property("sensitive", self._source_box, "sensitive")
self._sat_view.bind_property("sensitive", self._receive_button, "sensitive")
self._receive_button.bind_property("visible", update_button, "visible")
self._left_action_box = builder.get_object("sat_update_left_action_box")
self._right_action_box = builder.get_object("sat_update_right_action_box")
# Filter
self._filter_bar = builder.get_object("sat_update_filter_bar")
self._from_pos_button = builder.get_object("from_pos_button")
@@ -456,19 +461,19 @@ class UpdateDialog:
builder.get_object("sat_update_search_down_button"),
builder.get_object("sat_update_search_up_button"))
builder.get_object("sat_update_find_button").connect("toggled", search_provider.on_search_toggled)
# Satellite lists init on dialog start.
self._sat_view.connect("realize", self.on_update_satellites_list)
if IS_GNOME_SESSION or IS_DARWIN:
if self._settings.use_header_bar:
header_bar = HeaderBar()
builder.get_object("sat_update_header").set_visible(False)
header_box = builder.get_object("satellites_update_header_box")
header_box.remove(self._source_box)
header_bar.pack_start(self._source_box)
action_box = builder.get_object("sat_update_left_action_box")
header_box.remove(action_box)
header_bar.pack_start(action_box)
action_box = builder.get_object("sat_update_right_action_box")
header_box.remove(action_box)
header_bar.pack_end(action_box)
header_box.remove(self._left_action_box)
header_bar.pack_start(self._left_action_box)
header_box.remove(self._right_action_box)
header_bar.pack_end(self._right_action_box)
self._window.set_titlebar(header_bar)
window_size = self._settings.get(self._size_name)
@@ -497,11 +502,11 @@ class UpdateDialog:
self.is_download = True
self._sat_view.set_sensitive(False)
src = self._source_box.get_active()
if not self._parser:
self._parser = SatellitesParser()
self.get_sat_list(src, self.append_satellites)
self.get_sat_list(self._source_box.get_active(), self.append_satellites)
def clear_data(self):
get_base_model(self._sat_view.get_model()).clear()
@@ -531,6 +536,7 @@ class UpdateDialog:
self._sat_view.set_sensitive(True)
self._satellites_count_label.set_text(str(len(model)))
self.update_receive_button_state(self._filter_model)
@run_idle
def on_receive_data(self, item):
@@ -710,7 +716,7 @@ class ServicesUpdateDialog(UpdateDialog):
self._services = {}
self._selected_transponders = set()
self._services_parser = ServicesParser(source=SatelliteSource.LYNGSAT)
# Transponder view popup menu
# Transponder view popup menu.
tr_popup_menu = Gtk.Menu()
select_all_item = Gtk.ImageMenuItem.new_from_stock("gtk-select-all")
select_all_item.connect("activate", lambda w: self.update_transponder_selection(True))
@@ -728,6 +734,41 @@ class ServicesUpdateDialog(UpdateDialog):
self._transponder_paned.set_visible(True)
self._source_box.connect("changed", self.on_update_satellites_list)
self._source_box.connect("changed", self.on_source_changed)
# Options for KingOfSat source.
popover = Gtk.Popover()
main_options_box = Gtk.Box(spacing=5, margin_left=10, margin_right=10, orientation=Gtk.Orientation.VERTICAL)
self._kos_bq_groups_switch = Gtk.Switch()
self._kos_bq_lang_switch = Gtk.Switch()
self._kos_options_box = Gtk.Box(spacing=5, orientation=Gtk.Orientation.VERTICAL)
box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5, margin_top=5)
box.pack_start(Gtk.Label(get_message("Create Category bouquets")), False, True, 0)
box.pack_end(self._kos_bq_groups_switch, False, True, 0)
self._kos_options_box.add(box)
box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5, margin_bottom=5)
box.pack_start(Gtk.Label(get_message("Create Regional bouquets")), False, True, 0)
box.pack_end(self._kos_bq_lang_switch, False, True, 0)
self._kos_options_box.add(box)
main_options_box.add(self._kos_options_box)
# General options.
self._general_options_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
self._skip_c_band_switch = Gtk.Switch()
box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5, margin_top=5)
box.pack_start(Gtk.Label(get_message("Skip C-band")), False, True, 0)
box.pack_end(self._skip_c_band_switch, False, True, 0)
self._general_options_box.add(box)
main_options_box.add(self._general_options_box)
main_options_box.add(Gtk.ModelButton(get_message("Close"), margin_bottom=5))
main_options_box.show_all()
popover.add(main_options_box)
# Options button.
option_button_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5)
option_button_box.add(Gtk.Image.new_from_icon_name("applications-system-symbolic", Gtk.IconSize.BUTTON))
option_button_box.add(Gtk.Label(get_message("Options")))
menu_button = Gtk.MenuButton(popover=popover)
menu_button.add(option_button_box)
menu_button.show_all()
self._right_action_box.pack_end(menu_button, False, False, 0)
@run_idle
def on_receive_data(self, item):
@@ -737,6 +778,14 @@ class ServicesUpdateDialog(UpdateDialog):
self.receive_services()
def on_source_changed(self, itme):
is_kos = itme.get_active_id() == SatelliteSource.KINGOFSAT.name
self._kos_options_box.set_sensitive(is_kos)
if not is_kos:
self._kos_bq_groups_switch.set_active(False)
self._kos_bq_lang_switch.set_active(False)
self._kos_options_box.set_tooltip_text(None if is_kos else get_message("KingOfSat only!"))
@run_task
def receive_services(self):
self.is_download = True
@@ -805,6 +854,7 @@ class ServicesUpdateDialog(UpdateDialog):
log(f"Getting services error: {e} [{t_names.get(futures[future])}]")
appender.send("-" * 75 + "\n")
services = OrderedDict({s.fav_id: s for s in services}).values()
appender.send(f"Consumed: {time.time() - start:0.0f}s, {len(services)} services received.")
try:
@@ -815,10 +865,38 @@ class ServicesUpdateDialog(UpdateDialog):
except ValueError as e:
log(f"ServicesUpdateDialog [on receive data] error: {e}")
else:
self._callback(srvs)
bouquets = None
if self._source_box.get_active_id() == SatelliteSource.KINGOFSAT.name:
bouquets = self.get_bouquets(srvs, services)
def c_filter(s):
try:
return int(s.freq) > 10000
except ValueError:
return False
self._callback(filter(c_filter, srvs) if self._skip_c_band_switch.get_active() else srvs, bouquets)
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)]
if self._kos_bq_groups_switch.get_active():
self.gen_bouquet_group(services, bouquets, lambda s: s[4] or "")
if self._kos_bq_lang_switch.get_active():
self.gen_bouquet_group(services, bouquets, lambda s: s[5] or "")
return Bouquets("", BqType.TV.value, bouquets),
def gen_bouquet_group(self, services, bouquets, grouper):
""" Generates bouquets depending on <grouper>. """
s_type = BqServiceType.DEFAULT
[bouquets.append(Bouquet(name=g[0], type=BqType.TV.name,
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]]
@run_task
def get_sat_list(self, src, callback):
sat_src = SatelliteSource.LYNGSAT

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.2
<!-- Generated with glade 3.38.2
The MIT License (MIT)
@@ -35,29 +35,29 @@ Author: Dmitriy Yefremov
<!-- interface-authors Dmitriy Yefremov -->
<object class="GtkAdjustment" id="pos_adjustment">
<property name="upper">180</property>
<property name="step_increment">0.10000000000000001</property>
<property name="page_increment">10</property>
<property name="step-increment">0.10</property>
<property name="page-increment">10</property>
</object>
<object class="GtkAdjustment" id="pos_adjustment2">
<property name="upper">180</property>
<property name="step_increment">0.10000000000000001</property>
<property name="page_increment">10</property>
<property name="step-increment">0.10</property>
<property name="page-increment">10</property>
</object>
<object class="GtkImage" id="remove_selection_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">edit-undo</property>
<property name="can-focus">False</property>
<property name="icon-name">edit-undo</property>
</object>
<object class="GtkMenu" id="satellites_update_popup_menu">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<child>
<object class="GtkImageMenuItem" id="select_all_popup_item">
<property name="label">gtk-select-all</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<property name="can-focus">False</property>
<property name="use-underline">True</property>
<property name="use-stock">True</property>
<signal name="activate" handler="on_select_all" object="sat_update_tree_view" swapped="no"/>
</object>
</child>
@@ -65,29 +65,29 @@ Author: Dmitriy Yefremov
<object class="GtkImageMenuItem" id="unselect_all_popup_item">
<property name="label" translatable="yes">Remove selection</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<property name="image">remove_selection_image</property>
<property name="use_stock">False</property>
<property name="use-stock">False</property>
<signal name="activate" handler="on_unselect_all" object="sat_update_tree_view" swapped="no"/>
</object>
</child>
</object>
<object class="GtkImage" id="sat_receive_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">network-receive-symbolic</property>
<property name="can-focus">False</property>
<property name="icon-name">network-receive-symbolic</property>
<property name="icon_size">1</property>
</object>
<object class="GtkImage" id="sat_update_cancel_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">window-close-symbolic</property>
<property name="can-focus">False</property>
<property name="icon-name">window-close-symbolic</property>
<property name="icon_size">1</property>
</object>
<object class="GtkImage" id="sat_update_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">emblem-synchronizing-symbolic</property>
<property name="can-focus">False</property>
<property name="icon-name">emblem-synchronizing-symbolic</property>
<property name="icon_size">1</property>
</object>
<object class="GtkListStore" id="side_store">
@@ -119,7 +119,7 @@ Author: Dmitriy Yefremov
</columns>
</object>
<object class="GtkTreeModelFilter" id="update_sat_list_model_filter">
<property name="child_model">update_sat_list_store</property>
<property name="child-model">update_sat_list_store</property>
</object>
<object class="GtkTreeModelSort" id="update_sat_list_model_sort">
<property name="model">update_sat_list_model_filter</property>
@@ -151,42 +151,39 @@ Author: Dmitriy Yefremov
</columns>
</object>
<object class="GtkWindow" id="satellites_update_window">
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<property name="title" translatable="yes">Satellites update</property>
<property name="modal">True</property>
<property name="window_position">center-on-parent</property>
<property name="destroy_with_parent">True</property>
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<property name="window-position">center-on-parent</property>
<property name="destroy-with-parent">True</property>
<property name="skip-taskbar-hint">True</property>
<property name="skip-pager-hint">True</property>
<signal name="delete-event" handler="on_quit" swapped="no"/>
<child type="titlebar">
<placeholder/>
</child>
<child>
<object class="GtkBox" id="satellites_update_main_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkBox" id="sat_update_header">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkBox" id="satellites_update_header_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">15</property>
<property name="margin_right">15</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="can-focus">False</property>
<property name="margin-left">15</property>
<property name="margin-right">15</property>
<property name="margin-top">5</property>
<property name="margin-bottom">5</property>
<property name="spacing">5</property>
<child>
<object class="GtkComboBoxText" id="source_combo_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Source</property>
<property name="active">0</property>
<property name="can-focus">False</property>
<property name="tooltip-text" translatable="yes">Source</property>
<property name="active-id">KINGOFSAT</property>
<items>
<item id="LYNGSAT" translatable="yes">LyngSat</item>
<item id="KINGOFSAT" translatable="yes">KingOfSat</item>
@@ -201,17 +198,17 @@ Author: Dmitriy Yefremov
<child>
<object class="GtkButtonBox" id="sat_update_left_action_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="layout_style">expand</property>
<property name="can-focus">False</property>
<property name="layout-style">expand</property>
<child>
<object class="GtkButton" id="sat_update_button">
<property name="label" translatable="yes">Update</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Update</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="tooltip-text" translatable="yes">Update</property>
<property name="image">sat_update_image</property>
<property name="always_show_image">True</property>
<property name="always-show-image">True</property>
<signal name="clicked" handler="on_update_satellites_list" swapped="no"/>
</object>
<packing>
@@ -221,15 +218,15 @@ Author: Dmitriy Yefremov
</packing>
</child>
<child>
<object class="GtkButton" id="receive_data_button">
<property name="label" translatable="yes">Receive</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Receive</property>
<property name="image">sat_receive_image</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="on_receive_data" swapped="no"/>
<object class="GtkButton" id="cancel_data_button">
<property name="label" translatable="yes">Cancel</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="tooltip-text" translatable="yes">Cancel</property>
<property name="image">sat_update_cancel_image</property>
<property name="always-show-image">True</property>
<signal name="clicked" handler="on_cancel_receive" swapped="no"/>
<accelerator key="z" signal="clicked" modifiers="Primary"/>
</object>
<packing>
<property name="expand">False</property>
@@ -238,15 +235,16 @@ Author: Dmitriy Yefremov
</packing>
</child>
<child>
<object class="GtkButton" id="cancel_data_button">
<property name="label" translatable="yes">Cancel</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Cancel</property>
<property name="image">sat_update_cancel_image</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="on_cancel_receive" swapped="no"/>
<accelerator key="z" signal="clicked" modifiers="Primary"/>
<object class="GtkButton" id="receive_data_button">
<property name="label" translatable="yes">Receive</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="tooltip-text" translatable="yes">Receive</property>
<property name="image">sat_receive_image</property>
<property name="always-show-image">True</property>
<signal name="clicked" handler="on_receive_data" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
@@ -262,63 +260,75 @@ Author: Dmitriy Yefremov
</packing>
</child>
<child>
<object class="GtkButtonBox" id="sat_update_right_action_box">
<object class="GtkBox" id="sat_update_right_action_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="layout_style">expand</property>
<property name="can-focus">False</property>
<property name="spacing">5</property>
<child>
<object class="GtkToggleButton" id="sat_update_filter_button">
<object class="GtkButtonBox" id="sat_update_fs_box">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Filter</property>
<property name="always_show_image">True</property>
<signal name="toggled" handler="on_filter_toggled" swapped="no"/>
<property name="can-focus">False</property>
<property name="layout-style">expand</property>
<child>
<object class="GtkImage" id="sat_update_filter_image">
<object class="GtkToggleButton" id="sat_update_filter_button">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">edit-find-replace-symbolic</property>
<property name="icon_size">1</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="tooltip-text" translatable="yes">Filter</property>
<property name="always-show-image">True</property>
<signal name="toggled" handler="on_filter_toggled" swapped="no"/>
<child>
<object class="GtkImage" id="sat_update_filter_image">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">edit-find-replace-symbolic</property>
<property name="icon_size">1</property>
</object>
</child>
<accelerator key="f" signal="clicked" modifiers="GDK_SHIFT_MASK | Primary"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkToggleButton" id="sat_update_find_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="tooltip-text" translatable="yes">Find</property>
<property name="always-show-image">True</property>
<signal name="toggled" handler="on_find_toggled" swapped="no"/>
<child>
<object class="GtkImage" id="sat_update_search_image">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">edit-find-symbolic</property>
<property name="icon_size">1</property>
</object>
</child>
<accelerator key="f" signal="clicked" modifiers="Primary"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<accelerator key="f" signal="clicked" modifiers="GDK_SHIFT_MASK | Primary"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkToggleButton" id="sat_update_find_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Find</property>
<property name="always_show_image">True</property>
<signal name="toggled" handler="on_find_toggled" swapped="no"/>
<child>
<object class="GtkImage" id="sat_update_search_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">edit-find-symbolic</property>
<property name="icon_size">1</property>
</object>
</child>
<accelerator key="f" signal="clicked" modifiers="Primary"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="pack-type">end</property>
<property name="position">3</property>
</packing>
</child>
@@ -341,21 +351,21 @@ Author: Dmitriy Yefremov
</child>
<child>
<object class="GtkSearchBar" id="sat_update_search_bar">
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<child>
<object class="GtkBox" id="search_bar_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">2</property>
<property name="margin_bottom">2</property>
<property name="can-focus">False</property>
<property name="margin-top">2</property>
<property name="margin-bottom">2</property>
<child>
<object class="GtkSearchEntry" id="sat_update_search_entry">
<property name="width_request">200</property>
<property name="width-request">200</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="primary_icon_name">edit-find-symbolic</property>
<property name="primary_icon_activatable">False</property>
<property name="primary_icon_sensitive">False</property>
<property name="can-focus">True</property>
<property name="primary-icon-name">edit-find-symbolic</property>
<property name="primary-icon-activatable">False</property>
<property name="primary-icon-sensitive">False</property>
</object>
<packing>
<property name="expand">False</property>
@@ -367,13 +377,13 @@ Author: Dmitriy Yefremov
<object class="GtkButton" id="sat_update_search_down_button">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkArrow" id="arrow1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="arrow_type">down</property>
<property name="can-focus">False</property>
<property name="arrow-type">down</property>
</object>
</child>
</object>
@@ -387,13 +397,13 @@ Author: Dmitriy Yefremov
<object class="GtkButton" id="sat_update_search_up_button">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkArrow" id="arrow2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="arrow_type">up</property>
<property name="can-focus">False</property>
<property name="arrow-type">up</property>
</object>
</child>
</object>
@@ -417,44 +427,45 @@ Author: Dmitriy Yefremov
</child>
<child>
<object class="GtkSearchBar" id="sat_update_filter_bar">
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<child>
<!-- n-columns=7 n-rows=1 -->
<object class="GtkGrid" id="source_header_grid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">2</property>
<property name="margin_bottom">2</property>
<property name="column_spacing">2</property>
<property name="can-focus">False</property>
<property name="margin-top">2</property>
<property name="margin-bottom">2</property>
<property name="column-spacing">2</property>
<child>
<object class="GtkLabel" id="from_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">From:</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="from_pos_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="input_purpose">number</property>
<property name="can-focus">True</property>
<property name="input-purpose">number</property>
<property name="adjustment">pos_adjustment</property>
<property name="digits">1</property>
<property name="numeric">True</property>
<signal name="changed" handler="on_filter" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
<property name="left-attach">1</property>
<property name="top-attach">0</property>
</packing>
</child>
<child>
<object class="GtkComboBox" id="filter_from_combo_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<property name="model">side_store</property>
<property name="active">0</property>
<signal name="changed" handler="on_filter" swapped="no"/>
@@ -466,40 +477,40 @@ Author: Dmitriy Yefremov
</child>
</object>
<packing>
<property name="left_attach">2</property>
<property name="top_attach">0</property>
<property name="left-attach">2</property>
<property name="top-attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="to_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">To:</property>
</object>
<packing>
<property name="left_attach">3</property>
<property name="top_attach">0</property>
<property name="left-attach">3</property>
<property name="top-attach">0</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="to_pos_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="input_purpose">number</property>
<property name="can-focus">True</property>
<property name="input-purpose">number</property>
<property name="adjustment">pos_adjustment2</property>
<property name="digits">1</property>
<property name="numeric">True</property>
<signal name="changed" handler="on_filter" swapped="no"/>
</object>
<packing>
<property name="left_attach">4</property>
<property name="top_attach">0</property>
<property name="left-attach">4</property>
<property name="top-attach">0</property>
</packing>
</child>
<child>
<object class="GtkComboBox" id="filter_to_combo_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<property name="model">side_store</property>
<property name="active">0</property>
<signal name="changed" handler="on_filter" swapped="no"/>
@@ -511,22 +522,22 @@ Author: Dmitriy Yefremov
</child>
</object>
<packing>
<property name="left_attach">5</property>
<property name="top_attach">0</property>
<property name="left-attach">5</property>
<property name="top-attach">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="filter_apply_button">
<property name="label">gtk-apply</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="use-stock">True</property>
<signal name="clicked" handler="on_filter" swapped="no"/>
</object>
<packing>
<property name="left_attach">6</property>
<property name="top_attach">0</property>
<property name="left-attach">6</property>
<property name="top-attach">0</property>
</packing>
</child>
</object>
@@ -541,40 +552,40 @@ Author: Dmitriy Yefremov
<child>
<object class="GtkPaned" id="sat_update_main_paned">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="wide_handle">True</property>
<property name="can-focus">True</property>
<property name="margin-left">5</property>
<property name="margin-right">5</property>
<property name="margin-top">5</property>
<property name="margin-bottom">5</property>
<property name="wide-handle">True</property>
<child>
<object class="GtkFrame" id="sat_update_frame">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0.49000000953674316</property>
<property name="shadow_type">in</property>
<property name="can-focus">False</property>
<property name="label-xalign">0.49000000953674316</property>
<property name="shadow-type">in</property>
<child>
<object class="GtkBox" id="sat_update_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="can-focus">False</property>
<property name="margin-left">5</property>
<property name="margin-right">5</property>
<property name="margin-top">5</property>
<property name="margin-bottom">5</property>
<property name="orientation">vertical</property>
<property name="spacing">5</property>
<child>
<object class="GtkScrolledWindow" id="sat_update_scrolled_window">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<property name="can-focus">True</property>
<property name="shadow-type">in</property>
<child>
<object class="GtkTreeView" id="sat_update_tree_view">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can-focus">True</property>
<property name="model">update_sat_list_model_sort</property>
<property name="search_column">0</property>
<property name="activate_on_single_click">True</property>
<property name="search-column">0</property>
<property name="activate-on-single-click">True</property>
<signal name="button-press-event" handler="on_popup_menu" object="satellites_update_popup_menu" swapped="no"/>
<signal name="select-all" handler="on_select_all" swapped="no"/>
<child internal-child="selection">
@@ -589,10 +600,10 @@ Author: Dmitriy Yefremov
<property name="clickable">True</property>
<property name="alignment">0.5</property>
<property name="reorderable">True</property>
<property name="sort_column_id">0</property>
<property name="sort-column-id">0</property>
<child>
<object class="GtkCellRendererText" id="upd_satellite_cellrenderertext">
<property name="xalign">0.0099999997764825821</property>
<property name="xalign">0.009999999776482582</property>
<property name="ellipsize">end</property>
</object>
<attributes>
@@ -607,7 +618,7 @@ Author: Dmitriy Yefremov
<property name="clickable">True</property>
<property name="alignment">0.5</property>
<property name="reorderable">True</property>
<property name="sort_column_id">1</property>
<property name="sort-column-id">1</property>
<child>
<object class="GtkCellRendererText" id="upd_position_cellrenderertext">
<property name="xalign">0.49000000953674316</property>
@@ -624,7 +635,7 @@ Author: Dmitriy Yefremov
<property name="clickable">True</property>
<property name="alignment">0.5</property>
<property name="reorderable">True</property>
<property name="sort_column_id">2</property>
<property name="sort-column-id">2</property>
<child>
<object class="GtkCellRendererText" id="upd_type_cellrenderertext">
<property name="xalign">0.49000000953674316</property>
@@ -652,7 +663,7 @@ Author: Dmitriy Yefremov
<property name="title" translatable="yes">Selected</property>
<property name="clickable">True</property>
<property name="reorderable">True</property>
<property name="sort_column_id">4</property>
<property name="sort-column-id">4</property>
<child>
<object class="GtkCellRendererToggle" id="upd_selected_cellrenderer">
<signal name="toggled" handler="on_satellite_toggled" swapped="no"/>
@@ -675,15 +686,15 @@ Author: Dmitriy Yefremov
<child>
<object class="GtkBox" id="sat_update_status_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">10</property>
<property name="margin_right">10</property>
<property name="can-focus">False</property>
<property name="margin-left">10</property>
<property name="margin-right">10</property>
<property name="spacing">5</property>
<child>
<object class="GtkImage" id="satellites_count_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">document-properties-symbolic</property>
<property name="can-focus">False</property>
<property name="icon-name">document-properties-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
@@ -694,7 +705,7 @@ Author: Dmitriy Yefremov
<child>
<object class="GtkLabel" id="satellites_count_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<property name="label">0</property>
</object>
<packing>
@@ -715,7 +726,7 @@ Author: Dmitriy Yefremov
<child type="label">
<object class="GtkLabel" id="sat_update_frame_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Satellites</property>
</object>
</child>
@@ -727,37 +738,37 @@ Author: Dmitriy Yefremov
</child>
<child>
<object class="GtkPaned" id="sat_update_tr_paned">
<property name="can_focus">True</property>
<property name="can-focus">True</property>
<property name="orientation">vertical</property>
<property name="wide_handle">True</property>
<property name="wide-handle">True</property>
<child>
<object class="GtkFrame" id="sat_update_tr_frame">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0.49000000953674316</property>
<property name="shadow_type">in</property>
<property name="can-focus">False</property>
<property name="label-xalign">0.49000000953674316</property>
<property name="shadow-type">in</property>
<child>
<object class="GtkBox" id="sat_update_tr_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="can-focus">False</property>
<property name="margin-left">5</property>
<property name="margin-right">5</property>
<property name="margin-top">5</property>
<property name="margin-bottom">5</property>
<property name="orientation">vertical</property>
<property name="spacing">5</property>
<child>
<object class="GtkScrolledWindow" id="sat_update_tr_scrolled_window">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<property name="can-focus">True</property>
<property name="shadow-type">in</property>
<child>
<object class="GtkTreeView" id="sat_update_tr_view">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can-focus">True</property>
<property name="model">update_transponder_store</property>
<property name="search_column">0</property>
<property name="activate_on_single_click">True</property>
<property name="search-column">0</property>
<property name="activate-on-single-click">True</property>
<child internal-child="selection">
<object class="GtkTreeSelection"/>
</child>
@@ -768,7 +779,7 @@ Author: Dmitriy Yefremov
<property name="alignment">0.5</property>
<child>
<object class="GtkCellRendererText" id="upd_tr_renderer">
<property name="xalign">0.0099999997764825821</property>
<property name="xalign">0.009999999776482582</property>
</object>
<attributes>
<attribute name="text">0</attribute>
@@ -813,15 +824,15 @@ Author: Dmitriy Yefremov
<child>
<object class="GtkBox" id="sat_update_tr_status_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">10</property>
<property name="margin_right">10</property>
<property name="can-focus">False</property>
<property name="margin-left">10</property>
<property name="margin-right">10</property>
<property name="spacing">5</property>
<child>
<object class="GtkImage" id="transponders_count_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">document-properties-symbolic</property>
<property name="can-focus">False</property>
<property name="icon-name">document-properties-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
@@ -832,7 +843,7 @@ Author: Dmitriy Yefremov
<child>
<object class="GtkLabel" id="transponders_count_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<property name="label">0</property>
</object>
<packing>
@@ -853,7 +864,7 @@ Author: Dmitriy Yefremov
<child type="label">
<object class="GtkLabel" id="sat_update_tr_frame_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Transponders</property>
</object>
</child>
@@ -866,30 +877,30 @@ Author: Dmitriy Yefremov
<child>
<object class="GtkFrame" id="sat_update_srv_frame">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0.49000000953674316</property>
<property name="shadow_type">in</property>
<property name="can-focus">False</property>
<property name="label-xalign">0.49000000953674316</property>
<property name="shadow-type">in</property>
<child>
<object class="GtkBox" id="sat_update_srv_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="can-focus">False</property>
<property name="margin-left">5</property>
<property name="margin-right">5</property>
<property name="margin-top">5</property>
<property name="margin-bottom">5</property>
<property name="orientation">vertical</property>
<property name="spacing">5</property>
<child>
<object class="GtkScrolledWindow" id="sat_update_srv_scrolled_window">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<property name="can-focus">True</property>
<property name="shadow-type">in</property>
<child>
<object class="GtkTreeView" id="sat_update_srv_view">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can-focus">True</property>
<property name="model">update_service_store</property>
<property name="search_column">1</property>
<property name="search-column">1</property>
<child internal-child="selection">
<object class="GtkTreeSelection"/>
</child>
@@ -908,7 +919,7 @@ Author: Dmitriy Yefremov
</child>
<child>
<object class="GtkCellRendererText" id="srv_service_renderer">
<property name="xalign">0.0099999997764825821</property>
<property name="xalign">0.009999999776482582</property>
</object>
<attributes>
<attribute name="text">1</attribute>
@@ -986,15 +997,15 @@ Author: Dmitriy Yefremov
<child>
<object class="GtkBox" id="sat_update_srv_status_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">10</property>
<property name="margin_right">10</property>
<property name="can-focus">False</property>
<property name="margin-left">10</property>
<property name="margin-right">10</property>
<property name="spacing">5</property>
<child>
<object class="GtkImage" id="services_count_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">document-properties-symbolic</property>
<property name="can-focus">False</property>
<property name="icon-name">document-properties-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
@@ -1005,7 +1016,7 @@ Author: Dmitriy Yefremov
<child>
<object class="GtkLabel" id="services_count_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<property name="label">0</property>
</object>
<packing>
@@ -1029,7 +1040,7 @@ Author: Dmitriy Yefremov
<child type="label">
<object class="GtkLabel" id="sat_update_srv_frame_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Services</property>
</object>
</child>
@@ -1054,23 +1065,23 @@ Author: Dmitriy Yefremov
</child>
<child>
<object class="GtkFrame" id="log_frame">
<property name="can_focus">False</property>
<property name="margin_left">4</property>
<property name="margin_right">5</property>
<property name="margin_bottom">5</property>
<property name="label_xalign">0</property>
<property name="shadow_type">in</property>
<property name="can-focus">False</property>
<property name="margin-left">4</property>
<property name="margin-right">5</property>
<property name="margin-bottom">5</property>
<property name="label-xalign">0</property>
<property name="shadow-type">in</property>
<child>
<object class="GtkInfoBar" id="log_info_bar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="message_type">other</property>
<property name="show_close_button">True</property>
<property name="can-focus">False</property>
<property name="message-type">other</property>
<property name="show-close-button">True</property>
<child internal-child="action_area">
<object class="GtkButtonBox" id="log_info_bar_button_box">
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<property name="spacing">6</property>
<property name="layout_style">end</property>
<property name="layout-style">end</property>
</object>
<packing>
<property name="expand">False</property>
@@ -1080,20 +1091,20 @@ Author: Dmitriy Yefremov
</child>
<child internal-child="content_area">
<object class="GtkBox" id="log_info_bar_box">
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<child>
<object class="GtkScrolledWindow" id="text_view_scrolled_window">
<property name="height_request">120</property>
<property name="height-request">120</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<property name="can-focus">True</property>
<property name="shadow-type">in</property>
<child>
<object class="GtkTextView" id="text_view">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can-focus">True</property>
<property name="editable">False</property>
<property name="left_margin">5</property>
<property name="right_margin">5</property>
<property name="left-margin">5</property>
<property name="right-margin">5</property>
</object>
</child>
</object>
@@ -1121,15 +1132,15 @@ Author: Dmitriy Yefremov
</child>
<child>
<object class="GtkInfoBar" id="sat_update_info_bar">
<property name="app_paintable">True</property>
<property name="can_focus">False</property>
<property name="show_close_button">True</property>
<property name="app-paintable">True</property>
<property name="can-focus">False</property>
<property name="show-close-button">True</property>
<signal name="response" handler="on_info_bar_close" swapped="no"/>
<child internal-child="action_area">
<object class="GtkButtonBox" id="infobar-action_area2">
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<property name="spacing">6</property>
<property name="layout_style">end</property>
<property name="layout-style">end</property>
</object>
<packing>
<property name="expand">False</property>
@@ -1139,12 +1150,12 @@ Author: Dmitriy Yefremov
</child>
<child internal-child="content_area">
<object class="GtkBox" id="infobar-content_area2">
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<property name="spacing">16</property>
<child>
<object class="GtkLabel" id="info_bar_message_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Info</property>
</object>
<packing>

View File

@@ -1,5 +1,5 @@
#!/bin/bash
VER="3.4.0_Beta"
VER="3.5.0_Beta"
B_PATH="dist/DemonEditor"
DEB_PATH="$B_PATH/usr/share/demoneditor"

View File

@@ -1,5 +1,5 @@
Package: demon-editor
Version: 3.4.0-Beta
Version: 3.5.0-Beta
Section: utils
Priority: optional
Architecture: all

View File

@@ -81,7 +81,7 @@ app = BUNDLE(coll,
'CFBundleGetInfoString': "Enigma2 channel and satellite editor",
'LSApplicationCategoryType': 'public.app-category.utilities',
'LSMinimumSystemVersion': '10.13',
'CFBundleShortVersionString': f"3.4.0.{BUILD_DATE} Beta",
'CFBundleShortVersionString': f"3.5.0.{BUILD_DATE} Beta",
'NSHumanReadableCopyright': u"Copyright © 2023, Dmitriy Yefremov",
'NSRequiresAquaSystemAppearance': 'false',
'NSHighResolutionCapable': 'true'

View File

@@ -46,6 +46,7 @@ class BaseExtension(metaclass=Singleton):
""" Base extension (plugin) class. """
# The label that will be displayed in the "Tools" menu.
LABEL = "Base extension"
VERSION = "1.0"
_LOGGER_NAME = "main_logger"

View File

@@ -1440,3 +1440,30 @@ msgstr "Уключыць падтрымку пашырэнняў"
msgid "After uploading the changes you may need to completely reboot the receiver!"
msgstr "Пасля загрузкі змен можа запатрабавацца перазапуск рэсівера!"
msgid "Remove duplicates"
msgstr "Выдаліць дублікаты"
msgid "Removed"
msgstr "Выдалена"
msgid "Enables overwriting existing main list services."
msgstr "Улучае перазапіс існых сэрвісаў асноўнага спіса."
msgid "Enables skipping services import from lamedb."
msgstr "Улучае пропуск імпарту сэрвісаў з lamedb."
msgid "Bouquets data only"
msgstr "Толькі дадзеныя букетаў"
msgid "Create Category bouquets"
msgstr "Стварыць букеты па катэгорыях"
msgid "Create Regional bouquets"
msgstr "Стварыць букеты па рэгіёнах"
msgid "Skip C-band"
msgstr "Прапусціць C-дыяпазон"
msgid "Automatically set the name selected in the bouquet list."
msgstr "Аўтаматычная ўсталёўка імя, абранага ў спісе букетаў."

View File

@@ -1454,3 +1454,30 @@ msgstr "Erweiterungen Unterstützung aktivieren"
msgid "After uploading the changes you may need to completely reboot the receiver!"
msgstr "Nach dem Hochladen der Änderungen muss den Receiver eventuell komplett neu starten!"
msgid "Remove duplicates"
msgstr "Duplikate entfernen"
msgid "Removed"
msgstr "Entfernt"
msgid "Enables overwriting existing main list services."
msgstr "Ermöglicht das Überschreiben vorhandener Hauptlistendienste."
msgid "Enables skipping services import from lamedb."
msgstr "Ermöglicht das Überspringen von Dienstimporten aus lamedb."
msgid "Bouquets data only"
msgstr "Nur Bouquets-Daten"
msgid "Create Category bouquets"
msgstr "Erstellen Kategories-Bouquets"
msgid "Create Regional bouquets"
msgstr "Erstellen Regionale-Bouquets"
msgid "Skip C-band"
msgstr "C-Band überspringen"
msgid "Automatically set the name selected in the bouquet list."
msgstr "Stellen in der Bouquet-Liste ausgewählten Namen automatisch ein."

View File

@@ -6,7 +6,7 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"PO-Revision-Date: 2023-02-12 07:10+0100\n"
"PO-Revision-Date: 2023-03-06 13:22+0100\n"
"Last-Translator: Massimo Pissarello <mapi68@gmail.com>\n"
"Language-Team: Italian <>\n"
"Language: it\n"
@@ -14,7 +14,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Lokalize 22.12.2\n"
"X-Generator: Lokalize 22.12.3\n"
msgid "translator-credits"
msgstr "Massimo Pissarello"
@@ -1230,6 +1230,9 @@ msgstr "Dimensione"
msgid "Date"
msgstr "Data"
msgid "Attr."
msgstr "Attr"
msgid "Toggle display position"
msgstr "Commuta posizione visualizzazione"
@@ -1492,3 +1495,36 @@ msgstr "Ora di fine"
msgid "Enable extensions support"
msgstr "Abilita supporto estensioni"
msgid ""
"After uploading the changes you may need to completely reboot the receiver!"
msgstr ""
"Dopo aver caricato le modifiche potrebbe essere necessario riavviare"
" completamente il ricevitore!"
msgid "Remove duplicates"
msgstr "Rimuovi duplicati"
msgid "Removed"
msgstr "Rimosso"
msgid "Enables overwriting existing main list services."
msgstr "Consente di sovrascrivere i servizi esistenti dell'elenco principale."
msgid "Enables skipping services import from lamedb."
msgstr "Consente di saltare l'importazione dei servizi da lamedb."
msgid "Bouquets data only"
msgstr "Bouquet solo dati"
msgid "Create Category bouquets"
msgstr "Crea bouquet categorie"
msgid "Create Regional bouquets"
msgstr "Crea bouquet regionali"
msgid "Skip C-band"
msgstr "Salta banda C"
msgid "Automatically set the name selected in the bouquet list."
msgstr "Imposta automaticamente il nome selezionato nell'elenco dei bouquet."

View File

@@ -1437,3 +1437,30 @@ msgstr "Включить поддержку расширений"
msgid "After uploading the changes you may need to completely reboot the receiver!"
msgstr "После загрузки изменений может потребоваться перезапуск ресивера!"
msgid "Remove duplicates"
msgstr "Удалить дубликаты"
msgid "Removed"
msgstr "Удалено"
msgid "Enables overwriting existing main list services."
msgstr "Включает перезапись существующих сервисов основного списка."
msgid "Enables skipping services import from lamedb."
msgstr "Включает пропуск импорта сервисов из lamedb."
msgid "Bouquets data only"
msgstr "Только данные букетов"
msgid "Create Category bouquets"
msgstr "Создать букеты по категориям"
msgid "Create Regional bouquets"
msgstr "Создать букеты по регионам"
msgid "Skip C-band"
msgstr "Пропустить C-диапазон"
msgid "Automatically set the name selected in the bouquet list."
msgstr "Автоматическая установка имени, выбранного в списке букетов."

View File

@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: DemonEditor\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-04-16 15:59+0300\n"
"PO-Revision-Date: 2023-02-06 15:41+0300\n"
"PO-Revision-Date: 2023-02-23 14:22+0300\n"
"Last-Translator: audi06_19 <info@dreamosat-forum.com>\n"
"Language-Team: \n"
"Language: tr\n"
@@ -1465,3 +1465,15 @@ msgstr "Başlangıç saati"
msgid "End time"
msgstr "Bitiş zamanı"
msgid "Enable extensions support"
msgstr "Uzantı desteğini etkinleştir"
msgid "After uploading the changes you may need to completely reboot the receiver!"
msgstr "Değişiklikleri yükledikten sonra, alıcıyı tamamen yeniden başlatmanız gerekebilir!"
msgid "Remove duplicates"
msgstr "Kopyaları kaldır"
msgid "Removed"
msgstr "Kaldırıldı"