mirror of
https://github.com/DYefremov/DemonEditor.git
synced 2026-05-09 07:17:31 +02:00
Compare commits
63 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0db8ee6d47 | ||
|
|
ed41b01f63 | ||
|
|
c2eaecb8b8 | ||
|
|
f5313f2c40 | ||
|
|
c6a0b80fdd | ||
|
|
7813aeb059 | ||
|
|
3a0e5c09a1 | ||
|
|
ab6a44dc3f | ||
|
|
caefb4587d | ||
|
|
93ff78d7ce | ||
|
|
1d583ecd99 | ||
|
|
d4914ac451 | ||
|
|
6207b6a10d | ||
|
|
1eb8fe621d | ||
|
|
79b41b1661 | ||
|
|
7a36ba8148 | ||
|
|
08e970fc96 | ||
|
|
9681fcbc79 | ||
|
|
7b002b208f | ||
|
|
95a1732f01 | ||
|
|
57e4fdff7f | ||
|
|
89c456993f | ||
|
|
2f3fc31023 | ||
|
|
5c18e49cf7 | ||
|
|
64530bcb85 | ||
|
|
4d472609b4 | ||
|
|
640b995ab8 | ||
|
|
42980a988f | ||
|
|
64c5f28957 | ||
|
|
a32bf230cf | ||
|
|
b8cac728a8 | ||
|
|
079f07cfd2 | ||
|
|
9a5884cc9a | ||
|
|
115237a10f | ||
|
|
994bd0ee1c | ||
|
|
27e5b373a3 | ||
|
|
43c05b1739 | ||
|
|
bd96c286e9 | ||
|
|
1bded41eab | ||
|
|
5f0f51679c | ||
|
|
380bb3150b | ||
|
|
d1a7a486a2 | ||
|
|
1be167bec3 | ||
|
|
dd3e88589c | ||
|
|
c5a2df6d7d | ||
|
|
c9fc3803c7 | ||
|
|
6afd518cfc | ||
|
|
02a51c9b56 | ||
|
|
c96cfa0e1b | ||
|
|
08bc4ff4c4 | ||
|
|
ae2b78e990 | ||
|
|
88be9fe49c | ||
|
|
9dae9b7219 | ||
|
|
f296a6c90b | ||
|
|
0486776d83 | ||
|
|
3e6146d825 | ||
|
|
9b97341e70 | ||
|
|
41714136e6 | ||
|
|
f781cbb9f6 | ||
|
|
177be7679b | ||
|
|
a65914a48c | ||
|
|
e3ffc2e24b | ||
|
|
79415c69c5 |
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
*.pyc
|
||||
*.pyo
|
||||
*__pycache__
|
||||
.idea
|
||||
@@ -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.
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
import re
|
||||
|
||||
from app.commons import log
|
||||
from app.eparser.satxml import get_pos_str
|
||||
from app.ui.uicommons import CODED_ICON, LOCKED_ICON, HIDE_ICON
|
||||
from .blacklist import get_blacklist
|
||||
from ..ecommons import Service, POLARIZATION, FEC, SERVICE_TYPE, Flag, T_FEC, TrType, FEC_DEFAULT, T_SYSTEM
|
||||
@@ -220,8 +221,7 @@ class LameDbReader:
|
||||
freq = f"{int(freq) // 1000}"
|
||||
rate = f"{int(rate) // 1000}"
|
||||
if tr_type is TrType.Satellite:
|
||||
pos = int(pos)
|
||||
pos = f"{abs(pos / 10):0.1f}{'W' if pos < 0 else 'E'}"
|
||||
pos = get_pos_str(int(pos))
|
||||
except ValueError as e:
|
||||
log(f"Parse error [parse_services]: {e}")
|
||||
|
||||
|
||||
@@ -153,12 +153,13 @@ def export_to_m3u(path, bouquet, s_type, url=None):
|
||||
file.writelines(lines)
|
||||
|
||||
|
||||
def get_fav_id(url, name, settings_type, params=None, st_type=None, s_id=0, srv_type=1):
|
||||
""" Returns fav id depending on the profile. """
|
||||
def get_fav_id(url, name, settings_type, params=None, st_type=None, s_id=0, srv_type=1, force_quote=True):
|
||||
""" Returns fav id depending on the settings type. """
|
||||
if settings_type is SettingsType.ENIGMA_2:
|
||||
st_type = st_type or StreamType.NONE_TS.value
|
||||
params = params or (0, 0, 0, 0)
|
||||
return ENIGMA2_FAV_ID_FORMAT.format(st_type, s_id, srv_type, *params, quote(url), name, name, None)
|
||||
url = quote(url) if force_quote else url
|
||||
return ENIGMA2_FAV_ID_FORMAT.format(st_type, s_id, srv_type, *params, url, name, name, None)
|
||||
elif settings_type is SettingsType.NEUTRINO_MP:
|
||||
return NEUTRINO_FAV_ID_FORMAT.format(url, "", 0, None, None, None, None, "", "", 1)
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -192,5 +192,10 @@ def indent(elem, parent=None, index=-1, level=0, space=" "):
|
||||
elem.tail = f"\n{space * (level - 1)}"
|
||||
|
||||
|
||||
def get_pos_str(pos: int) -> str:
|
||||
""" Converts satellite position int value to readable string. """
|
||||
return f"{abs(pos / 10):0.1f}{'W' if pos < 0 else 'E'}"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pass
|
||||
|
||||
@@ -429,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):
|
||||
@@ -437,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):
|
||||
@@ -445,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):
|
||||
@@ -481,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 ********* #
|
||||
|
||||
@@ -903,13 +903,14 @@ class Settings:
|
||||
# **************** Get-Set settings **************** #
|
||||
|
||||
@staticmethod
|
||||
def get_settings():
|
||||
if not os.path.isfile(CONFIG_FILE) or os.stat(CONFIG_FILE).st_size == 0:
|
||||
Settings.write_settings(Settings.get_default_settings())
|
||||
def get_settings(config_file=CONFIG_FILE, default_settings=None):
|
||||
if not os.path.isfile(config_file) or os.stat(config_file).st_size == 0:
|
||||
df = Settings.get_default_settings() if default_settings is None else default_settings
|
||||
Settings.write_settings(df, config_file=config_file)
|
||||
|
||||
with open(CONFIG_FILE, "r", encoding="utf-8") as config_file:
|
||||
with open(config_file, "r", encoding="utf-8") as cf:
|
||||
try:
|
||||
return json.load(config_file)
|
||||
return json.load(cf)
|
||||
except ValueError as e:
|
||||
raise SettingsReadException(e)
|
||||
|
||||
@@ -941,10 +942,14 @@ class Settings:
|
||||
"ab": "192", "channels": "2", "samplerate": "44100", "scodec": "none"}}
|
||||
|
||||
@staticmethod
|
||||
def write_settings(config):
|
||||
os.makedirs(os.path.dirname(CONFIG_PATH), exist_ok=True)
|
||||
with open(CONFIG_FILE, "w", encoding="utf-8") as config_file:
|
||||
json.dump(config, config_file, indent=" ")
|
||||
def write_settings(config, config_path=CONFIG_PATH, config_file=CONFIG_FILE):
|
||||
os.makedirs(os.path.dirname(config_path), exist_ok=True)
|
||||
with open(config_file, "w", encoding="utf-8") as cf:
|
||||
json.dump(config, cf, indent=" ")
|
||||
|
||||
@staticmethod
|
||||
def normalize_path(path):
|
||||
return f"{os.path.normpath(path)}{SEP}"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -29,12 +29,13 @@ from functools import partial, wraps
|
||||
from warnings import warn
|
||||
|
||||
if os.name == 'nt':
|
||||
dll = ctypes.util.find_library('mpv-1.dll')
|
||||
dll = ctypes.util.find_library('libmpv-2.dll') or ctypes.util.find_library('mpv-1.dll')
|
||||
if dll is None:
|
||||
raise OSError('Cannot find mpv-1.dll in your system %PATH%. One way to deal with this is to ship mpv-1.dll '
|
||||
'with your script and put the directory your script is in into %PATH% before "import mpv": '
|
||||
'os.environ["PATH"] = os.path.dirname(__file__) + os.pathsep + os.environ["PATH"] '
|
||||
'If mpv-1.dll is located elsewhere, you can add that path to os.environ["PATH"].')
|
||||
raise OSError(
|
||||
'Cannot find [lib]mpv-*.dll in your system %PATH%. One way to deal with this is to ship [lib]mpv-*.dll '
|
||||
'with your script and put the directory your script is in into %PATH% before "import mpv": '
|
||||
'os.environ["PATH"] = os.path.dirname(__file__) + os.pathsep + os.environ["PATH"] '
|
||||
'If mpv-1.dll is located elsewhere, you can add that path to os.environ["PATH"].')
|
||||
backend = CDLL(dll)
|
||||
fs_enc = 'utf-8'
|
||||
else:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -129,8 +129,7 @@ class YouTube:
|
||||
fmts = streaming_data.get("formats", None) if streaming_data else None
|
||||
|
||||
if fmts:
|
||||
links = {Quality[i["itag"]]: i["url"] for i in filter(
|
||||
lambda i: i.get("itag", -1) in Quality, fmts) if "url" in i}
|
||||
links = {Quality[i["itag"]]: i["url"] for i in fmts if i.get("itag", -1) in Quality and "url" in i}
|
||||
|
||||
if links and title:
|
||||
return links, title.replace("+", " ")
|
||||
|
||||
@@ -27,7 +27,7 @@ Author: Dmitriy Yefremov
|
||||
|
||||
-->
|
||||
<interface domain="demon-editor">
|
||||
<requires lib="gtk+" version="3.16"/>
|
||||
<requires lib="gtk+" version="3.22"/>
|
||||
<!-- interface-license-type mit -->
|
||||
<!-- interface-name DemonEditor -->
|
||||
<!-- interface-description Enigma2 channel and satellites list editor. -->
|
||||
@@ -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.1 Beta</property>
|
||||
<property name="version">3.6.0 Beta</property>
|
||||
<property name="copyright">2018-2023 Dmitriy Yefremov
|
||||
</property>
|
||||
<property name="comments" translatable="yes">Enigma2 channel and satellite list editor.</property>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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")
|
||||
@@ -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 """
|
||||
|
||||
1083
app/ui/iptv.glade
1083
app/ui/iptv.glade
File diff suppressed because it is too large
Load Diff
119
app/ui/iptv.py
119
app/ui/iptv.py
@@ -51,6 +51,7 @@ _DIGIT_ENTRY_NAME = "digit-entry"
|
||||
_ENIGMA2_REFERENCE = "{}:{}:{:X}:{:X}:{:X}:{:X}:{:X}:0:0:0"
|
||||
_PATTERN = re.compile("(?:^[\\s]*$|\\D)")
|
||||
_UI_PATH = UI_RESOURCES_PATH + "iptv.glade"
|
||||
_URL_PREFIXES = {"YT-DLP": "YT-DLP://", "YT-DL": "YT-DL://", "STREAMLINK": "streamlink://", "No": None}
|
||||
|
||||
|
||||
def is_data_correct(elems):
|
||||
@@ -81,6 +82,7 @@ class IptvDialog:
|
||||
handlers = {"on_response": self.on_response,
|
||||
"on_entry_changed": self.on_entry_changed,
|
||||
"on_url_changed": self.on_url_changed,
|
||||
"on_url_paste": self.on_url_paste,
|
||||
"on_save": self.on_save,
|
||||
"on_stream_type_changed": self.on_stream_type_changed,
|
||||
"on_yt_quality_changed": self.on_yt_quality_changed,
|
||||
@@ -93,6 +95,7 @@ class IptvDialog:
|
||||
self._bouquet = bouquet
|
||||
self._yt_links = None
|
||||
self._yt_dl = None
|
||||
self._inserted_url = False
|
||||
|
||||
builder = get_builder(_UI_PATH, handlers, use_str=True,
|
||||
objects=("iptv_dialog", "stream_type_liststore", "yt_quality_liststore"))
|
||||
@@ -116,8 +119,10 @@ class IptvDialog:
|
||||
self._info_bar = builder.get_object("info_bar")
|
||||
self._message_label = builder.get_object("info_bar_message_label")
|
||||
self._yt_quality_box = builder.get_object("yt_iptv_quality_combobox")
|
||||
self._url_prefix_box = builder.get_object("iptv_url_prefix_box")
|
||||
self._url_prefix_combobox = builder.get_object("iptv_url_prefix_combobox")
|
||||
self._model, self._paths = view.get_selection().get_selected_rows()
|
||||
# style
|
||||
# Style.
|
||||
self._style_provider = Gtk.CssProvider()
|
||||
self._style_provider.load_from_path(UI_RESOURCES_PATH + "style.css")
|
||||
self._digit_elems = (self._srv_id_entry, self._srv_type_entry, self._sid_entry, self._tr_id_entry,
|
||||
@@ -134,6 +139,8 @@ class IptvDialog:
|
||||
else:
|
||||
self._description_entry.set_visible(False)
|
||||
builder.get_object("iptv_description_label").set_visible(False)
|
||||
[self._url_prefix_combobox.append(v, k) for k, v in _URL_PREFIXES.items()]
|
||||
self._url_prefix_combobox.set_active(0)
|
||||
|
||||
if self._action is Action.ADD:
|
||||
self._save_button.set_visible(False)
|
||||
@@ -160,6 +167,13 @@ class IptvDialog:
|
||||
self.show_info_message(get_message("Error. Verify the data!"), Gtk.MessageType.ERROR)
|
||||
return
|
||||
|
||||
url = self._url_entry.get_text()
|
||||
if all((self._url_prefix_box.get_visible(),
|
||||
self._url_prefix_combobox.get_active_id(),
|
||||
url.count("http") > 1 or urlparse(url).scheme.upper() in _URL_PREFIXES)):
|
||||
self.show_info_message(get_message("Invalid prefix for the given URL!"), Gtk.MessageType.ERROR)
|
||||
return
|
||||
|
||||
if show_dialog(DialogType.QUESTION, self._dialog) in (Gtk.ResponseType.CANCEL, Gtk.ResponseType.DELETE_EVENT):
|
||||
return
|
||||
|
||||
@@ -194,7 +208,7 @@ class IptvDialog:
|
||||
elif stream_type is StreamType.E_SERVICE_HLS:
|
||||
self._stream_type_combobox.set_active(5)
|
||||
except ValueError:
|
||||
self.show_info_message("Unknown stream type {}".format(s_type), Gtk.MessageType.ERROR)
|
||||
self.show_info_message(f"Unknown stream type {s_type}", Gtk.MessageType.ERROR)
|
||||
|
||||
self._srv_id_entry.set_text(data[1])
|
||||
self._srv_type_entry.set_text(str(int(data[2], 16)))
|
||||
@@ -202,7 +216,17 @@ class IptvDialog:
|
||||
self._tr_id_entry.set_text(str(int(data[4], 16)))
|
||||
self._net_id_entry.set_text(str(int(data[5], 16)))
|
||||
self._namespace_entry.set_text(str(int(data[6], 16)))
|
||||
self._url_entry.set_text(unquote(data[10].strip()))
|
||||
# URL.
|
||||
url = unquote(data[10].strip())
|
||||
sch = urlparse(url).scheme.upper()
|
||||
if YouTube.get_yt_id(url) and sch in _URL_PREFIXES:
|
||||
active_prefix = _URL_PREFIXES.get(sch)
|
||||
url = re.sub(active_prefix, "", url, 1, re.IGNORECASE)
|
||||
self._url_prefix_combobox.set_active_id(active_prefix)
|
||||
else:
|
||||
self._url_prefix_combobox.set_active(len(_URL_PREFIXES) - 1)
|
||||
|
||||
self._url_entry.set_text(url)
|
||||
self.update_reference_entry()
|
||||
|
||||
def init_neutrino_data(self, fav_id):
|
||||
@@ -212,7 +236,6 @@ class IptvDialog:
|
||||
|
||||
def update_reference_entry(self):
|
||||
if self._s_type is SettingsType.ENIGMA_2 and is_data_correct(self._digit_elems):
|
||||
self.on_url_changed(self._url_entry)
|
||||
self._reference_entry.set_text(_ENIGMA2_REFERENCE.format(self.get_type(),
|
||||
self._srv_id_entry.get_text(),
|
||||
int(self._srv_type_entry.get_text()),
|
||||
@@ -242,15 +265,25 @@ class IptvDialog:
|
||||
if yt_id:
|
||||
entry.set_icon_from_pixbuf(Gtk.EntryIconPosition.SECONDARY, get_yt_icon("youtube", 32))
|
||||
text = "Found a link to the YouTube resource!\nTry to get a direct link to the video?"
|
||||
if show_dialog(DialogType.QUESTION, self._dialog, text=text) == Gtk.ResponseType.OK:
|
||||
entry.set_sensitive(False)
|
||||
gen = self.set_yt_url(entry, yt_id)
|
||||
GLib.idle_add(lambda: next(gen, False), priority=GLib.PRIORITY_LOW)
|
||||
if self._inserted_url and url_str.count("http") == 1:
|
||||
if show_dialog(DialogType.QUESTION, self._dialog, text=text) == Gtk.ResponseType.OK:
|
||||
entry.set_sensitive(False)
|
||||
gen = self.set_yt_url(entry, yt_id)
|
||||
GLib.idle_add(lambda: next(gen, False), priority=GLib.PRIORITY_LOW)
|
||||
else:
|
||||
self._url_prefix_box.set_visible(self._s_type is SettingsType.ENIGMA_2)
|
||||
else:
|
||||
self._url_prefix_box.set_visible(self._s_type is SettingsType.ENIGMA_2)
|
||||
self._inserted_url = False
|
||||
elif YouTube.is_yt_video_link(url_str):
|
||||
entry.set_icon_from_pixbuf(Gtk.EntryIconPosition.SECONDARY, get_yt_icon("youtube", 32))
|
||||
else:
|
||||
entry.set_icon_from_stock(Gtk.EntryIconPosition.SECONDARY, None)
|
||||
self._yt_quality_box.set_visible(False)
|
||||
self._url_prefix_box.set_visible(False)
|
||||
|
||||
def on_url_paste(self, entry):
|
||||
self._inserted_url = True
|
||||
self._yt_quality_box.set_visible(False)
|
||||
|
||||
def set_yt_url(self, entry, video_id):
|
||||
try:
|
||||
@@ -264,7 +297,7 @@ class IptvDialog:
|
||||
links, title = self._yt_dl.get_yt_link(video_id, entry.get_text())
|
||||
yield True
|
||||
except urllib.error.URLError as e:
|
||||
self.show_info_message(get_message("Getting link error:") + (str(e)), Gtk.MessageType.ERROR)
|
||||
self.show_info_message(f"{get_message('Getting link error:')} {e}", Gtk.MessageType.ERROR)
|
||||
return
|
||||
except YouTubeException as e:
|
||||
self.show_info_message((str(e)), Gtk.MessageType.ERROR)
|
||||
@@ -279,7 +312,7 @@ class IptvDialog:
|
||||
entry.set_text(links[sorted(links, key=lambda x: int(x.rstrip("p")), reverse=True)[0]])
|
||||
self._yt_links = links
|
||||
else:
|
||||
msg = get_message("Getting link error:") + " No link received for id: {}".format(video_id)
|
||||
msg = f"{get_message('Getting link error:')} No link received for id: {video_id}"
|
||||
self.show_info_message(msg, Gtk.MessageType.ERROR)
|
||||
finally:
|
||||
entry.set_sensitive(True)
|
||||
@@ -291,13 +324,25 @@ class IptvDialog:
|
||||
self.update_reference_entry()
|
||||
|
||||
def on_yt_quality_changed(self, box):
|
||||
if not self._yt_links:
|
||||
return
|
||||
|
||||
model = box.get_model()
|
||||
active = model.get_value(box.get_active_iter(), 0)
|
||||
if self._yt_links and active in self._yt_links:
|
||||
if active in self._yt_links:
|
||||
self._url_entry.set_text(self._yt_links[active])
|
||||
else:
|
||||
self._url_entry.set_text(self._yt_links.get(max(self._yt_links, default=None), ""))
|
||||
|
||||
def save_enigma2_data(self):
|
||||
name = self._name_entry.get_text().strip()
|
||||
if self._url_prefix_box.get_visible():
|
||||
prefix = self._url_prefix_combobox.get_active_id()
|
||||
url = self._url_entry.get_text().replace(':', '%3A', 1 if prefix else -1)
|
||||
url = f"{quote(prefix) if prefix else ''}{url}"
|
||||
else:
|
||||
url = quote(self._url_entry.get_text())
|
||||
|
||||
fav_id = ENIGMA2_FAV_ID_FORMAT.format(self.get_type(),
|
||||
self._srv_id_entry.get_text(),
|
||||
int(self._srv_type_entry.get_text()),
|
||||
@@ -305,8 +350,7 @@ class IptvDialog:
|
||||
int(self._tr_id_entry.get_text()),
|
||||
int(self._net_id_entry.get_text()),
|
||||
int(self._namespace_entry.get_text()),
|
||||
quote(self._url_entry.get_text()),
|
||||
name, name)
|
||||
url, name, name)
|
||||
|
||||
self.update_bouquet_data(name, fav_id)
|
||||
|
||||
@@ -887,9 +931,14 @@ class YtListImportDialog:
|
||||
self._import_button = builder.get_object("yt_import_button")
|
||||
self._quality_box = builder.get_object("yt_quality_combobox")
|
||||
self._quality_model = builder.get_object("yt_quality_liststore")
|
||||
self._import_button.bind_property("visible", self._quality_box, "visible")
|
||||
self._import_button.bind_property("sensitive", self._quality_box, "sensitive")
|
||||
self._receive_button.bind_property("sensitive", self._import_button, "sensitive")
|
||||
self._extract_switch = builder.get_object("yt_extract_links_switch")
|
||||
|
||||
self._url_prefix_combobox = builder.get_object("yt_url_prefix_combobox")
|
||||
[self._url_prefix_combobox.append(v, k) for k, v in _URL_PREFIXES.items()]
|
||||
self._url_prefix_combobox.set_active(0)
|
||||
|
||||
builder.get_object("yt_extract_links_box").set_visible(self._s_type is SettingsType.ENIGMA_2)
|
||||
builder.get_object("yt_url_prefix_box").set_visible(self._s_type is SettingsType.ENIGMA_2)
|
||||
|
||||
if self._settings.use_header_bar:
|
||||
header_bar = HeaderBar(title="YouTube", subtitle=get_message("Playlist import"))
|
||||
@@ -905,19 +954,31 @@ class YtListImportDialog:
|
||||
window_size = self._settings.get("yt_import_dialog_size")
|
||||
if window_size:
|
||||
self._dialog.resize(*window_size)
|
||||
# Style
|
||||
# Style.
|
||||
style_provider = Gtk.CssProvider()
|
||||
style_provider.load_from_path(UI_RESOURCES_PATH + "style.css")
|
||||
style_provider.load_from_path(f"{UI_RESOURCES_PATH}style.css")
|
||||
self._url_entry.get_style_context().add_provider_for_screen(Gdk.Screen.get_default(), style_provider,
|
||||
Gtk.STYLE_PROVIDER_PRIORITY_USER)
|
||||
|
||||
def show(self):
|
||||
self._dialog.show()
|
||||
|
||||
@run_task
|
||||
def on_import(self, item):
|
||||
self.on_info_bar_close()
|
||||
self.update_active_elements(False)
|
||||
|
||||
if self._extract_switch.get_active():
|
||||
self.extract_direct_links()
|
||||
else:
|
||||
prefix = self._url_prefix_combobox.get_active_id()
|
||||
selected = filter(lambda r: r[2], self._model)
|
||||
prefix = quote(prefix) if prefix else ''
|
||||
links = [(f"{prefix}https{quote(':')}//www.youtube.com/watch?v={r[1]}", r[0]) for r in selected]
|
||||
self.append_services(links)
|
||||
self.update_active_elements(True)
|
||||
|
||||
@run_task
|
||||
def extract_direct_links(self):
|
||||
self._download_task = True
|
||||
|
||||
try:
|
||||
@@ -946,7 +1007,6 @@ class YtListImportDialog:
|
||||
self.show_info_message(str(e), Gtk.MessageType.ERROR)
|
||||
else:
|
||||
if self._download_task:
|
||||
self.show_info_message(get_message("Done!"), Gtk.MessageType.INFO)
|
||||
self.append_services([done_links[r] for r in rows])
|
||||
finally:
|
||||
self._download_task = False
|
||||
@@ -989,22 +1049,31 @@ class YtListImportDialog:
|
||||
aggr = [None] * 9
|
||||
srvs = []
|
||||
|
||||
if self._yt_list_title:
|
||||
if self._yt_list_title and self._s_type is SettingsType.ENIGMA_2:
|
||||
title = self._yt_list_title
|
||||
fav_id = MARKER_FORMAT.format(0, title, title)
|
||||
mk = Service(None, None, None, title, *aggr[0:3], BqServiceType.MARKER.name, *aggr, 0, fav_id, None)
|
||||
srvs.append(mk)
|
||||
|
||||
act = self._quality_model.get_value(self._quality_box.get_active_iter(), 0)
|
||||
extract = self._extract_switch.get_active()
|
||||
|
||||
act = self._quality_model.get_value(self._quality_box.get_active_iter(), 0) if extract else None
|
||||
for link in links:
|
||||
lnk, title = link or (None, None)
|
||||
if not lnk:
|
||||
continue
|
||||
ln = lnk.get(act) if act in lnk else lnk[sorted(lnk, key=lambda x: int(x.rstrip("p")), reverse=True)[0]]
|
||||
fav_id = get_fav_id(ln, title, self._s_type)
|
||||
|
||||
if extract:
|
||||
ln = lnk.get(act) if act in lnk else lnk[sorted(lnk, key=lambda x: int(x.rstrip("p")), reverse=True)[0]]
|
||||
else:
|
||||
ln = lnk
|
||||
|
||||
fav_id = get_fav_id(ln, title, self._s_type, force_quote=extract)
|
||||
srv = Service(None, None, IPTV_ICON, title, *aggr[0:3], BqServiceType.IPTV.name, *aggr, None, fav_id, None)
|
||||
srvs.append(srv)
|
||||
|
||||
self.appender(srvs)
|
||||
self.show_info_message(get_message("Done!"), Gtk.MessageType.INFO)
|
||||
|
||||
@run_idle
|
||||
def update_active_elements(self, sensitive):
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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.1 Beta</property>
|
||||
<property name="label">3.6.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>
|
||||
|
||||
@@ -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,
|
||||
@@ -1362,6 +1364,10 @@ class Application(Gtk.Application):
|
||||
|
||||
selection = view.get_selection()
|
||||
model, paths = selection.get_selected_rows()
|
||||
if not paths:
|
||||
self.show_error_message("No selected item!")
|
||||
return
|
||||
|
||||
model_name = get_base_model(model).get_name()
|
||||
itrs = [model.get_iter(path) for path in paths]
|
||||
rows = [model[in_itr][:] for in_itr in itrs]
|
||||
@@ -2412,7 +2418,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()))
|
||||
@@ -2420,7 +2429,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)
|
||||
@@ -2899,6 +2908,11 @@ class Application(Gtk.Application):
|
||||
self.update_bouquet_list()
|
||||
|
||||
def on_view_focus(self, view, focus_event=None):
|
||||
# Preventing focus lack for some cases.
|
||||
if not focus_event and not view.is_focus():
|
||||
view.grab_focus()
|
||||
return True
|
||||
|
||||
model_name, model = get_model_data(view)
|
||||
not_empty = len(model) > 0 if model else False
|
||||
is_service = model_name == self.SERVICE_MODEL
|
||||
@@ -3243,26 +3257,26 @@ class Application(Gtk.Application):
|
||||
if self._s_type is not SettingsType.ENIGMA_2:
|
||||
self.show_error_message("Not allowed in this context!")
|
||||
return
|
||||
ServicesUpdateDialog(self._main_window, self._settings, self.on_import_data_from_web).show()
|
||||
ServicesUpdateDialog(self).show()
|
||||
|
||||
@run_idle
|
||||
def on_import_data_from_web(self, services):
|
||||
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 ******************** #
|
||||
@@ -3885,7 +3899,7 @@ class Application(Gtk.Application):
|
||||
return self.show_error_message("Data loading in progress!")
|
||||
|
||||
model, paths = view.get_selection().get_selected_rows()
|
||||
if is_only_one_item_selected(paths, self._main_window):
|
||||
if is_only_one_item_selected(paths, self):
|
||||
model_name = get_base_model(model).get_name()
|
||||
if model_name == self.FAV_MODEL:
|
||||
srv_type = model.get_value(model.get_iter(paths), Column.FAV_TYPE)
|
||||
@@ -3910,7 +3924,7 @@ class Application(Gtk.Application):
|
||||
|
||||
def on_bouquets_edit(self, view):
|
||||
""" Renaming bouquets. """
|
||||
if not self._bq_selected:
|
||||
if not self._bq_selected and self._s_type is SettingsType.NEUTRINO_MP:
|
||||
self.show_error_message("This item is not allowed to edit!")
|
||||
return
|
||||
|
||||
@@ -3918,7 +3932,7 @@ class Application(Gtk.Application):
|
||||
|
||||
if paths:
|
||||
itr = model.get_iter(paths[0])
|
||||
bq_name, bq_type = model.get(itr, 0, 3)
|
||||
bq_name, bq_type = model.get(itr, Column.BQ_NAME, Column.BQ_TYPE)
|
||||
response = show_dialog(DialogType.INPUT, self._main_window, bq_name)
|
||||
if response == Gtk.ResponseType.CANCEL:
|
||||
return
|
||||
@@ -3928,14 +3942,17 @@ class Application(Gtk.Application):
|
||||
self.show_error_message(get_message("A bouquet with that name exists!"))
|
||||
return
|
||||
|
||||
model.set_value(itr, 0, response)
|
||||
model.set_value(itr, Column.BQ_NAME, response)
|
||||
if not model.iter_parent(itr):
|
||||
return
|
||||
|
||||
old_bq_name = f"{bq_name}:{bq_type}"
|
||||
self._bouquets[bq] = self._bouquets.pop(old_bq_name)
|
||||
self._bq_file[bq] = self._bq_file.pop(old_bq_name, None)
|
||||
self._current_bq_name = response
|
||||
self._bq_name_label.set_text(self._current_bq_name)
|
||||
self._bq_selected = bq
|
||||
# services with extra names for the bouquet
|
||||
# Services with extra names for the bouquet.
|
||||
ext_bq = self._extra_bouquets.get(old_bq_name, None)
|
||||
if ext_bq:
|
||||
self._extra_bouquets[bq] = ext_bq
|
||||
@@ -4022,6 +4039,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!")
|
||||
@@ -4201,8 +4238,7 @@ class Application(Gtk.Application):
|
||||
self.show_error_message("No bouquets config is loaded. Load or create a new config!")
|
||||
return
|
||||
|
||||
gen_bouquets(self._services_view, self._bouquets_view, self._main_window, g_type, self._s_type,
|
||||
self.append_bouquet)
|
||||
gen_bouquets(self, g_type)
|
||||
|
||||
# ***************** Alternatives ********************* #
|
||||
|
||||
|
||||
@@ -33,14 +33,14 @@ __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
|
||||
import shutil
|
||||
import unicodedata
|
||||
from collections import defaultdict
|
||||
from functools import lru_cache
|
||||
from itertools import groupby
|
||||
from pathlib import Path
|
||||
from urllib.parse import unquote
|
||||
|
||||
@@ -546,13 +546,13 @@ def remove_picons(settings, picon_ids, picons):
|
||||
shutil.move(src, backup_path + p_id)
|
||||
|
||||
|
||||
def is_only_one_item_selected(paths, transient):
|
||||
def is_only_one_item_selected(paths, app):
|
||||
if len(paths) > 1:
|
||||
show_dialog(DialogType.ERROR, transient, "Please, select only one item!")
|
||||
app.show_error_message("Please, select only one item!")
|
||||
return False
|
||||
|
||||
if not paths:
|
||||
show_dialog(DialogType.ERROR, transient, "No selected item!")
|
||||
app.show_error_message("No selected item!")
|
||||
return False
|
||||
|
||||
return True
|
||||
@@ -574,44 +574,89 @@ def get_picon_file_name(service_name):
|
||||
|
||||
# ***************** Bouquets ********************* #
|
||||
|
||||
def gen_bouquets(view, bq_view, transient, gen_type, s_type, callback):
|
||||
def gen_bouquets(app, gen_type):
|
||||
""" Auto-generate and append list of bouquets. """
|
||||
model, paths = view.get_selection().get_selected_rows()
|
||||
single_types = (BqGenType.SAT, BqGenType.PACKAGE, BqGenType.TYPE)
|
||||
if gen_type in single_types:
|
||||
if not is_only_one_item_selected(paths, transient):
|
||||
return
|
||||
model, paths = app.services_view.get_selection().get_selected_rows()
|
||||
single_types = {BqGenType.SAT, BqGenType.PACKAGE, BqGenType.TYPE}
|
||||
if gen_type in single_types and not is_only_one_item_selected(paths, app):
|
||||
return
|
||||
|
||||
fav_id_index = Column.SRV_FAV_ID
|
||||
index = Column.SRV_TYPE
|
||||
if gen_type in (BqGenType.PACKAGE, BqGenType.EACH_PACKAGE):
|
||||
index = Column.SRV_PACKAGE
|
||||
elif gen_type in (BqGenType.SAT, BqGenType.EACH_SAT):
|
||||
index = Column.SRV_POS
|
||||
|
||||
# Splitting services [caching] by column value.
|
||||
s_data = defaultdict(list)
|
||||
for row in model:
|
||||
s_data[row[index]].append(BouquetService(None, BqServiceType.DEFAULT, row[fav_id_index], 0))
|
||||
ids = {row[Column.SRV_FAV_ID] for row in model}
|
||||
services = [v for k, v in app.current_services.items() if k in ids]
|
||||
|
||||
bq_type = BqType.BOUQUET.value if s_type is SettingsType.NEUTRINO_MP else BqType.TV.value
|
||||
bq_index = 0 if s_type is SettingsType.ENIGMA_2 else 1
|
||||
bq_root_iter = bq_view.get_model().get_iter(bq_index)
|
||||
srv = Service(*model[paths][:Column.SRV_TOOLTIP])
|
||||
cond = srv.package if gen_type is BqGenType.PACKAGE else srv.pos if gen_type is BqGenType.SAT else srv.service_type
|
||||
bq_view.expand_row(Gtk.TreePath(bq_index), 0)
|
||||
|
||||
if gen_type is BqGenType.TYPE and cond == "Data":
|
||||
msg = f"{get_message('Selected type:')} '{cond}'\n\n{get_message('Are you sure?')}"
|
||||
if show_dialog(DialogType.QUESTION, app.app_window, msg) != Gtk.ResponseType.OK:
|
||||
return
|
||||
|
||||
def grouper(s):
|
||||
data = s[index]
|
||||
return data if data else "None"
|
||||
|
||||
services = {k: list(v) for k, v in groupby(sorted(services, key=grouper), key=grouper)}
|
||||
|
||||
bq_view = app.bouquets_view
|
||||
bq_type = BqType.TV.value if app.is_enigma else BqType.BOUQUET.value
|
||||
bq_index = 0 if app.is_enigma else 1
|
||||
bq_root_iter = bq_view.get_model().get_iter(bq_index)
|
||||
|
||||
bq_names = get_bouquets_names(bq_view.get_model())
|
||||
|
||||
if gen_type in single_types:
|
||||
if cond in bq_names:
|
||||
show_dialog(DialogType.ERROR, transient, "A bouquet with that name exists!")
|
||||
else:
|
||||
callback(Bouquet(cond, bq_type, s_data.get(cond)), bq_root_iter)
|
||||
app.show_error_message("A bouquet with that name exists!")
|
||||
return
|
||||
|
||||
bq_services = get_services_type_groups(services.get(cond, []))
|
||||
if app.is_enigma:
|
||||
if srv.service_type == "Radio":
|
||||
bq_index = 1
|
||||
bq_type = BqType.RADIO.value
|
||||
bq_root_iter = bq_view.get_model().get_iter(bq_index)
|
||||
bq_view.expand_row(Gtk.TreePath(bq_index), 1)
|
||||
bq_services = bq_services.get("Radio", [])
|
||||
else:
|
||||
bq_view.expand_row(Gtk.TreePath(bq_index), 0)
|
||||
bq_services = bq_services.get("Data" if srv.service_type == "Data" else "TV", [])
|
||||
app.append_bouquet(Bouquet(cond, bq_type, get_bouquet_services(bq_services)), bq_root_iter)
|
||||
else:
|
||||
bq_view.expand_row(Gtk.TreePath(bq_index), 0)
|
||||
# We add a bouquet only if the given name is missing [keys - names]!
|
||||
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(services.keys() - bq_names, key=get_pos_num, reverse=True)
|
||||
else:
|
||||
bq_names = sorted(services.keys() - bq_names)
|
||||
|
||||
tv_bqs = []
|
||||
radio_bqs = []
|
||||
for n in bq_names:
|
||||
bqs = services.get(n, [])
|
||||
# TV and Radio separation.
|
||||
bq_grp = get_services_type_groups(bqs)
|
||||
tv_bq = bq_grp.get("TV", [])
|
||||
tv_bqs.append(Bouquet(n, BqType.TV.value, get_bouquet_services(tv_bq))) if tv_bq else None
|
||||
radio_bq = bq_grp.get("Radio", [])
|
||||
radio_bqs.append(Bouquet(n, BqType.RADIO.value, get_bouquet_services(radio_bq))) if radio_bq else None
|
||||
|
||||
[app.append_bouquet(b, bq_root_iter) for b in tv_bqs]
|
||||
if app.is_enigma:
|
||||
bq_root_iter = bq_view.get_model().get_iter(bq_index + 1)
|
||||
bq_view.expand_row(Gtk.TreePath(bq_index + 1), 0)
|
||||
[app.append_bouquet(b, bq_root_iter) for b in radio_bqs]
|
||||
|
||||
|
||||
def get_bouquet_services(services):
|
||||
services.sort(key=lambda s: s.service)
|
||||
return [BouquetService(None, BqServiceType.DEFAULT, s.fav_id, 0) for s in services]
|
||||
|
||||
|
||||
def get_bouquets_names(model):
|
||||
@@ -627,12 +672,28 @@ def get_bouquets_names(model):
|
||||
return bouquets_names
|
||||
|
||||
|
||||
def get_services_type_groups(services):
|
||||
""" Returns services grouped by main types [TV, Radio, Data]. -> dict """
|
||||
|
||||
def type_grouper(s):
|
||||
s_type = s.service_type
|
||||
|
||||
if s_type == "Data":
|
||||
return s_type
|
||||
elif s_type == "Radio":
|
||||
return s_type
|
||||
else:
|
||||
return "TV"
|
||||
|
||||
return {k: list(v) for k, v in groupby(sorted(services, key=type_grouper), key=type_grouper)}
|
||||
|
||||
|
||||
# ***************** Others ********************* #
|
||||
|
||||
def copy_reference(view, app):
|
||||
""" Copying picon id to clipboard. """
|
||||
model, paths = view.get_selection().get_selected_rows()
|
||||
if not is_only_one_item_selected(paths, app.app_window):
|
||||
if not is_only_one_item_selected(paths, app):
|
||||
return
|
||||
|
||||
target = app.get_target_view(view)
|
||||
@@ -711,12 +772,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 +820,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())
|
||||
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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,11 +40,13 @@ 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 USE_HEADER_BAR
|
||||
HIERARCHY, Inversion, C_MODULATION, FEC_DEFAULT, TerTransponder, CableTransponder,
|
||||
Bouquet, BouquetService, BqServiceType, Bouquets, BqType)
|
||||
from app.eparser.satxml import get_pos_str
|
||||
from app.settings import USE_HEADER_BAR, Settings, CONFIG_PATH
|
||||
from app.tools.satellites import SatellitesParser, SatelliteSource, ServicesParser
|
||||
from ..dialogs import show_dialog, DialogType, get_message, get_builder
|
||||
from ..main_helper import append_text_to_tview, get_base_model, on_popup_menu
|
||||
from ..main_helper import append_text_to_tview, get_base_model, on_popup_menu, get_services_type_groups
|
||||
from ..search import SearchProvider
|
||||
from ..uicommons import Gtk, Gdk, UI_RESOURCES_PATH, HeaderBar
|
||||
|
||||
@@ -408,14 +412,13 @@ class UpdateDialog:
|
||||
self._settings = settings
|
||||
self._download_task = False
|
||||
self._parser = None
|
||||
self._size_name = f"{'_'.join(re.findall('[A-Z][^A-Z]*', self.__class__.__name__))}_window_size".lower()
|
||||
self._selected_satellites = set()
|
||||
|
||||
builder = get_builder(f"{UI_RESOURCES_PATH}xml{os.sep}update.glade", handlers)
|
||||
|
||||
self._window = builder.get_object("satellites_update_window")
|
||||
self._window.set_transient_for(transient)
|
||||
if title:
|
||||
self._window.set_title(title)
|
||||
self._window.set_title(title if title else "")
|
||||
|
||||
self._transponder_paned = builder.get_object("sat_update_tr_paned")
|
||||
self._sat_view = builder.get_object("sat_update_tree_view")
|
||||
@@ -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,6 +461,12 @@ 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)
|
||||
# Options.
|
||||
self._general_options_box = builder.get_object("general_options_box")
|
||||
self._save_sat_selection_switch = builder.get_object("save_sat_selection_switch")
|
||||
self._skip_c_band_switch = builder.get_object("skip_c_band_switch")
|
||||
|
||||
if self._settings.use_header_bar:
|
||||
header_bar = HeaderBar()
|
||||
@@ -463,15 +474,23 @@ class UpdateDialog:
|
||||
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)
|
||||
# Dialog settings.
|
||||
self._dialog_name = f"{'_'.join(re.findall('[A-Z][^A-Z]*', self.__class__.__name__))}".lower()
|
||||
self._dialog_settings = self._settings.get(self._dialog_name, {})
|
||||
self._source_box.set_active(self._dialog_settings.get("source", 1))
|
||||
self._save_sat_selection_switch.set_active(self._dialog_settings.get("save_sat_selection", False))
|
||||
self._skip_c_band_switch.set_active(self._dialog_settings.get("skip_c_band", False))
|
||||
|
||||
if self._save_sat_selection_switch.get_active():
|
||||
self._selected_satellites.update(self.get_selected_satellites())
|
||||
|
||||
window_size = self._dialog_settings.get("window_size", None)
|
||||
if window_size:
|
||||
self._window.resize(*window_size)
|
||||
|
||||
@@ -497,11 +516,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()
|
||||
@@ -526,11 +545,14 @@ class UpdateDialog:
|
||||
@run_idle
|
||||
def append_satellites(self, sats):
|
||||
model = get_base_model(self._sat_view.get_model())
|
||||
|
||||
for sat in sats:
|
||||
model.append(sat)
|
||||
itr = model.append(sat)
|
||||
model[itr][-1] = sat[-2] in self._selected_satellites
|
||||
|
||||
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):
|
||||
@@ -625,10 +647,33 @@ class UpdateDialog:
|
||||
itr = self._filter_model.convert_iter_to_child_iter(model.convert_iter_to_child_iter(model.get_iter(path)))
|
||||
self._filter_model.get_model().set_value(itr, 4, select)
|
||||
|
||||
if self._save_sat_selection_switch.get_active():
|
||||
sat = model[path][-2]
|
||||
self._selected_satellites.add(sat) if select else self._selected_satellites.discard(sat)
|
||||
|
||||
def on_quit(self, window, event):
|
||||
self._settings.add(self._size_name, window.get_size())
|
||||
self.save_settings()
|
||||
self.is_download = False
|
||||
|
||||
def save_settings(self):
|
||||
self._dialog_settings["window_size"] = self._window.get_size()
|
||||
self._dialog_settings["source"] = self._source_box.get_active()
|
||||
self._dialog_settings["save_sat_selection"] = self._save_sat_selection_switch.get_active()
|
||||
self._dialog_settings["skip_c_band"] = self._skip_c_band_switch.get_active()
|
||||
self._settings.add(self._dialog_name, self._dialog_settings)
|
||||
self.save_selected_satellites()
|
||||
|
||||
def get_selected_satellites(self):
|
||||
""" Returns selected satellites set from the last session. """
|
||||
c_file = f"{CONFIG_PATH}{self._dialog_name}_satellites"
|
||||
return Settings.get_settings(c_file, default_settings=[])
|
||||
|
||||
def save_selected_satellites(self):
|
||||
""" Saves current selected satellites to a file. """
|
||||
if self._save_sat_selection_switch.get_active():
|
||||
c_file = f"{CONFIG_PATH}{self._dialog_name}_satellites"
|
||||
Settings.write_settings(list(self._selected_satellites), config_file=c_file)
|
||||
|
||||
|
||||
class SatellitesUpdateDialog(UpdateDialog):
|
||||
""" Dialog for update satellites from the Web. """
|
||||
@@ -638,6 +683,16 @@ class SatellitesUpdateDialog(UpdateDialog):
|
||||
|
||||
self._main_model = main_model
|
||||
self._source_box.connect("changed", self.on_update_satellites_list)
|
||||
# Options.
|
||||
self._merge_sat_switch = Gtk.Switch(active=self._dialog_settings.get("merge_satellites", False))
|
||||
self._merge_sat_switch.connect("state-set", lambda b, s: self._dialog_settings.update({"merge_satellites": s}))
|
||||
box = Gtk.Box(spacing=5, orientation=Gtk.Orientation.HORIZONTAL)
|
||||
box.pack_start(Gtk.Label(get_message("Merge satellites by positions")), False, True, 0)
|
||||
box.pack_end(self._merge_sat_switch, False, True, 0)
|
||||
self._general_options_box.pack_start(box, True, True, 0)
|
||||
self._general_options_box.show_all()
|
||||
|
||||
self._skip_c_band_switch.get_parent().set_visible(False)
|
||||
|
||||
@run_idle
|
||||
def on_receive_data(self, item):
|
||||
@@ -653,6 +708,7 @@ class SatellitesUpdateDialog(UpdateDialog):
|
||||
self.update_log_visibility()
|
||||
model = self._sat_view.get_model()
|
||||
start = time.time()
|
||||
_len = 75
|
||||
|
||||
with concurrent.futures.ProcessPoolExecutor(max_workers=4) as executor:
|
||||
text = "Processing: {}\n"
|
||||
@@ -672,10 +728,39 @@ class SatellitesUpdateDialog(UpdateDialog):
|
||||
appender.send(text.format(data[0]))
|
||||
sats.append(data)
|
||||
|
||||
appender.send("-" * 75 + "\n")
|
||||
appender.send("-" * _len + "\n")
|
||||
sat_count = len(sats)
|
||||
|
||||
sats = {s[0]: s for s in sats} # key = name, v = satellite
|
||||
if self._merge_sat_switch.get_active():
|
||||
def grouper(sat):
|
||||
try:
|
||||
return int(sat.position)
|
||||
except ValueError:
|
||||
pass
|
||||
return 0
|
||||
|
||||
sat_groups = groupby(sorted(sats, key=grouper, reverse=True), key=grouper)
|
||||
sats = {}
|
||||
for pos, satellites in sat_groups:
|
||||
satellites = list(satellites)
|
||||
if len(satellites) > 1:
|
||||
position = get_pos_str(pos)
|
||||
appender.send(f"Merging satellites for position: {position}\n")
|
||||
names = []
|
||||
transponders = []
|
||||
for s in satellites:
|
||||
names.append(s.name.lstrip(position).strip().split())
|
||||
transponders.extend(s.transponders)
|
||||
|
||||
transponders.sort(key=lambda t: int(t.frequency))
|
||||
sat = Satellite(self.get_grouped_satellite_name(names, position), "0", str(pos), transponders)
|
||||
sats[sat.name] = sat
|
||||
else:
|
||||
sat = satellites.pop()
|
||||
sats[sat.name] = sat
|
||||
appender.send("-" * _len + "\n")
|
||||
else:
|
||||
sats = {s.name: s for s in sats} # key = name, v = satellite
|
||||
|
||||
for row in self._main_model:
|
||||
pos = row[0]
|
||||
@@ -688,11 +773,39 @@ class SatellitesUpdateDialog(UpdateDialog):
|
||||
appender.send(f"Adding satellite: {s.name}\n")
|
||||
self.append_satellite(s)
|
||||
|
||||
appender.send("-" * 75 + "\n")
|
||||
appender.send("-" * _len + "\n")
|
||||
appender.send(f"Consumed: {time.time() - start:0.0f}s, {sat_count} satellites received.\n")
|
||||
appender.close()
|
||||
self.is_download = False
|
||||
|
||||
def get_grouped_satellite_name(self, sat_names, pos):
|
||||
""" Forms name for merged satellites. """
|
||||
|
||||
def name_grouper(nd):
|
||||
if nd:
|
||||
return nd[0]
|
||||
return ""
|
||||
|
||||
name_groups = groupby(sorted(sat_names, key=name_grouper), key=name_grouper)
|
||||
names = []
|
||||
for s, s_names in name_groups:
|
||||
tk = set()
|
||||
name = s
|
||||
for i, n_data in enumerate(s_names):
|
||||
if i == 0:
|
||||
name = " ".join(n_data)
|
||||
tk.update(n_data)
|
||||
else:
|
||||
for n in n_data:
|
||||
if n in tk:
|
||||
continue
|
||||
name = f"{name}/{n}"
|
||||
tk.add(n)
|
||||
|
||||
names.append(name)
|
||||
|
||||
return f"{pos} {' & '.join(names)}"
|
||||
|
||||
@run_idle
|
||||
def append_satellite(self, sat):
|
||||
self._main_model.append(sat)
|
||||
@@ -701,16 +814,16 @@ class SatellitesUpdateDialog(UpdateDialog):
|
||||
class ServicesUpdateDialog(UpdateDialog):
|
||||
""" Dialog for updating services from the Web. """
|
||||
|
||||
def __init__(self, transient, settings, callback):
|
||||
super().__init__(transient=transient, settings=settings, title="Services update")
|
||||
def __init__(self, app):
|
||||
super().__init__(transient=app.app_window, settings=app.app_settings, title="Services update")
|
||||
|
||||
self._callback = callback
|
||||
self._callback = app.on_import_data_from_web
|
||||
self._satellite_paths = {}
|
||||
self._transponders = {}
|
||||
self._services = {}
|
||||
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 +841,23 @@ 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.
|
||||
self._kos_bq_groups_switch = Gtk.Switch(active=self._dialog_settings.get("kos_bq_groups", False))
|
||||
self._kos_bq_groups_switch.connect("state-set", lambda b, s: self._dialog_settings.update({"kos_bq_groups": s}))
|
||||
self._kos_bq_lang_switch = Gtk.Switch(active=self._dialog_settings.get("kos_bq_lang", False))
|
||||
self._kos_bq_lang_switch.connect("state-set", lambda b, s: self._dialog_settings.update({"kos_bq_lang": s}))
|
||||
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)
|
||||
self._general_options_box.pack_start(self._kos_options_box, True, True, 0)
|
||||
self._general_options_box.show_all()
|
||||
|
||||
@run_idle
|
||||
def on_receive_data(self, item):
|
||||
@@ -737,6 +867,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 +943,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 +954,47 @@ 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([srv._replace(fav_id=srvs[i].fav_id) for i, srv in enumerate(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, services):
|
||||
type_groups = get_services_type_groups(services)
|
||||
tv_bouquets, radio_bouquets = [], []
|
||||
|
||||
tv_services = sorted(type_groups.get("TV", []), key=lambda s: s.service)
|
||||
rd_services = sorted(type_groups.get("Radio", []), key=lambda s: s.service)
|
||||
no_lb = "No Category"
|
||||
|
||||
if self._kos_bq_groups_switch.get_active():
|
||||
self.gen_bouquet_group(tv_services, tv_bouquets, lambda s: s[4] or no_lb)
|
||||
self.gen_bouquet_group(rd_services, radio_bouquets, lambda s: s[4] or no_lb, bq_type=BqType.RADIO.value)
|
||||
|
||||
if self._kos_bq_lang_switch.get_active():
|
||||
lb = "" if no_lb in {b.name for b in tv_bouquets} else "No Region"
|
||||
self.gen_bouquet_group(tv_services, tv_bouquets, lambda s: s[5] or lb)
|
||||
lb = "" if no_lb in {b.name for b in radio_bouquets} else "No Region"
|
||||
self.gen_bouquet_group(rd_services, radio_bouquets, lambda s: s[5] or lb, bq_type=BqType.RADIO.value)
|
||||
|
||||
return Bouquets("", BqType.TV.value, tv_bouquets), Bouquets("", BqType.RADIO.value, radio_bouquets)
|
||||
|
||||
def gen_bouquet_group(self, services, bouquets, grouper, bq_type=BqType.TV.value):
|
||||
""" Generates bouquets depending on <grouper>. """
|
||||
s_type = BqServiceType.DEFAULT
|
||||
[bouquets.append(Bouquet(name=g[0], type=bq_type,
|
||||
services=[BouquetService(None, s_type, s.fav_id, 0) for s in g[1]])) for g in
|
||||
groupby(sorted(services, key=grouper), key=grouper) if g[0]]
|
||||
|
||||
@run_task
|
||||
def get_sat_list(self, src, callback):
|
||||
sat_src = SatelliteSource.LYNGSAT
|
||||
@@ -831,10 +1007,9 @@ class ServicesUpdateDialog(UpdateDialog):
|
||||
self.is_download = False
|
||||
|
||||
def on_satellite_toggled(self, toggle, path):
|
||||
model = self._sat_view.get_model()
|
||||
self.update_state(model, path, not toggle.get_active())
|
||||
self.update_receive_button_state(self._filter_model)
|
||||
super().on_satellite_toggled(toggle, path)
|
||||
|
||||
model = self._sat_view.get_model()
|
||||
url = model.get_value(model.get_iter(path), 3)
|
||||
selected = toggle.get_active()
|
||||
transponders = self._transponders.get(url, None)
|
||||
|
||||
@@ -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
|
||||
@@ -37,9 +37,9 @@ from app.eparser import get_satellites, write_satellites, Satellite, Transponder
|
||||
from app.eparser.ecommons import (POLARIZATION, FEC, SYSTEM, MODULATION, T_SYSTEM, BANDWIDTH, CONSTELLATION, T_FEC,
|
||||
GUARD_INTERVAL, TRANSMISSION_MODE, HIERARCHY, Inversion, FEC_DEFAULT, C_MODULATION,
|
||||
Terrestrial, Cable, CableTransponder, TerTransponder)
|
||||
from app.eparser.satxml import get_terrestrial, get_cable, write_terrestrial, write_cable
|
||||
from .dialogs import SatelliteDialog, SatellitesUpdateDialog, TerrestrialDialog, CableDialog, SatTransponderDialog, \
|
||||
CableTransponderDialog, TerTransponderDialog
|
||||
from app.eparser.satxml import get_terrestrial, get_cable, write_terrestrial, write_cable, get_pos_str
|
||||
from .dialogs import (SatelliteDialog, SatellitesUpdateDialog, TerrestrialDialog, CableDialog, SatTransponderDialog,
|
||||
CableTransponderDialog, TerTransponderDialog)
|
||||
from ..dialogs import show_dialog, DialogType, get_chooser_dialog, get_message, get_builder
|
||||
from ..main_helper import move_items, on_popup_menu, scroll_to
|
||||
from ..uicommons import Gtk, Gdk, UI_RESOURCES_PATH, MOVE_KEYS, KeyboardKey, MOD_MASK, Page
|
||||
@@ -56,8 +56,8 @@ class SatellitesTool(Gtk.Box):
|
||||
def __str__(self):
|
||||
return self.value
|
||||
|
||||
def __init__(self, app, settings, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
def __init__(self, app, settings, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
self._app = app
|
||||
self._app.connect("data-save", self.on_save)
|
||||
@@ -162,8 +162,7 @@ class SatellitesTool(Gtk.Box):
|
||||
|
||||
def sat_pos_func(self, column, renderer, model, itr, data):
|
||||
""" Converts and sets the satellite position value to a readable format. """
|
||||
pos = int(model.get_value(itr, 2))
|
||||
renderer.set_property("text", f"{abs(pos / 10):0.1f}{'W' if pos < 0 else 'E'}")
|
||||
renderer.set_property("text", get_pos_str(int(model.get_value(itr, 2))))
|
||||
|
||||
def sat_pol_func(self, column, renderer, model, itr, data):
|
||||
renderer.set_property("text", POLARIZATION.get(model.get_value(itr, 2), None))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -65,19 +65,19 @@ Author: Dmitriy Yefremov
|
||||
</object>
|
||||
<object class="GtkImage" id="popup_menu_add_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="stock">gtk-add</property>
|
||||
</object>
|
||||
<object class="GtkMenu" id="popup_menu">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="can-focus">False</property>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="add_sat_popup_menu_item">
|
||||
<property name="label" translatable="yes">Add</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="image">popup_menu_add_image</property>
|
||||
<property name="use_stock">False</property>
|
||||
<property name="use-stock">False</property>
|
||||
<signal name="activate" handler="on_add" swapped="no"/>
|
||||
<accelerator key="Insert" signal="activate"/>
|
||||
</object>
|
||||
@@ -85,16 +85,16 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkSeparatorMenuItem" id="popup_sat_menu_separator">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="can-focus">False</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="edit_sat_popup_menu_item">
|
||||
<property name="label">gtk-edit</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_edit" swapped="no"/>
|
||||
<accelerator key="e" signal="activate" modifiers="Primary"/>
|
||||
</object>
|
||||
@@ -102,16 +102,16 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkSeparatorMenuItem" id="popup_sat_menu_separator_2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="can-focus">False</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="remove_sat_popup_menu_item">
|
||||
<property name="label">gtk-remove</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_remove" swapped="no"/>
|
||||
<accelerator key="Delete" signal="activate"/>
|
||||
</object>
|
||||
@@ -119,19 +119,19 @@ Author: Dmitriy Yefremov
|
||||
</object>
|
||||
<object class="GtkImage" id="popup_menu_add_image_2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="stock">gtk-add</property>
|
||||
</object>
|
||||
<object class="GtkMenu" id="transponder_popup_menu">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="can-focus">False</property>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="add_tr_popup_menu_item">
|
||||
<property name="label" translatable="yes">Add</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="image">popup_menu_add_image_2</property>
|
||||
<property name="use_stock">False</property>
|
||||
<property name="use-stock">False</property>
|
||||
<signal name="activate" handler="on_transponder_add" swapped="no"/>
|
||||
<accelerator key="Insert" signal="activate"/>
|
||||
</object>
|
||||
@@ -139,16 +139,16 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkSeparatorMenuItem" id="popup_tr_menu_separator">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="can-focus">False</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="edit_tr_popup_menu_item">
|
||||
<property name="label">gtk-edit</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_transponder_edit" swapped="no"/>
|
||||
<accelerator key="e" signal="activate" modifiers="Primary"/>
|
||||
</object>
|
||||
@@ -156,16 +156,16 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkSeparatorMenuItem" id="popup_tr_menu_separator_2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="can-focus">False</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="remove_tr_popup_menu_item">
|
||||
<property name="label">gtk-remove</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_transponder_remove" swapped="no"/>
|
||||
<accelerator key="Delete" signal="activate"/>
|
||||
</object>
|
||||
@@ -255,45 +255,58 @@ Author: Dmitriy Yefremov
|
||||
</object>
|
||||
<object class="GtkPaned" id="main_paned">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="wide_handle">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="wide-handle">True</property>
|
||||
<child>
|
||||
<object class="GtkFrame" id="editor_sat_frame">
|
||||
<property name="width_request">360</property>
|
||||
<property name="width-request">360</property>
|
||||
<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="editor_sat_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="can-focus">False</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">5</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="editor_header_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">2</property>
|
||||
<property name="margin_bottom">5</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">2</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<property name="spacing">5</property>
|
||||
<child type="center">
|
||||
<object class="GtkStackSwitcher" id="stack_switcher">
|
||||
<property name="name">header-stack-switcher</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="stack">sat_stack</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="add_header_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Add</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="tooltip-text" translatable="yes">Add</property>
|
||||
<signal name="clicked" handler="on_add" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="add_satellite_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">document-new-symbolic</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="icon-name">document-new-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
@@ -306,15 +319,15 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkButton" id="update_header_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Update</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="tooltip-text" translatable="yes">Update</property>
|
||||
<signal name="clicked" handler="on_update" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="update_header_button_img">
|
||||
<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>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
@@ -324,19 +337,6 @@ Author: Dmitriy Yefremov
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child type="center">
|
||||
<object class="GtkStackSwitcher" id="stack_switcher">
|
||||
<property name="visible">True</property>
|
||||
<property name="name">header-stack-switcher</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stack">sat_stack</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
@@ -347,26 +347,26 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkStack" id="sat_stack">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="can-focus">False</property>
|
||||
<signal name="notify::visible-child-name" handler="on_visible_page" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkBox" id="satellite_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="tooltip_text" translatable="yes">Satellites</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="tooltip-text" translatable="yes">Satellites</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="satellite_view_scrolled">
|
||||
<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="satellite_view">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="model">satellite_model</property>
|
||||
<property name="rubber_banding">True</property>
|
||||
<property name="activate_on_single_click">True</property>
|
||||
<property name="rubber-banding">True</property>
|
||||
<property name="activate-on-single-click">True</property>
|
||||
<signal name="button-press-event" handler="on_button_press" object="popup_menu" swapped="no"/>
|
||||
<signal name="cursor-changed" handler="on_satellite_selection" swapped="no"/>
|
||||
<signal name="key-press-event" handler="on_key_press" swapped="no"/>
|
||||
@@ -393,7 +393,7 @@ Author: Dmitriy Yefremov
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="sat_pos_column">
|
||||
<property name="fixed_width">85</property>
|
||||
<property name="fixed-width">85</property>
|
||||
<property name="title" translatable="yes">Pos</property>
|
||||
<property name="alignment">0.49000000953674316</property>
|
||||
<child>
|
||||
@@ -417,17 +417,17 @@ Author: Dmitriy Yefremov
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="sat_status_box">
|
||||
<property name="height_request">26</property>
|
||||
<property name="height-request">26</property>
|
||||
<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="can-focus">False</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="spacing">5</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="sat_count_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">document-properties</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="icon-name">document-properties</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
@@ -438,9 +438,9 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkLabel" id="sat_count_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">0</property>
|
||||
<property name="width_chars">4</property>
|
||||
<property name="width-chars">4</property>
|
||||
<property name="xalign">0</property>
|
||||
</object>
|
||||
<packing>
|
||||
@@ -465,22 +465,22 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkBox" id="terrestrial_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="tooltip_text" translatable="yes">Terrestrial</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="tooltip-text" translatable="yes">Terrestrial</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="terrestrial_view_scrolled">
|
||||
<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="terrestrial_view">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="model">terrestrial_model</property>
|
||||
<property name="search_column">0</property>
|
||||
<property name="rubber_banding">True</property>
|
||||
<property name="activate_on_single_click">True</property>
|
||||
<property name="search-column">0</property>
|
||||
<property name="rubber-banding">True</property>
|
||||
<property name="activate-on-single-click">True</property>
|
||||
<signal name="button-press-event" handler="on_button_press" object="popup_menu" swapped="no"/>
|
||||
<signal name="cursor-changed" handler="on_terrestrial_selection" swapped="no"/>
|
||||
<signal name="key-press-event" handler="on_key_press" swapped="no"/>
|
||||
@@ -516,17 +516,17 @@ Author: Dmitriy Yefremov
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="ter_status_box">
|
||||
<property name="height_request">26</property>
|
||||
<property name="height-request">26</property>
|
||||
<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="can-focus">False</property>
|
||||
<property name="margin-left">5</property>
|
||||
<property name="margin-right">5</property>
|
||||
<property name="spacing">5</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="ter_count_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">document-properties</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="icon-name">document-properties</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
@@ -537,9 +537,9 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkLabel" id="ter_count_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">0</property>
|
||||
<property name="width_chars">4</property>
|
||||
<property name="width-chars">4</property>
|
||||
<property name="xalign">0</property>
|
||||
</object>
|
||||
<packing>
|
||||
@@ -565,22 +565,22 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkBox" id="cable_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="tooltip_text" translatable="yes">Cable</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="tooltip-text" translatable="yes">Cable</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="cable_view_scrolled">
|
||||
<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="cable_view">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="model">cable_model</property>
|
||||
<property name="search_column">0</property>
|
||||
<property name="rubber_banding">True</property>
|
||||
<property name="activate_on_single_click">True</property>
|
||||
<property name="search-column">0</property>
|
||||
<property name="rubber-banding">True</property>
|
||||
<property name="activate-on-single-click">True</property>
|
||||
<signal name="button-press-event" handler="on_button_press" object="popup_menu" swapped="no"/>
|
||||
<signal name="cursor-changed" handler="on_cable_selection" swapped="no"/>
|
||||
<signal name="key-press-event" handler="on_key_press" swapped="no"/>
|
||||
@@ -616,17 +616,17 @@ Author: Dmitriy Yefremov
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="cable_status_box">
|
||||
<property name="height_request">26</property>
|
||||
<property name="height-request">26</property>
|
||||
<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="can-focus">False</property>
|
||||
<property name="margin-left">5</property>
|
||||
<property name="margin-right">5</property>
|
||||
<property name="spacing">5</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="cable_count_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">document-properties</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="icon-name">document-properties</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
@@ -637,9 +637,9 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkLabel" id="cable_count_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">0</property>
|
||||
<property name="width_chars">4</property>
|
||||
<property name="width-chars">4</property>
|
||||
<property name="xalign">0</property>
|
||||
</object>
|
||||
<packing>
|
||||
@@ -674,7 +674,7 @@ Author: Dmitriy Yefremov
|
||||
<child type="label">
|
||||
<object class="GtkLabel" id="editor_sat_frame_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">DVB</property>
|
||||
</object>
|
||||
</child>
|
||||
@@ -687,39 +687,39 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkFrame" id="editor_transponder_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="transponders_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="can-focus">False</property>
|
||||
<property name="margin-left">5</property>
|
||||
<property name="margin-right">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">5</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="editor_tr_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">2</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">2</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<property name="spacing">5</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="transponder_add_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Add</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="tooltip-text" translatable="yes">Add</property>
|
||||
<signal name="clicked" handler="on_transponder_add" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="add_transponder_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">document-new-symbolic</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="icon-name">document-new-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
@@ -742,25 +742,25 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkStack" id="transponders_stack">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="can-focus">False</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="sat_tr_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="GtkScrolledWindow" id="sat_tr_view_scrolled">
|
||||
<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_tr_view">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="model">sat_tr_view_model</property>
|
||||
<property name="search_column">0</property>
|
||||
<property name="rubber_banding">True</property>
|
||||
<property name="enable_grid_lines">both</property>
|
||||
<property name="search-column">0</property>
|
||||
<property name="rubber-banding">True</property>
|
||||
<property name="enable-grid-lines">both</property>
|
||||
<signal name="button-press-event" handler="on_tr_button_press" object="transponder_popup_menu" swapped="no"/>
|
||||
<signal name="key-press-event" handler="on_tr_key_press" swapped="no"/>
|
||||
<child internal-child="selection">
|
||||
@@ -771,7 +771,7 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="freq_column">
|
||||
<property name="resizable">True</property>
|
||||
<property name="min_width">20</property>
|
||||
<property name="min-width">20</property>
|
||||
<property name="title" translatable="yes">Freq</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="alignment">0.5</property>
|
||||
@@ -788,7 +788,7 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="rate_column">
|
||||
<property name="resizable">True</property>
|
||||
<property name="min_width">20</property>
|
||||
<property name="min-width">20</property>
|
||||
<property name="title" translatable="yes">Rate</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="alignment">0.5</property>
|
||||
@@ -805,7 +805,7 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="pol_column">
|
||||
<property name="resizable">True</property>
|
||||
<property name="min_width">20</property>
|
||||
<property name="min-width">20</property>
|
||||
<property name="title" translatable="yes">Pol</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="alignment">0.5</property>
|
||||
@@ -822,7 +822,7 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="fec_column">
|
||||
<property name="resizable">True</property>
|
||||
<property name="min_width">20</property>
|
||||
<property name="min-width">20</property>
|
||||
<property name="title" translatable="yes">FEC</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="alignment">0.5</property>
|
||||
@@ -839,7 +839,7 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="sys_column">
|
||||
<property name="resizable">True</property>
|
||||
<property name="min_width">20</property>
|
||||
<property name="min-width">20</property>
|
||||
<property name="title" translatable="yes">System</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="alignment">0.5</property>
|
||||
@@ -856,7 +856,7 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="mod_column">
|
||||
<property name="resizable">True</property>
|
||||
<property name="min_width">20</property>
|
||||
<property name="min-width">20</property>
|
||||
<property name="title" translatable="yes">Mod</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="alignment">0.5</property>
|
||||
@@ -935,17 +935,17 @@ Author: Dmitriy Yefremov
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="sat_tr_status_box">
|
||||
<property name="height_request">26</property>
|
||||
<property name="height-request">26</property>
|
||||
<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="can-focus">False</property>
|
||||
<property name="margin-left">5</property>
|
||||
<property name="margin-right">5</property>
|
||||
<property name="spacing">5</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="sat_tr_count_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">document-properties</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="icon-name">document-properties</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
@@ -956,9 +956,9 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkLabel" id="sat_tr_count_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">0</property>
|
||||
<property name="width_chars">4</property>
|
||||
<property name="width-chars">4</property>
|
||||
<property name="xalign">0</property>
|
||||
</object>
|
||||
<packing>
|
||||
@@ -983,21 +983,21 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkBox" id="ter_tr_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="GtkScrolledWindow" id="ter_tr_view_scrolled">
|
||||
<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="ter_tr_view">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="model">ter_tr_view_model</property>
|
||||
<property name="search_column">0</property>
|
||||
<property name="rubber_banding">True</property>
|
||||
<property name="enable_grid_lines">both</property>
|
||||
<property name="search-column">0</property>
|
||||
<property name="rubber-banding">True</property>
|
||||
<property name="enable-grid-lines">both</property>
|
||||
<signal name="button-press-event" handler="on_tr_button_press" object="transponder_popup_menu" swapped="no"/>
|
||||
<signal name="key-press-event" handler="on_tr_key_press" swapped="no"/>
|
||||
<child internal-child="selection">
|
||||
@@ -1008,7 +1008,7 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="ter_freq_column">
|
||||
<property name="resizable">True</property>
|
||||
<property name="min_width">20</property>
|
||||
<property name="min-width">20</property>
|
||||
<property name="title" translatable="yes">Freq</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="alignment">0.5</property>
|
||||
@@ -1025,7 +1025,7 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="ter_system_column">
|
||||
<property name="resizable">True</property>
|
||||
<property name="min_width">20</property>
|
||||
<property name="min-width">20</property>
|
||||
<property name="title" translatable="yes">System</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="alignment">0.5</property>
|
||||
@@ -1042,7 +1042,7 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="ter_bandwidth_column">
|
||||
<property name="resizable">True</property>
|
||||
<property name="min_width">20</property>
|
||||
<property name="min-width">20</property>
|
||||
<property name="title" translatable="yes">Bandwidth</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="alignment">0.5</property>
|
||||
@@ -1059,7 +1059,7 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="ter_constellation_column">
|
||||
<property name="resizable">True</property>
|
||||
<property name="min_width">20</property>
|
||||
<property name="min-width">20</property>
|
||||
<property name="title" translatable="yes">Constellation</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="alignment">0.5</property>
|
||||
@@ -1076,7 +1076,7 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="ter_rate_hp_column">
|
||||
<property name="resizable">True</property>
|
||||
<property name="min_width">20</property>
|
||||
<property name="min-width">20</property>
|
||||
<property name="title" translatable="yes">SR (HP)</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="alignment">0.5</property>
|
||||
@@ -1107,7 +1107,7 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="ter_guard_column">
|
||||
<property name="resizable">True</property>
|
||||
<property name="min_width">20</property>
|
||||
<property name="min-width">20</property>
|
||||
<property name="title" translatable="yes">Guard</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="alignment">0.5</property>
|
||||
@@ -1177,17 +1177,17 @@ Author: Dmitriy Yefremov
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="ter_tr_status_box">
|
||||
<property name="height_request">26</property>
|
||||
<property name="height-request">26</property>
|
||||
<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="can-focus">False</property>
|
||||
<property name="margin-left">5</property>
|
||||
<property name="margin-right">5</property>
|
||||
<property name="spacing">5</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="ter_tr_count_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">document-properties</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="icon-name">document-properties</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
@@ -1198,9 +1198,9 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkLabel" id="ter_tr_count_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">0</property>
|
||||
<property name="width_chars">4</property>
|
||||
<property name="width-chars">4</property>
|
||||
<property name="xalign">0</property>
|
||||
</object>
|
||||
<packing>
|
||||
@@ -1226,21 +1226,21 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkBox" id="cable_tr_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="GtkScrolledWindow" id="cable_tr_view_scrolled">
|
||||
<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="cable_tr_view">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="model">cable_tr_view_model</property>
|
||||
<property name="search_column">0</property>
|
||||
<property name="rubber_banding">True</property>
|
||||
<property name="enable_grid_lines">both</property>
|
||||
<property name="search-column">0</property>
|
||||
<property name="rubber-banding">True</property>
|
||||
<property name="enable-grid-lines">both</property>
|
||||
<signal name="button-press-event" handler="on_tr_button_press" object="transponder_popup_menu" swapped="no"/>
|
||||
<signal name="key-press-event" handler="on_tr_key_press" swapped="no"/>
|
||||
<child internal-child="selection">
|
||||
@@ -1251,7 +1251,7 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="cable_freq_column">
|
||||
<property name="resizable">True</property>
|
||||
<property name="min_width">20</property>
|
||||
<property name="min-width">20</property>
|
||||
<property name="title" translatable="yes">Freq</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="alignment">0.5</property>
|
||||
@@ -1268,7 +1268,7 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="cable_rate_column">
|
||||
<property name="resizable">True</property>
|
||||
<property name="min_width">20</property>
|
||||
<property name="min-width">20</property>
|
||||
<property name="title" translatable="yes">Rate</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="alignment">0.5</property>
|
||||
@@ -1285,7 +1285,7 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="cable_fec_column">
|
||||
<property name="resizable">True</property>
|
||||
<property name="min_width">20</property>
|
||||
<property name="min-width">20</property>
|
||||
<property name="title" translatable="yes">FEC</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="alignment">0.5</property>
|
||||
@@ -1302,7 +1302,7 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="cable_mod_column">
|
||||
<property name="resizable">True</property>
|
||||
<property name="min_width">20</property>
|
||||
<property name="min-width">20</property>
|
||||
<property name="title" translatable="yes">Mod</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="alignment">0.5</property>
|
||||
@@ -1327,17 +1327,17 @@ Author: Dmitriy Yefremov
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="cable_tr_status_box">
|
||||
<property name="height_request">26</property>
|
||||
<property name="height-request">26</property>
|
||||
<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="can-focus">False</property>
|
||||
<property name="margin-left">5</property>
|
||||
<property name="margin-right">5</property>
|
||||
<property name="spacing">5</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="cable_tr_count_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">document-properties</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="icon-name">document-properties</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
@@ -1348,9 +1348,9 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkLabel" id="cable_tr_count_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">0</property>
|
||||
<property name="width_chars">4</property>
|
||||
<property name="width-chars">4</property>
|
||||
<property name="xalign">0</property>
|
||||
</object>
|
||||
<packing>
|
||||
@@ -1385,7 +1385,7 @@ Author: Dmitriy Yefremov
|
||||
<child type="label">
|
||||
<object class="GtkLabel" id="editor_transponder_frame_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">Transponder</property>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
VER="3.4.1_Beta"
|
||||
VER="3.6.0_Beta"
|
||||
B_PATH="dist/DemonEditor"
|
||||
DEB_PATH="$B_PATH/usr/share/demoneditor"
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Package: demon-editor
|
||||
Version: 3.4.1-Beta
|
||||
Version: 3.6.0-Beta
|
||||
Section: utils
|
||||
Priority: optional
|
||||
Architecture: all
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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.1.{BUILD_DATE} Beta",
|
||||
'CFBundleShortVersionString': f"3.6.0.{BUILD_DATE} Beta",
|
||||
'NSHumanReadableCopyright': u"Copyright © 2023, Dmitriy Yefremov",
|
||||
'NSRequiresAquaSystemAppearance': 'false',
|
||||
'NSHighResolutionCapable': 'true'
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -1440,3 +1440,51 @@ 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 "Аўтаматычная ўсталёўка імя, абранага ў спісе букетаў."
|
||||
|
||||
msgid "Merge satellites by positions"
|
||||
msgstr "Аб'яднаць спадарожнікі па пазіцыях"
|
||||
|
||||
msgid "Save satellite selection"
|
||||
msgstr "Захоўваць выбар спадарожнікаў"
|
||||
|
||||
msgid "Extract direct links"
|
||||
msgstr "Выняць простыя спасылкі"
|
||||
|
||||
msgid "URL prefix:"
|
||||
msgstr "Префикс URL:"
|
||||
|
||||
msgid "Invalid prefix for the given URL!"
|
||||
msgstr "Недапушчальны прэфікс для дадзенага URL!"
|
||||
|
||||
msgid "Alternate window title"
|
||||
msgstr "Альтэрнатыўны загаловак акна"
|
||||
|
||||
msgid "Selected type:"
|
||||
msgstr "Абраны тып:"
|
||||
|
||||
@@ -1454,3 +1454,51 @@ 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."
|
||||
|
||||
msgid "Merge satellites by positions"
|
||||
msgstr "Satelliten nach Pos. zusammenführen"
|
||||
|
||||
msgid "Save satellite selection"
|
||||
msgstr "Satellitenauswahl speichern"
|
||||
|
||||
msgid "Extract direct links"
|
||||
msgstr "Direktlinks extrahieren"
|
||||
|
||||
msgid "URL prefix:"
|
||||
msgstr "URL-Präfix:"
|
||||
|
||||
msgid "Invalid prefix for the given URL!"
|
||||
msgstr "Ungültiges Präfix für die angegebene URL!"
|
||||
|
||||
msgid "Alternate window title"
|
||||
msgstr "Alternativer Fenstertitel"
|
||||
|
||||
msgid "Selected type:"
|
||||
msgstr "Ausgewählt Typ:"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (C) 2018-2022 Víctor Pont
|
||||
# Copyright (C) 2018-2023 Frank Neirynck
|
||||
# This file is distributed under the MIT license.
|
||||
#
|
||||
# Frank Neirynck <frank@insink.be>, 2018-2020.
|
||||
# Frank Neirynck <frank@insink.be>, 2018-2023.
|
||||
# Víctor Pont <victor@pont.cat>, 2021-2022.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -1441,3 +1441,57 @@ msgstr "Habilita la carga como un archivo si se selecciona una gran cantidad de
|
||||
|
||||
msgid "Clear \"New\" flag"
|
||||
msgstr "Limpiar \"Nuevo\" flag"
|
||||
|
||||
msgid "Group by"
|
||||
msgstr "Agrupar por"
|
||||
|
||||
msgid "Replace existing"
|
||||
msgstr "Sustituir los existentes"
|
||||
|
||||
msgid "Already exists"
|
||||
msgstr "Ya existe"
|
||||
|
||||
msgid "Enable unlimited copy buffer"
|
||||
msgstr "Activar búfer de copia ilimitado"
|
||||
|
||||
msgid "Enables unlimited copy buffer for the bouquets tab."
|
||||
msgstr "Activa el búfer de copia ilimitado para la pestaña de bouquets."
|
||||
|
||||
msgid "Start time"
|
||||
msgstr "Hora de inicio"
|
||||
|
||||
msgid "End time"
|
||||
msgstr "Hora final"
|
||||
|
||||
msgid "Enable extensions support"
|
||||
msgstr "Activar el soporte de extensiones"
|
||||
|
||||
msgid "After uploading the changes you may need to completely reboot the receiver!"
|
||||
msgstr "Después de cargar los cambios, es posible que tenga que reiniciar completamente el receptor."
|
||||
|
||||
msgid "Remove duplicates"
|
||||
msgstr "Eliminar duplicados"
|
||||
|
||||
msgid "Removed"
|
||||
msgstr "Eliminado"
|
||||
|
||||
msgid "Enables overwriting existing main list services."
|
||||
msgstr "Permite sobrescribir los servicios existentes de la lista principal."
|
||||
|
||||
msgid "Enables skipping services import from lamedb."
|
||||
msgstr "Permite omitir la importación de servicios desde lamedb."
|
||||
|
||||
msgid "Bouquets data only"
|
||||
msgstr "Sólo datos de bouquets"
|
||||
|
||||
msgid "Create Category bouquets"
|
||||
msgstr "Crear categoría de bouquets"
|
||||
|
||||
msgid "Create Regional bouquets"
|
||||
msgstr "Crear bouquets regionales"
|
||||
|
||||
msgid "Skip C-band"
|
||||
msgstr "Omitir banda C"
|
||||
|
||||
msgid "Automatically set the name selected in the bouquet list."
|
||||
msgstr "Establece automáticamente el nombre seleccionado en la lista de bouquets."
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"PO-Revision-Date: 2023-02-12 07:10+0100\n"
|
||||
"PO-Revision-Date: 2023-04-13 02:15+0200\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,58 @@ 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."
|
||||
|
||||
msgid "Merge satellites by positions"
|
||||
msgstr "Unisci i satelliti per posizione"
|
||||
|
||||
msgid "Save satellite selection"
|
||||
msgstr "Salva la selezione dei satelliti"
|
||||
|
||||
msgid "Extract direct links"
|
||||
msgstr "Estrai link diretti"
|
||||
|
||||
msgid "URL prefix:"
|
||||
msgstr "Prefisso URL:"
|
||||
|
||||
msgid "Invalid prefix for the given URL!"
|
||||
msgstr "Prefisso non valido per l'URL specificata!"
|
||||
|
||||
msgid "Alternate window title"
|
||||
msgstr "Titolo alternativo della finestra"
|
||||
|
||||
msgid "Selected type:"
|
||||
msgstr "Tipo selezionato:"
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (C) 2018-2020 Frank Neirynck
|
||||
# Copyright (C) 2018-2023 Frank Neirynck
|
||||
# This file is distributed under the MIT license.
|
||||
#
|
||||
# Frank Neirynck <frank@insink.be>, 2018-2022.
|
||||
@@ -1401,3 +1401,57 @@ msgstr "Maakt uploaden als archief mogelijk als een groot aantal pictogrammen (>
|
||||
|
||||
msgid "Clear \"New\" flag"
|
||||
msgstr "Opruimen \"Niew\" flag"
|
||||
|
||||
msgid "Group by"
|
||||
msgstr "Groeperen per"
|
||||
|
||||
msgid "Replace existing"
|
||||
msgstr "Vervang bestaande"
|
||||
|
||||
msgid "Already exists"
|
||||
msgstr "Bestaat reeds"
|
||||
|
||||
msgid "Enable unlimited copy buffer"
|
||||
msgstr "Onbeperkte kopieerbuffer inschakelen"
|
||||
|
||||
msgid "Enables unlimited copy buffer for the bouquets tab."
|
||||
msgstr "Schakelt een onbeperkte kopieerbuffer in voor het boeketten tabblad."
|
||||
|
||||
msgid "Start time"
|
||||
msgstr "Starttijd"
|
||||
|
||||
msgid "End time"
|
||||
msgstr "Eindtijd"
|
||||
|
||||
msgid "Enable extensions support"
|
||||
msgstr "Ondersteuning voor extensies inschakelen"
|
||||
|
||||
msgid "After uploading the changes you may need to completely reboot the receiver!"
|
||||
msgstr "Na het uploaden van de wijzigingen kan het nodig zijn de ontvanger volledig opnieuw op te starten!"
|
||||
|
||||
msgid "Remove duplicates"
|
||||
msgstr "Duplicaten verwijderen"
|
||||
|
||||
msgid "Removed"
|
||||
msgstr "Verwijderd"
|
||||
|
||||
msgid "Enables overwriting existing main list services."
|
||||
msgstr "Maakt het overschrijven van bestaande hoofdlijst diensten mogelijk."
|
||||
|
||||
msgid "Enables skipping services import from lamedb."
|
||||
msgstr "Maakt het overslaan van dienstenimport uit lamedb mogelijk."
|
||||
|
||||
msgid "Bouquets data only"
|
||||
msgstr "Alleen gegevens over boeketten"
|
||||
|
||||
msgid "Create Category bouquets"
|
||||
msgstr "Maak categorie boeketten"
|
||||
|
||||
msgid "Create Regional bouquets"
|
||||
msgstr "Maak regionale boeketten"
|
||||
|
||||
msgid "Skip C-band"
|
||||
msgstr "C-band overslaan"
|
||||
|
||||
msgid "Automatically set the name selected in the bouquet list."
|
||||
msgstr "Stel automatisch de naam in die is geselecteerd in de boeketlijst."
|
||||
|
||||
@@ -1437,3 +1437,51 @@ 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 "Автоматическая установка имени, выбранного в списке букетов."
|
||||
|
||||
msgid "Merge satellites by positions"
|
||||
msgstr "Объединять спутники по позициям"
|
||||
|
||||
msgid "Save satellite selection"
|
||||
msgstr "Сохранять выбор спутников"
|
||||
|
||||
msgid "Extract direct links"
|
||||
msgstr "Извлечь прямые ссылки"
|
||||
|
||||
msgid "URL prefix:"
|
||||
msgstr "Префикс URL:"
|
||||
|
||||
msgid "Invalid prefix for the given URL!"
|
||||
msgstr "Недопустимый префикс для данного URL!"
|
||||
|
||||
msgid "Alternate window title"
|
||||
msgstr "Альтернативный заголовок окна"
|
||||
|
||||
msgid "Selected type:"
|
||||
msgstr "Выбран тип:"
|
||||
|
||||
@@ -3,9 +3,9 @@ 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-18 00:56+0300\n"
|
||||
"PO-Revision-Date: 2023-04-09 01:44+0300\n"
|
||||
"Last-Translator: audi06_19 <info@dreamosat-forum.com>\n"
|
||||
"Language-Team: \n"
|
||||
"Language-Team: audi06_19 <info@dreamosat-forum.com>\n"
|
||||
"Language: tr\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -1471,3 +1471,48 @@ 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ı"
|
||||
|
||||
msgid "Enables overwriting existing main list services."
|
||||
msgstr "Mevcut ana liste hizmetlerinin üzerine yazılmasını sağlar."
|
||||
|
||||
msgid "Enables skipping services import from lamedb."
|
||||
msgstr "Lamedb'den içe aktarılan hizmetlerin atlanmasını sağlar."
|
||||
|
||||
msgid "Bouquets data only"
|
||||
msgstr "Yalnızca buket verileri"
|
||||
|
||||
msgid "Create Category bouquets"
|
||||
msgstr "Kategori buketleri oluştur"
|
||||
|
||||
msgid "Create Regional bouquets"
|
||||
msgstr "Bölgesel buketler oluşturun"
|
||||
|
||||
msgid "Skip C-band"
|
||||
msgstr "C-band atla"
|
||||
|
||||
msgid "Automatically set the name selected in the bouquet list."
|
||||
msgstr "Buket listesinde seçilen isimleri otomatik olarak ayarlayın."
|
||||
|
||||
msgid "Merge satellites by positions"
|
||||
msgstr "Uyduları konumlara göre birleştir"
|
||||
|
||||
msgid "Save satellite selection"
|
||||
msgstr "Uydu seçimini kaydet"
|
||||
|
||||
msgid "Extract direct links"
|
||||
msgstr "Doğrudan bağlantıları ayıklayın"
|
||||
|
||||
msgid "URL prefix:"
|
||||
msgstr "URL öneki:"
|
||||
|
||||
msgid "Invalid prefix for the given URL!"
|
||||
msgstr "Belirtilen URL için geçersiz önek!"
|
||||
|
||||
msgid "Alternate window title"
|
||||
msgstr "Alternatif pencere başlığı"
|
||||
|
||||
Reference in New Issue
Block a user