mirror of
https://github.com/DYefremov/DemonEditor.git
synced 2026-05-09 12:15:30 +02:00
Compare commits
51 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d3822474ba | ||
|
|
e1ce9f3006 | ||
|
|
c2b0768857 | ||
|
|
283d85ef8e | ||
|
|
f5656d8d5f | ||
|
|
5dd5a09bfc | ||
|
|
1b5f3372b4 | ||
|
|
974e964f42 | ||
|
|
8cb6ed02d2 | ||
|
|
8bb3b780d1 | ||
|
|
3000c8830c | ||
|
|
ac550e016d | ||
|
|
7420751806 | ||
|
|
f35889e8e4 | ||
|
|
857b252f4c | ||
|
|
572584a14f | ||
|
|
7e4ac3e69c | ||
|
|
0d73ffa79d | ||
|
|
5e2f1ddb84 | ||
|
|
6c4040901f | ||
|
|
103e09b900 | ||
|
|
8ddc517ab7 | ||
|
|
b26d982db4 | ||
|
|
3733bc395b | ||
|
|
26bfbafc0e | ||
|
|
84d1a18111 | ||
|
|
1cdacd5276 | ||
|
|
354715558c | ||
|
|
bca1613bff | ||
|
|
36b533b890 | ||
|
|
2eabccc1a9 | ||
|
|
75cd78277e | ||
|
|
5181b732ed | ||
|
|
513c0e8d3d | ||
|
|
f932feb305 | ||
|
|
6a2fda5ec0 | ||
|
|
86c30dd2c1 | ||
|
|
0ed41c473d | ||
|
|
5078a854d2 | ||
|
|
353bf04924 | ||
|
|
474ff8e303 | ||
|
|
5834bd4a0b | ||
|
|
81f31e5d8d | ||
|
|
267f645c16 | ||
|
|
8c10d7d6a5 | ||
|
|
bbdb47ee7a | ||
|
|
7f6856e6aa | ||
|
|
3439a3ad0a | ||
|
|
ee2e2ac49d | ||
|
|
a745167fb7 | ||
|
|
8551bc2459 |
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2018 Dmitriy Yefremov
|
Copyright (c) 2018-2019 Dmitriy Yefremov
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
@@ -20,6 +20,9 @@ Clipboard is **"rubber"**. There is an accumulation before the insertion!
|
|||||||
* **Space** - select/deselect.
|
* **Space** - select/deselect.
|
||||||
* **Left/Right** - remove selection.
|
* **Left/Right** - remove selection.
|
||||||
* **Ctrl + Up, Down, PageUp, PageDown, Home, End** - move selected items in the list.
|
* **Ctrl + Up, Down, PageUp, PageDown, Home, End** - move selected items in the list.
|
||||||
|
* **Ctrl + O** - (re)load user data from current dir.
|
||||||
|
* **Ctrl + D** - load data from receiver.
|
||||||
|
* **Ctrl + U/B** upload data/bouquets to receiver.
|
||||||
|
|
||||||
### Extra:
|
### Extra:
|
||||||
* Multiple selections in lists only with Space key (as in file managers).
|
* Multiple selections in lists only with Space key (as in file managers).
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class TestException(Exception):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def download_data(*, properties, download_type=DownloadType.ALL, callback=None):
|
def download_data(*, properties, download_type=DownloadType.ALL, callback):
|
||||||
with FTP(host=properties["host"], user=properties["user"], passwd=properties["password"]) as ftp:
|
with FTP(host=properties["host"], user=properties["user"], passwd=properties["password"]) as ftp:
|
||||||
ftp.encoding = "utf-8"
|
ftp.encoding = "utf-8"
|
||||||
callback("FTP OK.\n")
|
callback("FTP OK.\n")
|
||||||
@@ -292,10 +292,11 @@ def test_ftp(host, port, user, password, timeout=5):
|
|||||||
raise TestException(e)
|
raise TestException(e)
|
||||||
|
|
||||||
|
|
||||||
def test_http(host, port, user, password, timeout=5):
|
def test_http(host, port, user, password, timeout=5, skip_message=False):
|
||||||
try:
|
try:
|
||||||
params = urlencode({"text": "Connection test", "type": 2, "timeout": timeout})
|
params = urlencode({"text": "Connection test", "type": 2, "timeout": timeout})
|
||||||
url = "http://{}:{}/api/message?{}".format(host, port, params)
|
params = "statusinfo" if skip_message else "message?{}".format(params)
|
||||||
|
url = "http://{}:{}/api/{}".format(host, port, params)
|
||||||
# authentication
|
# authentication
|
||||||
init_auth(user, password, url)
|
init_auth(user, password, url)
|
||||||
|
|
||||||
|
|||||||
@@ -90,18 +90,23 @@ def parse_bouquets(path, bq_name, bq_type):
|
|||||||
lines = file.readlines()
|
lines = file.readlines()
|
||||||
bouquets = None
|
bouquets = None
|
||||||
nm_sep = "#NAME"
|
nm_sep = "#NAME"
|
||||||
|
bq_pattern = re.compile(".*userbouquet\\.+(.*)\\.+[tv|radio].*")
|
||||||
|
|
||||||
for line in lines:
|
for line in lines:
|
||||||
if nm_sep in line:
|
if nm_sep in line:
|
||||||
_, _, name = line.partition(nm_sep)
|
_, _, name = line.partition(nm_sep)
|
||||||
bouquets = Bouquets(name.strip(), bq_type, [])
|
bouquets = Bouquets(name.strip(), bq_type, [])
|
||||||
if bouquets and "#SERVICE" in line:
|
if bouquets and "#SERVICE" in line:
|
||||||
b_name, services = get_bouquet(path, line.split(".")[1], bq_type)
|
name = re.match(bq_pattern, line)
|
||||||
bouquets[2].append(Bouquet(name=b_name,
|
if name:
|
||||||
type=bq_type,
|
b_name, services = get_bouquet(path, name.group(1), bq_type)
|
||||||
services=services,
|
bouquets[2].append(Bouquet(name=b_name,
|
||||||
locked=None,
|
type=bq_type,
|
||||||
hidden=None))
|
services=services,
|
||||||
|
locked=None,
|
||||||
|
hidden=None))
|
||||||
|
else:
|
||||||
|
raise ValueError("No bouquet name found for: {}".format(line))
|
||||||
|
|
||||||
return bouquets
|
return bouquets
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ MARKER_FORMAT = " 1:64:{}:0:0:0:0:0:0:0::{}\n#DESCRIPTION {}\n"
|
|||||||
class StreamType(Enum):
|
class StreamType(Enum):
|
||||||
DVB_TS = "1"
|
DVB_TS = "1"
|
||||||
NONE_TS = "4097"
|
NONE_TS = "4097"
|
||||||
|
NONE_REC_1 = "5001"
|
||||||
|
NONE_REC_2 = "5002"
|
||||||
|
|
||||||
|
|
||||||
def parse_m3u(path, profile):
|
def parse_m3u(path, profile):
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ def write_satellites(satellites, data_path):
|
|||||||
transponder_child.setAttribute("system", get_key_by_value(SYSTEM, tr.system))
|
transponder_child.setAttribute("system", get_key_by_value(SYSTEM, tr.system))
|
||||||
transponder_child.setAttribute("modulation", get_key_by_value(MODULATION, tr.modulation))
|
transponder_child.setAttribute("modulation", get_key_by_value(MODULATION, tr.modulation))
|
||||||
if tr.pls_mode:
|
if tr.pls_mode:
|
||||||
transponder_child.setAttribute("pls_mode", get_key_by_value(PLS_MODE, tr.pls_mode))
|
transponder_child.setAttribute("pls_mode", tr.pls_mode)
|
||||||
if tr.pls_code:
|
if tr.pls_code:
|
||||||
transponder_child.setAttribute("pls_code", tr.pls_code)
|
transponder_child.setAttribute("pls_code", tr.pls_code)
|
||||||
if tr.is_id:
|
if tr.is_id:
|
||||||
@@ -88,7 +88,7 @@ def parse_transponders(elem, sat_name):
|
|||||||
FEC[atr["fec_inner"].value],
|
FEC[atr["fec_inner"].value],
|
||||||
SYSTEM[atr["system"].value],
|
SYSTEM[atr["system"].value],
|
||||||
MODULATION[atr["modulation"].value],
|
MODULATION[atr["modulation"].value],
|
||||||
PLS_MODE[atr["pls_mode"].value] if "pls_mode" in atr else None,
|
atr["pls_mode"].value if "pls_mode" in atr else None,
|
||||||
atr["pls_code"].value if "pls_code" in atr else None,
|
atr["pls_code"].value if "pls_code" in atr else None,
|
||||||
atr["is_id"].value if "is_id" in atr else None)
|
atr["is_id"].value if "is_id" in atr else None)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@@ -48,7 +48,8 @@ def get_default_settings():
|
|||||||
"backup_dir_path": DATA_PATH + "enigma2/backup/",
|
"backup_dir_path": DATA_PATH + "enigma2/backup/",
|
||||||
"backup_before_save": True, "backup_before_downloading": True,
|
"backup_before_save": True, "backup_before_downloading": True,
|
||||||
"v5_support": False, "http_api_support": False,
|
"v5_support": False, "http_api_support": False,
|
||||||
"use_colors": True, "new_color": "rgb(255,230,204)", "extra_color": "rgb(179,230,204)"},
|
"use_colors": True, "new_color": "rgb(255,230,204)", "extra_color": "rgb(179,230,204)",
|
||||||
|
"fav_click_mode": 0},
|
||||||
Profile.NEUTRINO_MP.value: {
|
Profile.NEUTRINO_MP.value: {
|
||||||
"host": "127.0.0.1", "port": "21", "user": "root", "password": "root",
|
"host": "127.0.0.1", "port": "21", "user": "root", "password": "root",
|
||||||
"http_user": "", "http_password": "", "http_port": "80", "http_timeout": 2,
|
"http_user": "", "http_password": "", "http_port": "80", "http_timeout": 2,
|
||||||
@@ -57,7 +58,8 @@ def get_default_settings():
|
|||||||
"satellites_xml_path": "/var/tuxbox/config/", "data_dir_path": DATA_PATH + "neutrino/",
|
"satellites_xml_path": "/var/tuxbox/config/", "data_dir_path": DATA_PATH + "neutrino/",
|
||||||
"picons_path": "/usr/share/tuxbox/neutrino/icons/logo/", "picons_dir_path": DATA_PATH + "neutrino/picons/",
|
"picons_path": "/usr/share/tuxbox/neutrino/icons/logo/", "picons_dir_path": DATA_PATH + "neutrino/picons/",
|
||||||
"backup_dir_path": DATA_PATH + "neutrino/backup/",
|
"backup_dir_path": DATA_PATH + "neutrino/backup/",
|
||||||
"backup_before_save": True, "backup_before_downloading": True},
|
"backup_before_save": True, "backup_before_downloading": True,
|
||||||
|
"fav_click_mode": 0},
|
||||||
"profile": Profile.ENIGMA_2.value}
|
"profile": Profile.ENIGMA_2.value}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,13 @@
|
|||||||
for replace or update current satellites.xml file.
|
for replace or update current satellites.xml file.
|
||||||
"""
|
"""
|
||||||
import re
|
import re
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from html.parser import HTMLParser
|
from html.parser import HTMLParser
|
||||||
|
|
||||||
from app.eparser import Satellite, Transponder, is_transponder_valid
|
from app.eparser import Satellite, Transponder, is_transponder_valid
|
||||||
|
from app.eparser.ecommons import PLS_MODE
|
||||||
|
|
||||||
|
|
||||||
class SatelliteSource(Enum):
|
class SatelliteSource(Enum):
|
||||||
@@ -137,6 +139,7 @@ class SatellitesParser(HTMLParser):
|
|||||||
return "{}{}".format("-" if pos[-1] == "W" else "", pos[:-1])
|
return "{}{}".format("-" if pos[-1] == "W" else "", pos[:-1])
|
||||||
|
|
||||||
def get_transponders(self, sat_url):
|
def get_transponders(self, sat_url):
|
||||||
|
""" Getting transponders(sorted by frequency). """
|
||||||
self._rows.clear()
|
self._rows.clear()
|
||||||
url = "https://www.flysat.com/" + sat_url if self._source is SatelliteSource.FLYSAT else sat_url
|
url = "https://www.flysat.com/" + sat_url if self._source is SatelliteSource.FLYSAT else sat_url
|
||||||
request = requests.get(url=url, headers=self._HEADERS)
|
request = requests.get(url=url, headers=self._HEADERS)
|
||||||
@@ -148,13 +151,23 @@ class SatellitesParser(HTMLParser):
|
|||||||
self.get_transponders_for_fly_sat(trs)
|
self.get_transponders_for_fly_sat(trs)
|
||||||
elif self._source is SatelliteSource.LYNGSAT:
|
elif self._source is SatelliteSource.LYNGSAT:
|
||||||
self.get_transponders_for_lyng_sat(trs)
|
self.get_transponders_for_lyng_sat(trs)
|
||||||
return trs
|
|
||||||
|
return sorted(trs, key=lambda x: int(x.frequency))
|
||||||
|
|
||||||
def get_transponders_for_fly_sat(self, trs):
|
def get_transponders_for_fly_sat(self, trs):
|
||||||
""" Parsing transponders for FlySat """
|
""" Parsing transponders for FlySat """
|
||||||
|
pls_pattern = re.compile("(PLS:)+ (Root|Gold|Combo)+ (\\d+)?")
|
||||||
|
is_id_pattern = re.compile("(Stream) (\\d+)")
|
||||||
|
pls_modes = {v: k for k, v in PLS_MODE.items()}
|
||||||
|
n_trs = []
|
||||||
|
|
||||||
if self._rows:
|
if self._rows:
|
||||||
zeros = "000"
|
zeros = "000"
|
||||||
|
is_ids = []
|
||||||
for r in self._rows:
|
for r in self._rows:
|
||||||
|
if len(r) == 1:
|
||||||
|
is_ids.extend(re.findall(is_id_pattern, r[0]))
|
||||||
|
continue
|
||||||
if len(r) < 3:
|
if len(r) < 3:
|
||||||
continue
|
continue
|
||||||
data = r[2].split(" ")
|
data = r[2].split(" ")
|
||||||
@@ -171,16 +184,36 @@ class SatellitesParser(HTMLParser):
|
|||||||
sys, mod = sys
|
sys, mod = sys
|
||||||
mod = "QPSK" if sys == "DVB-S" else mod
|
mod = "QPSK" if sys == "DVB-S" else mod
|
||||||
|
|
||||||
tr = Transponder(freq + zeros, sr + zeros, pol, fec, sys, mod, None, None, None)
|
pls = re.findall(pls_pattern, r[1])
|
||||||
if is_transponder_valid(tr):
|
pls_code = None
|
||||||
trs.append(tr)
|
pls_mode = None
|
||||||
|
|
||||||
|
if pls:
|
||||||
|
pls_code = pls[0][2]
|
||||||
|
pls_mode = pls_modes.get(pls[0][1], None)
|
||||||
|
|
||||||
|
if is_ids:
|
||||||
|
tr = trs.pop()
|
||||||
|
for index, is_id in enumerate(is_ids):
|
||||||
|
tr = tr._replace(is_id=is_id[1])
|
||||||
|
if is_transponder_valid(tr):
|
||||||
|
n_trs.append(tr)
|
||||||
|
else:
|
||||||
|
tr = Transponder(freq + zeros, sr + zeros, pol, fec, sys, mod, pls_mode, pls_code, None)
|
||||||
|
if is_transponder_valid(tr):
|
||||||
|
trs.append(tr)
|
||||||
|
is_ids.clear()
|
||||||
|
trs.extend(n_trs)
|
||||||
|
|
||||||
def get_transponders_for_lyng_sat(self, trs):
|
def get_transponders_for_lyng_sat(self, trs):
|
||||||
""" Parsing transponders for LyngSat """
|
""" Parsing transponders for LyngSat """
|
||||||
frq_pol_pattern = re.compile("(\d{4,5}).*([RLHV])(.*\d$)")
|
frq_pol_pattern = re.compile("(\\d{4,5}).*([RLHV])(.*\\d$)")
|
||||||
sr_fec_pattern = re.compile("^(\d{4,5})-(\d/\d)(.+PSK)?(.*)?$")
|
sr_fec_pattern = re.compile("^(\\d{4,5})-(\\d/\\d)(.+PSK)?(.*)?$")
|
||||||
sys_pattern = re.compile("(DVB-S[2]?)(.*)?")
|
sys_pattern = re.compile("(DVB-S[2]?) ?(PLS+ (Root|Gold|Combo)+ (\\d+))* ?(multistream stream (\\d+))?",
|
||||||
|
re.IGNORECASE)
|
||||||
zeros = "000"
|
zeros = "000"
|
||||||
|
pls_modes = {v: k for k, v in PLS_MODE.items()}
|
||||||
|
|
||||||
for r in filter(lambda x: len(x) > 8, self._rows):
|
for r in filter(lambda x: len(x) > 8, self._rows):
|
||||||
freq = re.match(frq_pol_pattern, r[2])
|
freq = re.match(frq_pol_pattern, r[2])
|
||||||
if not freq:
|
if not freq:
|
||||||
@@ -191,12 +224,18 @@ class SatellitesParser(HTMLParser):
|
|||||||
continue
|
continue
|
||||||
sr, fec, mod = sr_fec.group(1), sr_fec.group(2), sr_fec.group(3)
|
sr, fec, mod = sr_fec.group(1), sr_fec.group(2), sr_fec.group(3)
|
||||||
mod = mod.strip() if mod else "Auto"
|
mod = mod.strip() if mod else "Auto"
|
||||||
sys = re.match(sys_pattern, r[-4])
|
|
||||||
if not sys:
|
|
||||||
continue
|
|
||||||
sys = sys.group(1)
|
|
||||||
|
|
||||||
tr = Transponder(frq + zeros, sr + zeros, pol, fec, sys, mod, None, None, None)
|
res = re.match(sys_pattern, r[-4])
|
||||||
|
if not res:
|
||||||
|
continue
|
||||||
|
|
||||||
|
sys = res.group(1)
|
||||||
|
pls_mode = res.group(3)
|
||||||
|
pls_mode = pls_modes.get(pls_mode.capitalize(), None) if pls_mode else pls_mode
|
||||||
|
pls_code = res.group(4)
|
||||||
|
pls_id = res.group(6)
|
||||||
|
|
||||||
|
tr = Transponder(frq + zeros, sr + zeros, pol, fec, sys, mod, pls_mode, pls_code, pls_id)
|
||||||
if is_transponder_valid(tr):
|
if is_transponder_valid(tr):
|
||||||
trs.append(tr)
|
trs.append(tr)
|
||||||
|
|
||||||
|
|||||||
@@ -40,8 +40,8 @@ Author: Dmitriy Yefremov
|
|||||||
<property name="icon_name">system-help</property>
|
<property name="icon_name">system-help</property>
|
||||||
<property name="type_hint">normal</property>
|
<property name="type_hint">normal</property>
|
||||||
<property name="program_name">DemonEditor</property>
|
<property name="program_name">DemonEditor</property>
|
||||||
<property name="version">0.4.3 Pre-alpha</property>
|
<property name="version">0.4.4 Pre-alpha</property>
|
||||||
<property name="copyright">2018 Dmitriy Yefremov
|
<property name="copyright">2018-2019 Dmitriy Yefremov
|
||||||
</property>
|
</property>
|
||||||
<property name="comments" translatable="yes">Enigma2 channel and satellites list editor for GNU/Linux</property>
|
<property name="comments" translatable="yes">Enigma2 channel and satellites list editor for GNU/Linux</property>
|
||||||
<property name="website">https://dyefremov.github.io/DemonEditor/</property>
|
<property name="website">https://dyefremov.github.io/DemonEditor/</property>
|
||||||
|
|||||||
388
app/ui/import_dialog.glade
Normal file
388
app/ui/import_dialog.glade
Normal file
@@ -0,0 +1,388 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Generated with glade 3.22.1
|
||||||
|
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2018-2019 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
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
||||||
|
Author: Dmitriy Yefremov
|
||||||
|
|
||||||
|
-->
|
||||||
|
<interface>
|
||||||
|
<requires lib="gtk+" version="3.16"/>
|
||||||
|
<!-- interface-license-type mit -->
|
||||||
|
<!-- interface-name DemonEditor -->
|
||||||
|
<!-- interface-description Enigma2 channel and satellites list editor for GNU/Linux. -->
|
||||||
|
<!-- interface-copyright 2018-2019 Dmitriy Yefremov -->
|
||||||
|
<!-- interface-authors Dmitriy Yefremov -->
|
||||||
|
<object class="GtkListStore" id="main_list_store">
|
||||||
|
<columns>
|
||||||
|
<!-- column-name name -->
|
||||||
|
<column type="gchararray"/>
|
||||||
|
<!-- column-name type -->
|
||||||
|
<column type="gchararray"/>
|
||||||
|
<!-- column-name selected -->
|
||||||
|
<column type="gboolean"/>
|
||||||
|
</columns>
|
||||||
|
</object>
|
||||||
|
<object class="GtkImage" id="remove_selection_image">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="icon_name">edit-undo</property>
|
||||||
|
</object>
|
||||||
|
<object class="GtkMenu" id="popup_menu">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImageMenuItem" id="select_all_popup_item">
|
||||||
|
<property name="label">gtk-select-all</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="use_underline">True</property>
|
||||||
|
<property name="use_stock">True</property>
|
||||||
|
<signal name="activate" handler="on_select_all" object="main_view" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImageMenuItem" id="unselect_all_popup_item">
|
||||||
|
<property name="label" translatable="yes">Remove selection</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="image">remove_selection_image</property>
|
||||||
|
<property name="use_stock">False</property>
|
||||||
|
<signal name="activate" handler="on_unselect_all" object="main_view" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<object class="GtkListStore" id="services_list_store">
|
||||||
|
<columns>
|
||||||
|
<!-- column-name name -->
|
||||||
|
<column type="gchararray"/>
|
||||||
|
<!-- column-name type -->
|
||||||
|
<column type="gchararray"/>
|
||||||
|
</columns>
|
||||||
|
</object>
|
||||||
|
<object class="GtkWindow" id="dialog_window">
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="modal">True</property>
|
||||||
|
<property name="window_position">center-on-parent</property>
|
||||||
|
<property name="default_width">480</property>
|
||||||
|
<property name="default_height">320</property>
|
||||||
|
<property name="destroy_with_parent">True</property>
|
||||||
|
<property name="type_hint">dialog</property>
|
||||||
|
<property name="gravity">center</property>
|
||||||
|
<child type="titlebar">
|
||||||
|
<object class="GtkHeaderBar" id="header_bar">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="title" translatable="yes">Import</property>
|
||||||
|
<property name="subtitle" translatable="yes">Bouquets and services</property>
|
||||||
|
<property name="spacing">2</property>
|
||||||
|
<property name="show_close_button">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkButton" id="import_button">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<property name="tooltip_text" translatable="yes">Import</property>
|
||||||
|
<signal name="clicked" handler="on_import" swapped="no"/>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage" id="import_button_image">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="stock">gtk-revert-to-saved</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCheckButton" id="info_check_button">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="draw_indicator">False</property>
|
||||||
|
<signal name="toggled" handler="on_info_button_toggled" swapped="no"/>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage" id="info_check_button_image">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="stock">gtk-dialog-info</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="pack_type">end</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox" id="main_box">
|
||||||
|
<property name="width_request">480</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="margin_left">1</property>
|
||||||
|
<property name="margin_right">1</property>
|
||||||
|
<property name="margin_bottom">1</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkPaned" id="main_paned">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="wide_handle">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox" id="bouquets_box">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="margin_top">2</property>
|
||||||
|
<property name="margin_bottom">2</property>
|
||||||
|
<property name="label" translatable="yes">Bouquets</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkScrolledWindow" id="bouquets_screlled_window">
|
||||||
|
<property name="width_request">200</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="shadow_type">in</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkTreeView" id="main_view">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="model">main_list_store</property>
|
||||||
|
<property name="headers_clickable">False</property>
|
||||||
|
<property name="search_column">0</property>
|
||||||
|
<signal name="button-press-event" handler="on_popup_menu" object="popup_menu" swapped="no"/>
|
||||||
|
<signal name="cursor-changed" handler="on_cursor_changed" swapped="no"/>
|
||||||
|
<signal name="key-press-event" handler="on_key_press" swapped="no"/>
|
||||||
|
<signal name="select-all" handler="on_select_all" swapped="no"/>
|
||||||
|
<child internal-child="selection">
|
||||||
|
<object class="GtkTreeSelection">
|
||||||
|
<property name="mode">multiple</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkTreeViewColumn" id="bouquet_name_column">
|
||||||
|
<property name="title" translatable="yes">Name</property>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="alignment">0.5</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCellRendererText" id="bq_name_renderer">
|
||||||
|
<property name="xalign">0.019999999552965164</property>
|
||||||
|
</object>
|
||||||
|
<attributes>
|
||||||
|
<attribute name="text">0</attribute>
|
||||||
|
</attributes>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkTreeViewColumn" id="bouquet_type_column">
|
||||||
|
<property name="title" translatable="yes">Type</property>
|
||||||
|
<property name="alignment">0.5</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCellRendererText" id="bq_type_renderer">
|
||||||
|
<property name="xalign">0.50999999046325684</property>
|
||||||
|
</object>
|
||||||
|
<attributes>
|
||||||
|
<attribute name="text">1</attribute>
|
||||||
|
</attributes>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkTreeViewColumn" id="bouquet_selected_column">
|
||||||
|
<property name="title" translatable="yes">Selected</property>
|
||||||
|
<property name="alignment">0.5</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCellRendererToggle" id="bq_selected_renderer">
|
||||||
|
<property name="xalign">0.50999999046325684</property>
|
||||||
|
<signal name="toggled" handler="on_selected_toggled" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<attributes>
|
||||||
|
<attribute name="active">2</attribute>
|
||||||
|
</attributes>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="resize">True</property>
|
||||||
|
<property name="shrink">True</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox" id="services_box">
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="margin_top">2</property>
|
||||||
|
<property name="margin_bottom">2</property>
|
||||||
|
<property name="label" translatable="yes">Bouquet details</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkScrolledWindow" id="services_view_scrolled_window">
|
||||||
|
<property name="width_request">150</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="shadow_type">in</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkTreeView" id="services_view">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="model">services_list_store</property>
|
||||||
|
<property name="headers_clickable">False</property>
|
||||||
|
<property name="search_column">0</property>
|
||||||
|
<child internal-child="selection">
|
||||||
|
<object class="GtkTreeSelection"/>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkTreeViewColumn" id="service_name_column">
|
||||||
|
<property name="title" translatable="yes">Service</property>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="alignment">0.5</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCellRendererText" id="info_name_renderer">
|
||||||
|
<property name="xalign">0.019999999552965164</property>
|
||||||
|
</object>
|
||||||
|
<attributes>
|
||||||
|
<attribute name="text">0</attribute>
|
||||||
|
</attributes>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkTreeViewColumn" id="service_type_column">
|
||||||
|
<property name="title" translatable="yes">Type</property>
|
||||||
|
<property name="alignment">0.5</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCellRendererText" id="info_type_renderer">
|
||||||
|
<property name="xalign">0.50999999046325684</property>
|
||||||
|
</object>
|
||||||
|
<attributes>
|
||||||
|
<attribute name="text">1</attribute>
|
||||||
|
</attributes>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="resize">True</property>
|
||||||
|
<property name="shrink">True</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkInfoBar" id="info_bar">
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="show_close_button">True</property>
|
||||||
|
<signal name="response" handler="on_info_bar_close" swapped="no"/>
|
||||||
|
<child internal-child="action_area">
|
||||||
|
<object class="GtkButtonBox">
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="spacing">6</property>
|
||||||
|
<property name="layout_style">end</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child internal-child="content_area">
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="spacing">16</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="message_label">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">message</property>
|
||||||
|
<property name="wrap">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">False</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</interface>
|
||||||
221
app/ui/imports.py
Normal file
221
app/ui/imports.py
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
from contextlib import suppress
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from app.commons import run_idle
|
||||||
|
from app.eparser import get_bouquets, get_services
|
||||||
|
from app.eparser.ecommons import BqType, BqServiceType, Bouquet
|
||||||
|
from app.eparser.enigma.bouquets import get_bouquet
|
||||||
|
from app.eparser.neutrino.bouquets import parse_webtv, parse_bouquets as get_neutrino_bouquets
|
||||||
|
from app.properties import Profile
|
||||||
|
from app.ui.dialogs import show_dialog, DialogType, get_chooser_dialog, get_message
|
||||||
|
from app.ui.main_helper import on_popup_menu
|
||||||
|
from .uicommons import Gtk, UI_RESOURCES_PATH, KeyboardKey, Column
|
||||||
|
|
||||||
|
|
||||||
|
def import_bouquet(transient, profile, model, path, options, services, appender):
|
||||||
|
""" Import of single bouquet """
|
||||||
|
itr = model.get_iter(path)
|
||||||
|
bq_type = BqType(model.get(itr, Column.BQ_TYPE)[0])
|
||||||
|
pattern, f_pattern = None, None
|
||||||
|
|
||||||
|
if profile is Profile.ENIGMA_2:
|
||||||
|
pattern = ".{}".format(bq_type.value)
|
||||||
|
f_pattern = "userbouquet.*{}".format(pattern)
|
||||||
|
elif profile is Profile.NEUTRINO_MP:
|
||||||
|
pattern = "webtv.xml" if bq_type is BqType.WEBTV else "bouquets.xml"
|
||||||
|
f_pattern = "bouquets.xml"
|
||||||
|
if bq_type is BqType.TV:
|
||||||
|
f_pattern = "ubouquets.xml"
|
||||||
|
elif bq_type is BqType.WEBTV:
|
||||||
|
f_pattern = "webtv.xml"
|
||||||
|
|
||||||
|
file_path = get_chooser_dialog(transient, options, f_pattern, "bouquet files")
|
||||||
|
if file_path == Gtk.ResponseType.CANCEL:
|
||||||
|
return
|
||||||
|
|
||||||
|
if not str(file_path).endswith(pattern):
|
||||||
|
show_dialog(DialogType.ERROR, transient, text="No bouquet file is selected!")
|
||||||
|
return
|
||||||
|
|
||||||
|
if profile is Profile.ENIGMA_2:
|
||||||
|
bq = get_enigma2_bouquet(file_path)
|
||||||
|
imported = list(filter(lambda x: x.data in services or x.type is BqServiceType.IPTV, bq.services))
|
||||||
|
|
||||||
|
if len(imported) == 0:
|
||||||
|
show_dialog(DialogType.ERROR, transient, text="The main list does not contain services for this bouquet!")
|
||||||
|
return
|
||||||
|
|
||||||
|
if model.iter_n_children(itr):
|
||||||
|
appender(bq, itr)
|
||||||
|
else:
|
||||||
|
p_itr = model.iter_parent(itr)
|
||||||
|
appender(bq, p_itr) if p_itr else appender(bq, itr)
|
||||||
|
elif profile is Profile.NEUTRINO_MP:
|
||||||
|
if bq_type is BqType.WEBTV:
|
||||||
|
bqs = parse_webtv(file_path, "WEBTV", bq_type.value)
|
||||||
|
else:
|
||||||
|
bqs = get_neutrino_bouquets(file_path, "", bq_type.value)
|
||||||
|
file_path = "{}/".format(Path(file_path).parent)
|
||||||
|
ImportDialog(transient, file_path, profile, services.keys(), lambda b, s: appender(b), (bqs,)).show()
|
||||||
|
|
||||||
|
|
||||||
|
def get_enigma2_bouquet(path):
|
||||||
|
path, sep, f_name = path.rpartition("userbouquet.")
|
||||||
|
name, sep, suf = f_name.rpartition(".")
|
||||||
|
bq = get_bouquet(path, name, suf)
|
||||||
|
bouquet = Bouquet(name=bq[0], type=BqType(suf).value, services=bq[1], locked=None, hidden=None)
|
||||||
|
return bouquet
|
||||||
|
|
||||||
|
|
||||||
|
class ImportDialog:
|
||||||
|
def __init__(self, transient, path, profile, service_ids, appender, bouquets=None):
|
||||||
|
handlers = {"on_import": self.on_import,
|
||||||
|
"on_cursor_changed": self.on_cursor_changed,
|
||||||
|
"on_info_button_toggled": self.on_info_button_toggled,
|
||||||
|
"on_selected_toggled": self.on_selected_toggled,
|
||||||
|
"on_info_bar_close": self.on_info_bar_close,
|
||||||
|
"on_select_all": self.on_select_all,
|
||||||
|
"on_unselect_all": self.on_unselect_all,
|
||||||
|
"on_popup_menu": on_popup_menu,
|
||||||
|
"on_key_press": self.on_key_press}
|
||||||
|
|
||||||
|
builder = Gtk.Builder()
|
||||||
|
builder.set_translation_domain("demon-editor")
|
||||||
|
builder.add_from_file(UI_RESOURCES_PATH + "import_dialog.glade")
|
||||||
|
builder.connect_signals(handlers)
|
||||||
|
|
||||||
|
self._bq_services = {}
|
||||||
|
self._services = {}
|
||||||
|
self._service_ids = service_ids
|
||||||
|
self._append = appender
|
||||||
|
self._profile = profile
|
||||||
|
self._bouquets = bouquets
|
||||||
|
|
||||||
|
self._dialog_window = builder.get_object("dialog_window")
|
||||||
|
self._dialog_window.set_transient_for(transient)
|
||||||
|
self._main_model = builder.get_object("main_list_store")
|
||||||
|
self._main_view = builder.get_object("main_view")
|
||||||
|
self._services_view = builder.get_object("services_view")
|
||||||
|
self._services_model = builder.get_object("services_list_store")
|
||||||
|
self._services_box = builder.get_object("services_box")
|
||||||
|
self._info_check_button = builder.get_object("info_check_button")
|
||||||
|
self._info_bar = builder.get_object("info_bar")
|
||||||
|
self._message_label = builder.get_object("message_label")
|
||||||
|
|
||||||
|
self.init_data(path)
|
||||||
|
|
||||||
|
def show(self):
|
||||||
|
self._dialog_window.show()
|
||||||
|
|
||||||
|
@run_idle
|
||||||
|
def init_data(self, path):
|
||||||
|
self._main_model.clear()
|
||||||
|
self._services_model.clear()
|
||||||
|
try:
|
||||||
|
if not self._bouquets:
|
||||||
|
self._bouquets = get_bouquets(path, self._profile)
|
||||||
|
for bqs in self._bouquets:
|
||||||
|
for bq in bqs.bouquets:
|
||||||
|
self._main_model.append((bq.name, bq.type, True))
|
||||||
|
self._bq_services[(bq.name, bq.type)] = bq.services
|
||||||
|
# Note! Getting default format ver. 4
|
||||||
|
services = get_services(path, self._profile, 4 if self._profile is Profile.ENIGMA_2 else 0)
|
||||||
|
for srv in services:
|
||||||
|
self._services[srv.fav_id] = srv
|
||||||
|
except FileNotFoundError as e:
|
||||||
|
self.show_info_message(str(e), Gtk.MessageType.ERROR)
|
||||||
|
|
||||||
|
def on_import(self, item):
|
||||||
|
if not any(r[-1] for r in self._main_model):
|
||||||
|
self.show_info_message(get_message("No selected item!"), Gtk.MessageType.ERROR)
|
||||||
|
return
|
||||||
|
|
||||||
|
if not self._bouquets or show_dialog(DialogType.QUESTION, self._dialog_window) == Gtk.ResponseType.CANCEL:
|
||||||
|
return
|
||||||
|
|
||||||
|
services = set()
|
||||||
|
to_delete = set()
|
||||||
|
|
||||||
|
for row in self._main_model:
|
||||||
|
bq = (row[0], row[1])
|
||||||
|
if row[-1]:
|
||||||
|
for bq_srv in self._bq_services.get(bq, []):
|
||||||
|
srv = self._services.get(bq_srv.data, None)
|
||||||
|
if srv:
|
||||||
|
services.add(srv)
|
||||||
|
else:
|
||||||
|
to_delete.add(bq)
|
||||||
|
|
||||||
|
bqs_to_delete = []
|
||||||
|
for bqs in self._bouquets:
|
||||||
|
for bq in bqs.bouquets:
|
||||||
|
if (bq.name, bq.type) in to_delete:
|
||||||
|
bqs_to_delete.append(bq)
|
||||||
|
|
||||||
|
for bqs in self._bouquets:
|
||||||
|
bq = bqs.bouquets
|
||||||
|
for b in bqs_to_delete:
|
||||||
|
with suppress(ValueError):
|
||||||
|
bq.remove(b)
|
||||||
|
|
||||||
|
self._append(self._bouquets, list(filter(lambda s: s.fav_id not in self._service_ids, services)))
|
||||||
|
self._dialog_window.destroy()
|
||||||
|
|
||||||
|
@run_idle
|
||||||
|
def on_cursor_changed(self, view):
|
||||||
|
if not self._info_check_button.get_active():
|
||||||
|
return
|
||||||
|
|
||||||
|
self._services_model.clear()
|
||||||
|
model, paths = view.get_selection().get_selected_rows()
|
||||||
|
if not paths:
|
||||||
|
return
|
||||||
|
|
||||||
|
bq_services = self._bq_services.get(model.get(model.get_iter(paths[0]), 0, 1))
|
||||||
|
for bq_srv in bq_services:
|
||||||
|
srv = self._services.get(bq_srv.data, None)
|
||||||
|
if srv:
|
||||||
|
self._services_model.append((srv.service, srv.service_type))
|
||||||
|
|
||||||
|
def on_info_button_toggled(self, button):
|
||||||
|
active = button.get_active()
|
||||||
|
self._services_box.set_visible(active)
|
||||||
|
|
||||||
|
def on_selected_toggled(self, toggle, path):
|
||||||
|
self._main_model.set_value(self._main_model.get_iter(path), 2, not toggle.get_active())
|
||||||
|
|
||||||
|
@run_idle
|
||||||
|
def show_info_message(self, text, message_type):
|
||||||
|
self._info_bar.set_visible(True)
|
||||||
|
self._info_bar.set_message_type(message_type)
|
||||||
|
self._message_label.set_text(text)
|
||||||
|
|
||||||
|
@run_idle
|
||||||
|
def on_info_bar_close(self, bar=None, resp=None):
|
||||||
|
self._info_bar.set_visible(False)
|
||||||
|
|
||||||
|
def on_select_all(self, view):
|
||||||
|
self.update_selection(view, True)
|
||||||
|
|
||||||
|
def on_unselect_all(self, view):
|
||||||
|
self.update_selection(view, False)
|
||||||
|
|
||||||
|
def update_selection(self, view, select):
|
||||||
|
view.get_model().foreach(lambda mod, path, itr: mod.set_value(itr, 2, select))
|
||||||
|
|
||||||
|
def on_key_press(self, view, event):
|
||||||
|
""" Handling keystrokes """
|
||||||
|
key_code = event.hardware_keycode
|
||||||
|
if not KeyboardKey.value_exist(key_code):
|
||||||
|
return
|
||||||
|
key = KeyboardKey(key_code)
|
||||||
|
|
||||||
|
if key is KeyboardKey.SPACE:
|
||||||
|
path, column = view.get_cursor()
|
||||||
|
itr = self._main_model.get_iter(path)
|
||||||
|
selected = self._main_model.get_value(itr, 2)
|
||||||
|
self._main_model.set_value(itr, 2, not selected)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
pass
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2018 Dmitriy Yefremov
|
Copyright (c) 2018-2019 Dmitriy Yefremov
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
@@ -31,7 +31,7 @@ Author: Dmitriy Yefremov
|
|||||||
<!-- interface-license-type mit -->
|
<!-- interface-license-type mit -->
|
||||||
<!-- interface-name DemonEditor -->
|
<!-- interface-name DemonEditor -->
|
||||||
<!-- interface-description Enigma2 channel and satellites list editor for GNU/Linux. -->
|
<!-- interface-description Enigma2 channel and satellites list editor for GNU/Linux. -->
|
||||||
<!-- interface-copyright 2018 Dmitriy Yefremov -->
|
<!-- interface-copyright 2018-2019 Dmitriy Yefremov -->
|
||||||
<!-- interface-authors Dmitriy Yefremov -->
|
<!-- interface-authors Dmitriy Yefremov -->
|
||||||
<object class="GtkDialog" id="search_unavailable_streams_dialog">
|
<object class="GtkDialog" id="search_unavailable_streams_dialog">
|
||||||
<property name="use-header-bar">1</property>
|
<property name="use-header-bar">1</property>
|
||||||
@@ -192,6 +192,12 @@ Author: Dmitriy Yefremov
|
|||||||
<row>
|
<row>
|
||||||
<col id="0">non-TS</col>
|
<col id="0">non-TS</col>
|
||||||
</row>
|
</row>
|
||||||
|
<row>
|
||||||
|
<col id="0">none-REC1</col>
|
||||||
|
</row>
|
||||||
|
<row>
|
||||||
|
<col id="0">none-REC2</col>
|
||||||
|
</row>
|
||||||
</data>
|
</data>
|
||||||
</object>
|
</object>
|
||||||
<object class="GtkDialog" id="iptv_dialog">
|
<object class="GtkDialog" id="iptv_dialog">
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ from app.commons import run_idle, run_task
|
|||||||
from app.eparser.ecommons import BqServiceType, Service
|
from app.eparser.ecommons import BqServiceType, Service
|
||||||
from app.eparser.iptv import NEUTRINO_FAV_ID_FORMAT, StreamType, ENIGMA2_FAV_ID_FORMAT
|
from app.eparser.iptv import NEUTRINO_FAV_ID_FORMAT, StreamType, ENIGMA2_FAV_ID_FORMAT
|
||||||
from app.properties import Profile
|
from app.properties import Profile
|
||||||
from .uicommons import Gtk, Gdk, TEXT_DOMAIN, UI_RESOURCES_PATH, IPTV_ICON
|
from .uicommons import Gtk, Gdk, TEXT_DOMAIN, UI_RESOURCES_PATH, IPTV_ICON, Column
|
||||||
from .dialogs import Action, show_dialog, DialogType
|
from .dialogs import Action, show_dialog, DialogType
|
||||||
from .main_helper import get_base_model, get_iptv_url
|
from .main_helper import get_base_model, get_iptv_url
|
||||||
|
|
||||||
@@ -25,6 +25,17 @@ def is_data_correct(elems):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def get_stream_type(box):
|
||||||
|
active = box.get_active()
|
||||||
|
if active == 0:
|
||||||
|
return StreamType.DVB_TS.value
|
||||||
|
elif active == 1:
|
||||||
|
return StreamType.NONE_TS.value
|
||||||
|
elif active == 2:
|
||||||
|
return StreamType.NONE_REC_1.value
|
||||||
|
return StreamType.NONE_REC_2.value
|
||||||
|
|
||||||
|
|
||||||
class IptvDialog:
|
class IptvDialog:
|
||||||
|
|
||||||
def __init__(self, transient, view, services, bouquet, profile=Profile.ENIGMA_2, action=Action.ADD):
|
def __init__(self, transient, view, services, bouquet, profile=Profile.ENIGMA_2, action=Action.ADD):
|
||||||
@@ -116,7 +127,21 @@ class IptvDialog:
|
|||||||
data = data.split(":")
|
data = data.split(":")
|
||||||
if len(data) < 11:
|
if len(data) < 11:
|
||||||
return
|
return
|
||||||
self._stream_type_combobox.set_active(0 if StreamType(data[0].strip()) is StreamType.DVB_TS else 1)
|
|
||||||
|
s_type = data[0].strip()
|
||||||
|
try:
|
||||||
|
stream_type = StreamType(s_type)
|
||||||
|
if stream_type is StreamType.DVB_TS:
|
||||||
|
self._stream_type_combobox.set_active(0)
|
||||||
|
elif stream_type is StreamType.NONE_TS:
|
||||||
|
self._stream_type_combobox.set_active(1)
|
||||||
|
elif stream_type is StreamType.NONE_REC_1:
|
||||||
|
self._stream_type_combobox.set_active(2)
|
||||||
|
elif stream_type is StreamType.NONE_REC_2:
|
||||||
|
self._stream_type_combobox.set_active(3)
|
||||||
|
except ValueError:
|
||||||
|
show_dialog(DialogType.ERROR, "Unknown stream type {}".format(s_type))
|
||||||
|
|
||||||
self._srv_type_entry.set_text(data[2])
|
self._srv_type_entry.set_text(data[2])
|
||||||
self._sid_entry.set_text(str(int(data[3], 16)))
|
self._sid_entry.set_text(str(int(data[3], 16)))
|
||||||
self._tr_id_entry.set_text(str(int(data[4], 16)))
|
self._tr_id_entry.set_text(str(int(data[4], 16)))
|
||||||
@@ -140,7 +165,7 @@ class IptvDialog:
|
|||||||
int(self._namespace_entry.get_text())))
|
int(self._namespace_entry.get_text())))
|
||||||
|
|
||||||
def get_type(self):
|
def get_type(self):
|
||||||
return 1 if self._stream_type_combobox.get_active() == 0 else 4097
|
return get_stream_type(self._stream_type_combobox)
|
||||||
|
|
||||||
def on_entry_changed(self, entry):
|
def on_entry_changed(self, entry):
|
||||||
if _PATTERN.search(entry.get_text()):
|
if _PATTERN.search(entry.get_text()):
|
||||||
@@ -183,11 +208,11 @@ class IptvDialog:
|
|||||||
old_srv = self._services.pop(self._current_srv[7])
|
old_srv = self._services.pop(self._current_srv[7])
|
||||||
self._services[fav_id] = old_srv._replace(service=name, fav_id=fav_id)
|
self._services[fav_id] = old_srv._replace(service=name, fav_id=fav_id)
|
||||||
self._bouquet[self._paths[0][0]] = fav_id
|
self._bouquet[self._paths[0][0]] = fav_id
|
||||||
self._model.set(self._model.get_iter(self._paths), {2: name, 7: fav_id})
|
self._model.set(self._model.get_iter(self._paths), {Column.FAV_SERVICE: name, Column.FAV_ID: fav_id})
|
||||||
else:
|
else:
|
||||||
aggr = [None] * 10
|
aggr = [None] * 10
|
||||||
s_type = BqServiceType.IPTV.name
|
s_type = BqServiceType.IPTV.name
|
||||||
srv = (None, None, name, None, None, s_type, None, fav_id, None)
|
srv = (None, None, name, None, None, s_type, None, fav_id, *aggr[0:3])
|
||||||
itr = self._model.insert_after(self._model.get_iter(self._paths[0]),
|
itr = self._model.insert_after(self._model.get_iter(self._paths[0]),
|
||||||
srv) if self._paths else self._model.insert(0, srv)
|
srv) if self._paths else self._model.insert(0, srv)
|
||||||
self._model.set_value(itr, 1, IPTV_ICON)
|
self._model.set_value(itr, 1, IPTV_ICON)
|
||||||
@@ -281,7 +306,7 @@ class SearchUnavailableDialog:
|
|||||||
|
|
||||||
class IptvListConfigurationDialog:
|
class IptvListConfigurationDialog:
|
||||||
|
|
||||||
def __init__(self, transient, services, iptv_rows, bouquet, profile):
|
def __init__(self, transient, services, iptv_rows, bouquet, fav_model, profile):
|
||||||
handlers = {"on_apply": self.on_apply,
|
handlers = {"on_apply": self.on_apply,
|
||||||
"on_response": self.on_response,
|
"on_response": self.on_response,
|
||||||
"on_stream_type_default_togged": self.on_stream_type_default_togged,
|
"on_stream_type_default_togged": self.on_stream_type_default_togged,
|
||||||
@@ -304,6 +329,7 @@ class IptvListConfigurationDialog:
|
|||||||
self._rows = iptv_rows
|
self._rows = iptv_rows
|
||||||
self._services = services
|
self._services = services
|
||||||
self._bouquet = bouquet
|
self._bouquet = bouquet
|
||||||
|
self._fav_model = fav_model
|
||||||
self._profile = profile
|
self._profile = profile
|
||||||
|
|
||||||
self._dialog = builder.get_object("iptv_list_configuration_dialog")
|
self._dialog = builder.get_object("iptv_list_configuration_dialog")
|
||||||
@@ -392,9 +418,6 @@ class IptvListConfigurationDialog:
|
|||||||
show_dialog(DialogType.ERROR, self._dialog, "Error. Verify the data!")
|
show_dialog(DialogType.ERROR, self._dialog, "Error. Verify the data!")
|
||||||
return
|
return
|
||||||
|
|
||||||
if len(self._bouquet) != len(self._rows):
|
|
||||||
return
|
|
||||||
|
|
||||||
if self._profile is Profile.ENIGMA_2:
|
if self._profile is Profile.ENIGMA_2:
|
||||||
reset = self._reset_to_default_switch.get_active()
|
reset = self._reset_to_default_switch.get_active()
|
||||||
type_default = self._type_check_button.get_active()
|
type_default = self._type_check_button.get_active()
|
||||||
@@ -403,35 +426,38 @@ class IptvListConfigurationDialog:
|
|||||||
nid_default = self._nid_check_button.get_active()
|
nid_default = self._nid_check_button.get_active()
|
||||||
namespace_default = self._namespace_check_button.get_active()
|
namespace_default = self._namespace_check_button.get_active()
|
||||||
|
|
||||||
|
stream_type = StreamType.NONE_TS.value if reset else get_stream_type(self._stream_type_combobox)
|
||||||
|
srv_type = "1" if type_default else self._list_srv_type_entry.get_text()
|
||||||
|
tid = "0" if tid_default else "{:X}".format(int(self._list_tid_entry.get_text()))
|
||||||
|
nid = "0" if nid_default else "{:X}".format(int(self._list_nid_entry.get_text()))
|
||||||
|
namespace = "0" if namespace_default else "{:X}".format(int(self._list_namespace_entry.get_text()))
|
||||||
|
|
||||||
for index, row in enumerate(self._rows):
|
for index, row in enumerate(self._rows):
|
||||||
fav_id = row[7]
|
fav_id = row[Column.FAV_ID]
|
||||||
data, sep, desc = fav_id.partition("http")
|
data, sep, desc = fav_id.partition("http")
|
||||||
data = data.split(":")
|
data = data.split(":")
|
||||||
|
|
||||||
if reset:
|
if reset:
|
||||||
data[0] = " 4097"
|
|
||||||
data[2], data[3], data[4], data[5], data[6] = "10000"
|
data[2], data[3], data[4], data[5], data[6] = "10000"
|
||||||
else:
|
else:
|
||||||
data[0] = " 4097" if self._stream_type_combobox.get_active() == 1 else "1"
|
data[0], data[2], data[4], data[5], data[6] = stream_type, srv_type, tid, nid, namespace
|
||||||
data[2] = "1" if type_default else self._list_srv_type_entry.get_text()
|
|
||||||
data[3] = "{:X}".format(index) if sid_auto else "0"
|
data[3] = "{:X}".format(index) if sid_auto else "0"
|
||||||
data[4] = "0" if tid_default else "{:X}".format(int(self._list_tid_entry.get_text()))
|
|
||||||
data[5] = "0" if nid_default else "{:X}".format(int(self._list_nid_entry.get_text()))
|
|
||||||
data[6] = "0" if namespace_default else "{:X}".format(int(self._list_namespace_entry.get_text()))
|
|
||||||
|
|
||||||
data = ":".join(data)
|
data = ":".join(data)
|
||||||
new_fav_id = "{}{}{}".format(data, sep, desc)
|
new_fav_id = "{}{}{}".format(data, sep, desc)
|
||||||
row[7] = new_fav_id
|
row[Column.FAV_ID] = new_fav_id
|
||||||
self._bouquet[index] = new_fav_id
|
|
||||||
srv = self._services.pop(fav_id, None)
|
srv = self._services.pop(fav_id, None)
|
||||||
self._services[new_fav_id] = srv._replace(fav_id=new_fav_id)
|
self._services[new_fav_id] = srv._replace(fav_id=new_fav_id)
|
||||||
|
|
||||||
|
self._bouquet.clear()
|
||||||
|
list(map(lambda r: self._bouquet.append(r[Column.FAV_ID]), self._fav_model))
|
||||||
|
|
||||||
self._info_bar.set_visible(True)
|
self._info_bar.set_visible(True)
|
||||||
|
|
||||||
@run_idle
|
@run_idle
|
||||||
def update_reference(self):
|
def update_reference(self):
|
||||||
if is_data_correct(self._digit_elems):
|
if is_data_correct(self._digit_elems):
|
||||||
stream_type = "4097" if self._stream_type_combobox.get_active() == 1 else "1"
|
stream_type = get_stream_type(self._stream_type_combobox)
|
||||||
self._reference_label.set_text(
|
self._reference_label.set_text(
|
||||||
_ENIGMA2_REFERENCE.format(stream_type, *[int(elem.get_text()) for elem in self._digit_elems]))
|
_ENIGMA2_REFERENCE.format(stream_type, *[int(elem.get_text()) for elem in self._digit_elems]))
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -7,7 +7,8 @@ from functools import lru_cache
|
|||||||
from gi.repository import GLib
|
from gi.repository import GLib
|
||||||
|
|
||||||
from app.commons import run_idle, log, run_task, run_with_delay
|
from app.commons import run_idle, log, run_task, run_with_delay
|
||||||
from app.connections import http_request, HttpRequestType
|
from app.connections import http_request, HttpRequestType, download_data, DownloadType, upload_data, test_http, \
|
||||||
|
TestException
|
||||||
from app.eparser import get_blacklist, write_blacklist, parse_m3u
|
from app.eparser import get_blacklist, write_blacklist, parse_m3u
|
||||||
from app.eparser import get_services, get_bouquets, write_bouquets, write_services, Bouquets, Bouquet, Service
|
from app.eparser import get_services, get_bouquets, write_bouquets, write_services, Bouquets, Bouquet, Service
|
||||||
from app.eparser.ecommons import CAS, Flag
|
from app.eparser.ecommons import CAS, Flag
|
||||||
@@ -15,16 +16,18 @@ from app.eparser.enigma.bouquets import BqServiceType
|
|||||||
from app.eparser.neutrino.bouquets import BqType
|
from app.eparser.neutrino.bouquets import BqType
|
||||||
from app.properties import get_config, write_config, Profile
|
from app.properties import get_config, write_config, Profile
|
||||||
from app.tools.media import Player
|
from app.tools.media import Player
|
||||||
from app.ui.backup import BackupDialog, backup_data, clear_data_path
|
from .backup import BackupDialog, backup_data, clear_data_path
|
||||||
|
from .imports import ImportDialog, import_bouquet
|
||||||
from .download_dialog import DownloadDialog
|
from .download_dialog import DownloadDialog
|
||||||
from .iptv import IptvDialog, SearchUnavailableDialog, IptvListConfigurationDialog
|
from .iptv import IptvDialog, SearchUnavailableDialog, IptvListConfigurationDialog
|
||||||
from .search import SearchProvider
|
from .search import SearchProvider
|
||||||
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, LOCKED_ICON, HIDE_ICON, IPTV_ICON, MOVE_KEYS, KeyboardKey, Column, \
|
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, LOCKED_ICON, HIDE_ICON, IPTV_ICON, MOVE_KEYS, KeyboardKey, Column, \
|
||||||
EXTRA_COLOR, NEW_COLOR
|
EXTRA_COLOR, NEW_COLOR, FavClickMode
|
||||||
from .dialogs import show_dialog, DialogType, get_chooser_dialog, WaitDialog, get_message
|
from .dialogs import show_dialog, DialogType, get_chooser_dialog, WaitDialog, get_message
|
||||||
from .main_helper import insert_marker, move_items, rename, ViewTarget, set_flags, locate_in_services, \
|
from .main_helper import insert_marker, move_items, rename, ViewTarget, set_flags, locate_in_services, \
|
||||||
scroll_to, get_base_model, update_picons_data, copy_picon_reference, assign_picon, remove_picon, \
|
scroll_to, get_base_model, update_picons_data, copy_picon_reference, assign_picon, remove_picon, \
|
||||||
is_only_one_item_selected, gen_bouquets, BqGenType, get_iptv_url, append_picons, get_selection, get_model_data
|
is_only_one_item_selected, gen_bouquets, BqGenType, get_iptv_url, append_picons, get_selection, get_model_data, \
|
||||||
|
remove_all_unused_picons
|
||||||
from .picons_downloader import PiconsDialog
|
from .picons_downloader import PiconsDialog
|
||||||
from .satellites_dialog import show_satellites_dialog
|
from .satellites_dialog import show_satellites_dialog
|
||||||
from .settings_dialog import show_settings_dialog
|
from .settings_dialog import show_settings_dialog
|
||||||
@@ -40,22 +43,31 @@ class Application(Gtk.Application):
|
|||||||
|
|
||||||
# Dynamically active elements depending on the selected view
|
# Dynamically active elements depending on the selected view
|
||||||
_SERVICE_ELEMENTS = ("services_popup_menu",)
|
_SERVICE_ELEMENTS = ("services_popup_menu",)
|
||||||
|
|
||||||
_FAV_ELEMENTS = ("fav_cut_popup_item", "fav_paste_popup_item", "fav_locate_popup_item", "fav_iptv_popup_item",
|
_FAV_ELEMENTS = ("fav_cut_popup_item", "fav_paste_popup_item", "fav_locate_popup_item", "fav_iptv_popup_item",
|
||||||
"fav_insert_marker_popup_item", "fav_edit_sub_menu_popup_item", "fav_edit_popup_item",
|
"fav_insert_marker_popup_item", "fav_edit_sub_menu_popup_item", "fav_edit_popup_item",
|
||||||
"fav_picon_popup_item", "fav_copy_popup_item")
|
"fav_picon_popup_item", "fav_copy_popup_item")
|
||||||
|
|
||||||
_BOUQUET_ELEMENTS = ("bouquets_new_popup_item", "bouquets_edit_popup_item", "bouquets_cut_popup_item",
|
_BOUQUET_ELEMENTS = ("bouquets_new_popup_item", "bouquets_edit_popup_item", "bouquets_cut_popup_item",
|
||||||
"bouquets_copy_popup_item", "bouquets_paste_popup_item", "edit_header_button",
|
"bouquets_copy_popup_item", "bouquets_paste_popup_item", "edit_header_button",
|
||||||
"new_header_button")
|
"new_header_button", "bouquet_import_popup_item")
|
||||||
_COMMONS_ELEMENTS = ("edit_header_button", "bouquets_remove_popup_item", "fav_remove_popup_item")
|
|
||||||
|
_COMMONS_ELEMENTS = ("edit_header_button", "bouquets_remove_popup_item",
|
||||||
|
"fav_remove_popup_item", "import_bq_menu_button")
|
||||||
|
|
||||||
_FAV_ENIGMA_ELEMENTS = ("fav_insert_marker_popup_item",)
|
_FAV_ENIGMA_ELEMENTS = ("fav_insert_marker_popup_item",)
|
||||||
|
|
||||||
_FAV_IPTV_ELEMENTS = ("fav_iptv_popup_item",)
|
_FAV_IPTV_ELEMENTS = ("fav_iptv_popup_item",)
|
||||||
|
|
||||||
_LOCK_HIDE_ELEMENTS = ("locked_tool_button", "hide_tool_button")
|
_LOCK_HIDE_ELEMENTS = ("locked_tool_button", "hide_tool_button")
|
||||||
|
|
||||||
_DYNAMIC_ELEMENTS = ("services_popup_menu", "new_header_button", "edit_header_button", "locked_tool_button",
|
_DYNAMIC_ELEMENTS = ("services_popup_menu", "new_header_button", "edit_header_button", "locked_tool_button",
|
||||||
"fav_cut_popup_item", "fav_paste_popup_item", "bouquets_new_popup_item", "hide_tool_button",
|
"fav_cut_popup_item", "fav_paste_popup_item", "bouquets_new_popup_item", "hide_tool_button",
|
||||||
"bouquets_remove_popup_item", "fav_remove_popup_item", "bouquets_edit_popup_item",
|
"bouquets_remove_popup_item", "fav_remove_popup_item", "bouquets_edit_popup_item",
|
||||||
"fav_insert_marker_popup_item", "fav_edit_popup_item", "fav_edit_sub_menu_popup_item",
|
"fav_insert_marker_popup_item", "fav_edit_popup_item", "fav_edit_sub_menu_popup_item",
|
||||||
"fav_locate_popup_item", "fav_picon_popup_item", "fav_iptv_popup_item", "fav_copy_popup_item",
|
"fav_locate_popup_item", "fav_picon_popup_item", "fav_iptv_popup_item", "fav_copy_popup_item",
|
||||||
"bouquets_cut_popup_item", "bouquets_copy_popup_item", "bouquets_paste_popup_item")
|
"bouquets_cut_popup_item", "bouquets_copy_popup_item", "bouquets_paste_popup_item",
|
||||||
|
"bouquet_import_popup_item", "import_bq_menu_button")
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
@@ -101,6 +113,8 @@ class Application(Gtk.Application):
|
|||||||
"on_locked": self.on_locked,
|
"on_locked": self.on_locked,
|
||||||
"on_model_changed": self.on_model_changed,
|
"on_model_changed": self.on_model_changed,
|
||||||
"on_import_m3u": self.on_import_m3u,
|
"on_import_m3u": self.on_import_m3u,
|
||||||
|
"on_import_bouquet": self.on_import_bouquet,
|
||||||
|
"on_import_bouquets": self.on_import_bouquets,
|
||||||
"on_backup_tool_show": self.on_backup_tool_show,
|
"on_backup_tool_show": self.on_backup_tool_show,
|
||||||
"on_insert_marker": self.on_insert_marker,
|
"on_insert_marker": self.on_insert_marker,
|
||||||
"on_fav_press": self.on_fav_press,
|
"on_fav_press": self.on_fav_press,
|
||||||
@@ -110,6 +124,7 @@ class Application(Gtk.Application):
|
|||||||
"on_assign_picon": self.on_assign_picon,
|
"on_assign_picon": self.on_assign_picon,
|
||||||
"on_remove_picon": self.on_remove_picon,
|
"on_remove_picon": self.on_remove_picon,
|
||||||
"on_reference_picon": self.on_reference_picon,
|
"on_reference_picon": self.on_reference_picon,
|
||||||
|
"on_remove_unused_picons": self.on_remove_unused_picons,
|
||||||
"on_filter_toggled": self.on_filter_toggled,
|
"on_filter_toggled": self.on_filter_toggled,
|
||||||
"on_search_toggled": self.on_search_toggled,
|
"on_search_toggled": self.on_search_toggled,
|
||||||
"on_search_down": self.on_search_down,
|
"on_search_down": self.on_search_down,
|
||||||
@@ -161,6 +176,7 @@ class Application(Gtk.Application):
|
|||||||
self._drawing_area_xid = None
|
self._drawing_area_xid = None
|
||||||
# http api
|
# http api
|
||||||
self._http_api = None
|
self._http_api = None
|
||||||
|
self._fav_click_mode = None
|
||||||
self._monitor_signal = False
|
self._monitor_signal = False
|
||||||
# Colors
|
# Colors
|
||||||
self._use_colors = False
|
self._use_colors = False
|
||||||
@@ -338,6 +354,7 @@ class Application(Gtk.Application):
|
|||||||
move_items(key, self._fav_view if self._fav_view.is_focus() else self._bouquets_view)
|
move_items(key, self._fav_view if self._fav_view.is_focus() else self._bouquets_view)
|
||||||
|
|
||||||
# ***************** Copy - Cut - Paste *********************#
|
# ***************** Copy - Cut - Paste *********************#
|
||||||
|
|
||||||
def on_services_copy(self, view):
|
def on_services_copy(self, view):
|
||||||
self.on_copy(view, target=ViewTarget.FAV)
|
self.on_copy(view, target=ViewTarget.FAV)
|
||||||
|
|
||||||
@@ -408,7 +425,7 @@ class Application(Gtk.Application):
|
|||||||
for row in self._rows_buffer:
|
for row in self._rows_buffer:
|
||||||
dest_index += 1
|
dest_index += 1
|
||||||
model.insert(dest_index, row)
|
model.insert(dest_index, row)
|
||||||
fav_bouquet.insert(dest_index, row[7])
|
fav_bouquet.insert(dest_index, row[Column.FAV_ID])
|
||||||
|
|
||||||
if model.get_name() == self._FAV_LIST_NAME:
|
if model.get_name() == self._FAV_LIST_NAME:
|
||||||
self.update_fav_num_column(model)
|
self.update_fav_num_column(model)
|
||||||
@@ -418,7 +435,7 @@ class Application(Gtk.Application):
|
|||||||
def bouquet_paste(self, selection):
|
def bouquet_paste(self, selection):
|
||||||
model, paths = selection.get_selected_rows()
|
model, paths = selection.get_selected_rows()
|
||||||
if len(paths) > 1:
|
if len(paths) > 1:
|
||||||
show_dialog(DialogType.ERROR, self._main_window, "Please, select only one item!")
|
self.show_error_dialog("Please, select only one item!")
|
||||||
return
|
return
|
||||||
|
|
||||||
path = paths[0]
|
path = paths[0]
|
||||||
@@ -499,7 +516,7 @@ class Application(Gtk.Application):
|
|||||||
def delete_bouquets(self, itrs, model):
|
def delete_bouquets(self, itrs, model):
|
||||||
""" Deleting bouquets """
|
""" Deleting bouquets """
|
||||||
if len(itrs) == 1 and len(model.get_path(itrs[0])) < 2:
|
if len(itrs) == 1 and len(model.get_path(itrs[0])) < 2:
|
||||||
show_dialog(DialogType.ERROR, self._main_window, "This item is not allowed to be removed!")
|
self.show_error_dialog("This item is not allowed to be removed!")
|
||||||
return
|
return
|
||||||
|
|
||||||
for itr in itrs:
|
for itr in itrs:
|
||||||
@@ -705,7 +722,7 @@ class Application(Gtk.Application):
|
|||||||
model.remove(in_itr)
|
model.remove(in_itr)
|
||||||
self.update_fav_num_column(model)
|
self.update_fav_num_column(model)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
show_dialog(DialogType.ERROR, self._main_window, str(e))
|
self.show_error_dialog(str(e))
|
||||||
|
|
||||||
def on_view_press(self, view, event):
|
def on_view_press(self, view, event):
|
||||||
if event.get_event_type() == Gdk.EventType.BUTTON_PRESS and event.button == Gdk.BUTTON_PRIMARY:
|
if event.get_event_type() == Gdk.EventType.BUTTON_PRESS and event.button == Gdk.BUTTON_PRIMARY:
|
||||||
@@ -746,6 +763,47 @@ class Application(Gtk.Application):
|
|||||||
""" Shows satellites editor dialog """
|
""" Shows satellites editor dialog """
|
||||||
show_satellites_dialog(self._main_window, self._options.get(self._profile))
|
show_satellites_dialog(self._main_window, self._options.get(self._profile))
|
||||||
|
|
||||||
|
def on_download(self, item):
|
||||||
|
DownloadDialog(transient=self._main_window,
|
||||||
|
properties=self._options,
|
||||||
|
open_data_callback=self.open_data,
|
||||||
|
profile=Profile(self._profile)).show()
|
||||||
|
|
||||||
|
@run_task
|
||||||
|
def on_download_data(self):
|
||||||
|
try:
|
||||||
|
download_data(properties=self._options.get(self._profile),
|
||||||
|
download_type=DownloadType.ALL,
|
||||||
|
callback=lambda x: print(x, end=""))
|
||||||
|
except Exception as e:
|
||||||
|
self.show_error_dialog(str(e))
|
||||||
|
else:
|
||||||
|
GLib.idle_add(self.open_data)
|
||||||
|
|
||||||
|
@run_task
|
||||||
|
def on_upload_data(self, download_type):
|
||||||
|
try:
|
||||||
|
profile = Profile(self._profile)
|
||||||
|
opts = self._options.get(self._profile)
|
||||||
|
use_http = profile is Profile.ENIGMA_2
|
||||||
|
|
||||||
|
if profile is Profile.ENIGMA_2:
|
||||||
|
host, port = opts.get("host", "127.0.0.1"), opts.get("http_port")
|
||||||
|
user, password = opts.get("http_user", "root"), opts.get("http_password", "")
|
||||||
|
try:
|
||||||
|
test_http(host, port, user, password, skip_message=True)
|
||||||
|
except TestException:
|
||||||
|
use_http = False
|
||||||
|
|
||||||
|
upload_data(properties=opts,
|
||||||
|
download_type=download_type,
|
||||||
|
remove_unused=True,
|
||||||
|
profile=profile,
|
||||||
|
callback=lambda x: print(x, end=""),
|
||||||
|
use_http=use_http)
|
||||||
|
except Exception as e:
|
||||||
|
self.show_error_dialog(str(e))
|
||||||
|
|
||||||
@run_idle
|
@run_idle
|
||||||
def on_data_open(self, model):
|
def on_data_open(self, model):
|
||||||
response = show_dialog(DialogType.CHOOSER, self._main_window, options=self._options.get(self._profile))
|
response = show_dialog(DialogType.CHOOSER, self._main_window, options=self._options.get(self._profile))
|
||||||
@@ -770,31 +828,40 @@ class Application(Gtk.Application):
|
|||||||
update_picons_data(self._options.get(self._profile).get("picons_dir_path"), self._picons)
|
update_picons_data(self._options.get(self._profile).get("picons_dir_path"), self._picons)
|
||||||
except FileNotFoundError as e:
|
except FileNotFoundError as e:
|
||||||
self._wait_dialog.hide()
|
self._wait_dialog.hide()
|
||||||
show_dialog(DialogType.ERROR, self._main_window, getattr(e, "message", str(e)) + "\n\n" +
|
msg = get_message("Please, download files from receiver or setup your path for read data!")
|
||||||
get_message("Please, download files from receiver or setup your path for read data!"))
|
self.show_error_dialog(getattr(e, "message", str(e)) + "\n\n" + msg)
|
||||||
except SyntaxError as e:
|
except SyntaxError as e:
|
||||||
self._wait_dialog.hide()
|
self._wait_dialog.hide()
|
||||||
show_dialog(DialogType.ERROR, self._main_window, str(e))
|
self.show_error_dialog(str(e))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self._wait_dialog.hide()
|
self._wait_dialog.hide()
|
||||||
log("Append services error: " + str(e))
|
log("Append services error: " + str(e))
|
||||||
show_dialog(DialogType.ERROR, self._main_window, "Reading data error!\n" + str(e))
|
self.show_error_dialog(get_message("Reading data error!") + "\n" + str(e))
|
||||||
else:
|
else:
|
||||||
self.append_blacklist(black_list)
|
self.append_blacklist(black_list)
|
||||||
self.append_bouquets(bouquets)
|
self.append_bouquets(bouquets)
|
||||||
self.append_services(services)
|
self.append_services(services)
|
||||||
self.update_sat_positions()
|
self.update_sat_positions()
|
||||||
self.update_services_counts(len(self._services.values()))
|
|
||||||
|
|
||||||
def append_blacklist(self, black_list):
|
def append_blacklist(self, black_list):
|
||||||
if black_list:
|
if black_list:
|
||||||
self._blacklist.update(black_list)
|
self._blacklist.update(black_list)
|
||||||
|
|
||||||
def append_bouquets(self, bqs):
|
def append_bouquets(self, bqs):
|
||||||
for bouquet in bqs:
|
if len(self._bouquets_model):
|
||||||
parent = self._bouquets_model.append(None, [bouquet.name, None, None, bouquet.type])
|
self.add_to_bouquets(bqs)
|
||||||
for bq in bouquet.bouquets:
|
else:
|
||||||
self.append_bouquet(bq, parent)
|
for bouquet in bqs:
|
||||||
|
parent = self._bouquets_model.append(None, [bouquet.name, None, None, bouquet.type])
|
||||||
|
for bq in bouquet.bouquets:
|
||||||
|
self.append_bouquet(bq, parent)
|
||||||
|
|
||||||
|
def add_to_bouquets(self, bqs):
|
||||||
|
for bouquets in bqs:
|
||||||
|
for row in self._bouquets_model:
|
||||||
|
if row[Column.BQ_TYPE] == bouquets.type:
|
||||||
|
for bq in bouquets.bouquets:
|
||||||
|
self.append_bouquet(bq, row.iter)
|
||||||
|
|
||||||
def append_bouquet(self, bq, parent):
|
def append_bouquet(self, bq, parent):
|
||||||
name, bt_type, locked, hidden = bq.name, bq.type, bq.locked, bq.hidden
|
name, bt_type, locked, hidden = bq.name, bq.type, bq.locked, bq.hidden
|
||||||
@@ -829,6 +896,7 @@ class Application(Gtk.Application):
|
|||||||
for srv in services:
|
for srv in services:
|
||||||
# adding channels to dict with fav_id as keys
|
# adding channels to dict with fav_id as keys
|
||||||
self._services[srv.fav_id] = srv
|
self._services[srv.fav_id] = srv
|
||||||
|
self.update_services_counts(len(self._services.values()))
|
||||||
gen = self.append_services_data(services)
|
gen = self.append_services_data(services)
|
||||||
GLib.idle_add(lambda: next(gen, False), priority=GLib.PRIORITY_LOW)
|
GLib.idle_add(lambda: next(gen, False), priority=GLib.PRIORITY_LOW)
|
||||||
|
|
||||||
@@ -844,7 +912,7 @@ class Application(Gtk.Application):
|
|||||||
|
|
||||||
s = srv + (tooltip, background)
|
s = srv + (tooltip, background)
|
||||||
itr = self._services_model.append(s)
|
itr = self._services_model.append(s)
|
||||||
self._services_model.set_value(itr, 8, self._picons.get(srv.picon_id, None))
|
self._services_model.set_value(itr, Column.SRV_PICON, self._picons.get(srv.picon_id, None))
|
||||||
yield True
|
yield True
|
||||||
self._wait_dialog.hide()
|
self._wait_dialog.hide()
|
||||||
|
|
||||||
@@ -865,7 +933,7 @@ class Application(Gtk.Application):
|
|||||||
@run_idle
|
@run_idle
|
||||||
def on_data_save(self, *args):
|
def on_data_save(self, *args):
|
||||||
if len(self._bouquets_model) == 0:
|
if len(self._bouquets_model) == 0:
|
||||||
show_dialog(DialogType.ERROR, self._main_window, get_message("No data to save!"))
|
self.show_error_dialog("No data to save!")
|
||||||
return
|
return
|
||||||
|
|
||||||
if show_dialog(DialogType.QUESTION, self._main_window) == Gtk.ResponseType.CANCEL:
|
if show_dialog(DialogType.QUESTION, self._main_window) == Gtk.ResponseType.CANCEL:
|
||||||
@@ -887,7 +955,8 @@ class Application(Gtk.Application):
|
|||||||
num_of_children = model.iter_n_children(itr)
|
num_of_children = model.iter_n_children(itr)
|
||||||
for num in range(num_of_children):
|
for num in range(num_of_children):
|
||||||
bq_itr = model.iter_nth_child(itr, num)
|
bq_itr = model.iter_nth_child(itr, num)
|
||||||
bq_name, locked, hidden, bq_type = model.get(bq_itr, 0, 1, 2, 3)
|
bq_name, locked, hidden, bq_type = model.get(bq_itr, Column.BQ_NAME, Column.BQ_LOCKED,
|
||||||
|
Column.BQ_HIDDEN, Column.BQ_TYPE)
|
||||||
bq_id = "{}:{}".format(bq_name, bq_type)
|
bq_id = "{}:{}".format(bq_name, bq_type)
|
||||||
favs = self._bouquets[bq_id]
|
favs = self._bouquets[bq_id]
|
||||||
ex_s = self._extra_bouquets.get(bq_id)
|
ex_s = self._extra_bouquets.get(bq_id)
|
||||||
@@ -897,7 +966,7 @@ class Application(Gtk.Application):
|
|||||||
bq = Bouquet(bq_name, bq_type, bq_s, locked, hidden)
|
bq = Bouquet(bq_name, bq_type, bq_s, locked, hidden)
|
||||||
bqs.append(bq)
|
bqs.append(bq)
|
||||||
if len(b_path) == 1:
|
if len(b_path) == 1:
|
||||||
bouquets.append(Bouquets(*model.get(itr, 0, 3), bqs if bqs else []))
|
bouquets.append(Bouquets(*model.get(itr, Column.BQ_NAME, Column.BQ_TYPE), bqs if bqs else []))
|
||||||
|
|
||||||
profile = Profile(self._profile)
|
profile = Profile(self._profile)
|
||||||
# Getting bouquets
|
# Getting bouquets
|
||||||
@@ -935,7 +1004,7 @@ class Application(Gtk.Application):
|
|||||||
|
|
||||||
def update_service_bar(self, model, path):
|
def update_service_bar(self, model, path):
|
||||||
def_val = "Unknown"
|
def_val = "Unknown"
|
||||||
cas = model.get_value(model.get_iter(path), 0)
|
cas = model.get_value(model.get_iter(path), Column.SRV_CAS_FLAGS)
|
||||||
if not cas:
|
if not cas:
|
||||||
return
|
return
|
||||||
cas_values = list(filter(lambda val: val.startswith("C:"), cas.split(",")))
|
cas_values = list(filter(lambda val: val.startswith("C:"), cas.split(",")))
|
||||||
@@ -948,7 +1017,7 @@ class Application(Gtk.Application):
|
|||||||
|
|
||||||
if self._current_bq_name:
|
if self._current_bq_name:
|
||||||
ch_row = model[model.get_iter(path)][:]
|
ch_row = model[model.get_iter(path)][:]
|
||||||
self._bq_selected = "{}:{}".format(ch_row[0], ch_row[3])
|
self._bq_selected = "{}:{}".format(ch_row[Column.BQ_NAME], ch_row[Column.BQ_TYPE])
|
||||||
else:
|
else:
|
||||||
self._bq_selected = ""
|
self._bq_selected = ""
|
||||||
|
|
||||||
@@ -966,7 +1035,7 @@ class Application(Gtk.Application):
|
|||||||
if path:
|
if path:
|
||||||
tree_iter = model.get_iter(path)
|
tree_iter = model.get_iter(path)
|
||||||
|
|
||||||
key = bq_key if bq_key else "{}:{}".format(*model.get(tree_iter, 0, 3))
|
key = bq_key if bq_key else "{}:{}".format(*model.get(tree_iter, Column.BQ_NAME, Column.BQ_TYPE))
|
||||||
services = self._bouquets.get(key, None)
|
services = self._bouquets.get(key, None)
|
||||||
ex_services = self._extra_bouquets.get(key, None)
|
ex_services = self._extra_bouquets.get(key, None)
|
||||||
if not services:
|
if not services:
|
||||||
@@ -987,11 +1056,11 @@ class Application(Gtk.Application):
|
|||||||
def check_bouquet_selection(self):
|
def check_bouquet_selection(self):
|
||||||
""" checks and returns bouquet if selected """
|
""" checks and returns bouquet if selected """
|
||||||
if not self._bq_selected:
|
if not self._bq_selected:
|
||||||
show_dialog(DialogType.ERROR, self._main_window, "Error. No bouquet is selected!")
|
self.show_error_dialog("Error. No bouquet is selected!")
|
||||||
return
|
return
|
||||||
|
|
||||||
if Profile(self._profile) is Profile.NEUTRINO_MP and self._bq_selected.endswith(BqType.WEBTV.value):
|
if Profile(self._profile) is Profile.NEUTRINO_MP and self._bq_selected.endswith(BqType.WEBTV.value):
|
||||||
show_dialog(DialogType.ERROR, self._main_window, "Operation not allowed in this context!")
|
self.show_error_dialog("Operation not allowed in this context!")
|
||||||
return
|
return
|
||||||
|
|
||||||
return self._bq_selected
|
return self._bq_selected
|
||||||
@@ -1004,11 +1073,11 @@ class Application(Gtk.Application):
|
|||||||
if bqs_rows:
|
if bqs_rows:
|
||||||
bq_type = row[-1]
|
bq_type = row[-1]
|
||||||
for b_row in bqs_rows:
|
for b_row in bqs_rows:
|
||||||
bq_id = "{}:{}".format(b_row[0], b_row[-1])
|
bq_id = "{}:{}".format(b_row[Column.BQ_NAME], b_row[Column.BQ_TYPE])
|
||||||
bq = self._bouquets.get(bq_id, None)
|
bq = self._bouquets.get(bq_id, None)
|
||||||
if bq:
|
if bq:
|
||||||
b_row[-1] = bq_type
|
b_row[Column.BQ_TYPE] = bq_type
|
||||||
self._bouquets["{}:{}".format(b_row[0], b_row[-1])] = bq
|
self._bouquets["{}:{}".format(b_row[Column.BQ_NAME], b_row[Column.BQ_TYPE])] = bq
|
||||||
|
|
||||||
def delete_selection(self, view, *args):
|
def delete_selection(self, view, *args):
|
||||||
""" Used for clear selection on given view(s) """
|
""" Used for clear selection on given view(s) """
|
||||||
@@ -1041,7 +1110,11 @@ class Application(Gtk.Application):
|
|||||||
ctrl = event.state & Gdk.ModifierType.CONTROL_MASK
|
ctrl = event.state & Gdk.ModifierType.CONTROL_MASK
|
||||||
model_name, model = get_model_data(view)
|
model_name, model = get_model_data(view)
|
||||||
|
|
||||||
if ctrl and key in MOVE_KEYS:
|
if ctrl and key is KeyboardKey.O:
|
||||||
|
self.open_data()
|
||||||
|
elif ctrl and key is KeyboardKey.Q:
|
||||||
|
self.quit()
|
||||||
|
elif ctrl and key in MOVE_KEYS:
|
||||||
self.move_items(key)
|
self.move_items(key)
|
||||||
elif ctrl and key is KeyboardKey.C:
|
elif ctrl and key is KeyboardKey.C:
|
||||||
if model_name == self._SERVICE_LIST_NAME:
|
if model_name == self._SERVICE_LIST_NAME:
|
||||||
@@ -1073,7 +1146,13 @@ class Application(Gtk.Application):
|
|||||||
ctrl = event.state & Gdk.ModifierType.CONTROL_MASK
|
ctrl = event.state & Gdk.ModifierType.CONTROL_MASK
|
||||||
model_name, model = get_model_data(view)
|
model_name, model = get_model_data(view)
|
||||||
|
|
||||||
if ctrl and key is KeyboardKey.INSERT:
|
if ctrl and key is KeyboardKey.D:
|
||||||
|
self.on_download_data()
|
||||||
|
elif ctrl and key is KeyboardKey.U:
|
||||||
|
self.on_upload_data(DownloadType.ALL)
|
||||||
|
elif ctrl and key is KeyboardKey.B:
|
||||||
|
self.on_upload_data(DownloadType.BOUQUETS)
|
||||||
|
elif ctrl and key is KeyboardKey.INSERT:
|
||||||
# Move items from app to fav list
|
# Move items from app to fav list
|
||||||
if model_name == self._SERVICE_LIST_NAME:
|
if model_name == self._SERVICE_LIST_NAME:
|
||||||
self.on_to_fav_copy(view)
|
self.on_to_fav_copy(view)
|
||||||
@@ -1107,12 +1186,6 @@ class Application(Gtk.Application):
|
|||||||
self.update_fav_num_column(model)
|
self.update_fav_num_column(model)
|
||||||
self.update_bouquet_list()
|
self.update_bouquet_list()
|
||||||
|
|
||||||
def on_download(self, item):
|
|
||||||
DownloadDialog(transient=self._main_window,
|
|
||||||
properties=self._options,
|
|
||||||
open_data_callback=self.open_data,
|
|
||||||
profile=Profile(self._profile)).show()
|
|
||||||
|
|
||||||
def on_view_focus(self, view, focus_event):
|
def on_view_focus(self, view, focus_event):
|
||||||
profile = Profile(self._profile)
|
profile = Profile(self._profile)
|
||||||
model_name, model = get_model_data(view)
|
model_name, model = get_model_data(view)
|
||||||
@@ -1207,8 +1280,14 @@ class Application(Gtk.Application):
|
|||||||
|
|
||||||
def on_fav_press(self, menu, event):
|
def on_fav_press(self, menu, event):
|
||||||
if event.get_event_type() == Gdk.EventType.DOUBLE_BUTTON_PRESS:
|
if event.get_event_type() == Gdk.EventType.DOUBLE_BUTTON_PRESS:
|
||||||
self.on_play_stream()
|
if self._fav_click_mode is FavClickMode.DISABLED:
|
||||||
self.on_zap()
|
return
|
||||||
|
elif self._fav_click_mode is FavClickMode.STREAM:
|
||||||
|
self.on_play_stream()
|
||||||
|
elif self._fav_click_mode is FavClickMode.PLAY:
|
||||||
|
self.on_zap(self.on_watch)
|
||||||
|
elif self._fav_click_mode is FavClickMode.ZAP:
|
||||||
|
self.on_zap()
|
||||||
else:
|
else:
|
||||||
return self.on_view_popup_menu(menu, event)
|
return self.on_view_popup_menu(menu, event)
|
||||||
|
|
||||||
@@ -1228,25 +1307,25 @@ class Application(Gtk.Application):
|
|||||||
def on_iptv_list_configuration(self, item):
|
def on_iptv_list_configuration(self, item):
|
||||||
profile = Profile(self._profile)
|
profile = Profile(self._profile)
|
||||||
if profile is Profile.NEUTRINO_MP:
|
if profile is Profile.NEUTRINO_MP:
|
||||||
show_dialog(DialogType.ERROR, transient=self._main_window, text="Neutrino at the moment not supported!")
|
self.show_error_dialog("Neutrino at the moment not supported!")
|
||||||
return
|
return
|
||||||
|
|
||||||
iptv_rows = list(filter(lambda r: r[Column.FAV_TYPE] == BqServiceType.IPTV.value, self._fav_model))
|
iptv_rows = list(filter(lambda r: r[Column.FAV_TYPE] == BqServiceType.IPTV.value, self._fav_model))
|
||||||
if not iptv_rows:
|
if not iptv_rows:
|
||||||
show_dialog(DialogType.ERROR, self._main_window, "This list does not contains IPTV streams!")
|
self.show_error_dialog("This list does not contains IPTV streams!")
|
||||||
return
|
return
|
||||||
|
|
||||||
if not self._bq_selected:
|
if not self._bq_selected:
|
||||||
return
|
return
|
||||||
|
|
||||||
bouquet = self._bouquets.get(self._bq_selected, [])
|
bq = self._bouquets.get(self._bq_selected, [])
|
||||||
IptvListConfigurationDialog(self._main_window, self._services, iptv_rows, bouquet, profile).show()
|
IptvListConfigurationDialog(self._main_window, self._services, iptv_rows, bq, self._fav_model, profile).show()
|
||||||
|
|
||||||
@run_idle
|
@run_idle
|
||||||
def on_remove_all_unavailable(self, item):
|
def on_remove_all_unavailable(self, item):
|
||||||
iptv_rows = list(filter(lambda r: r[5] == BqServiceType.IPTV.value, self._fav_model))
|
iptv_rows = list(filter(lambda r: r[Column.FAV_TYPE] == BqServiceType.IPTV.value, self._fav_model))
|
||||||
if not iptv_rows:
|
if not iptv_rows:
|
||||||
show_dialog(DialogType.ERROR, self._main_window, "This list does not contains IPTV streams!")
|
self.show_error_dialog("This list does not contains IPTV streams!")
|
||||||
return
|
return
|
||||||
|
|
||||||
if not self._bq_selected:
|
if not self._bq_selected:
|
||||||
@@ -1261,6 +1340,8 @@ class Application(Gtk.Application):
|
|||||||
if response:
|
if response:
|
||||||
next(self.remove_favs(response, self._fav_model), False)
|
next(self.remove_favs(response, self._fav_model), False)
|
||||||
|
|
||||||
|
# ***************** Import ********************#
|
||||||
|
|
||||||
def on_import_m3u(self, item):
|
def on_import_m3u(self, item):
|
||||||
""" Imports iptv from m3u files. """
|
""" Imports iptv from m3u files. """
|
||||||
response = get_chooser_dialog(self._main_window, self._options.get(self._profile), "*.m3u", "m3u files")
|
response = get_chooser_dialog(self._main_window, self._options.get(self._profile), "*.m3u", "m3u files")
|
||||||
@@ -1268,7 +1349,7 @@ class Application(Gtk.Application):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if not str(response).endswith("m3u"):
|
if not str(response).endswith("m3u"):
|
||||||
show_dialog(DialogType.ERROR, self._main_window, text="No m3u file is selected!")
|
self.show_error_dialog("No m3u file is selected!")
|
||||||
return
|
return
|
||||||
|
|
||||||
channels = parse_m3u(response, Profile(self._profile))
|
channels = parse_m3u(response, Profile(self._profile))
|
||||||
@@ -1281,6 +1362,26 @@ class Application(Gtk.Application):
|
|||||||
bq_services.append(ch.fav_id)
|
bq_services.append(ch.fav_id)
|
||||||
next(self.update_bouquet_services(self._fav_model, None, self._bq_selected), False)
|
next(self.update_bouquet_services(self._fav_model, None, self._bq_selected), False)
|
||||||
|
|
||||||
|
def on_import_bouquet(self, item):
|
||||||
|
profile = Profile(self._profile)
|
||||||
|
model, paths = self._bouquets_view.get_selection().get_selected_rows()
|
||||||
|
if not paths:
|
||||||
|
self.show_error_dialog("No selected item!")
|
||||||
|
return
|
||||||
|
|
||||||
|
opts = self._options.get(self._profile)
|
||||||
|
appender = self.append_bouquet if profile is Profile.ENIGMA_2 else self.append_bouquets
|
||||||
|
import_bouquet(self._main_window, profile, model, paths[0], opts, self._services, appender)
|
||||||
|
|
||||||
|
def on_import_bouquets(self, item):
|
||||||
|
response = show_dialog(DialogType.CHOOSER, self._main_window, options=self._options.get(self._profile))
|
||||||
|
if response in (Gtk.ResponseType.CANCEL, Gtk.ResponseType.DELETE_EVENT):
|
||||||
|
return
|
||||||
|
|
||||||
|
ImportDialog(self._main_window, response, Profile(self._profile), self._services.keys(),
|
||||||
|
lambda b, s: (self._wait_dialog.show(), self.append_bouquets(b),
|
||||||
|
self.append_services(s), self.update_sat_positions())).show()
|
||||||
|
|
||||||
# ***************** Backup ********************#
|
# ***************** Backup ********************#
|
||||||
|
|
||||||
def on_backup_tool_show(self, item):
|
def on_backup_tool_show(self, item):
|
||||||
@@ -1308,7 +1409,7 @@ class Application(Gtk.Application):
|
|||||||
try:
|
try:
|
||||||
self._player = Player()
|
self._player = Player()
|
||||||
except (NameError, AttributeError):
|
except (NameError, AttributeError):
|
||||||
show_dialog(DialogType.ERROR, self._main_window, "No VLC is found. Check that it is installed!")
|
self.show_error_dialog("No VLC is found. Check that it is installed!")
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
if self._drawing_area_xid:
|
if self._drawing_area_xid:
|
||||||
@@ -1398,17 +1499,17 @@ class Application(Gtk.Application):
|
|||||||
self._http_api = None
|
self._http_api = None
|
||||||
|
|
||||||
prp = self._options.get(self._profile)
|
prp = self._options.get(self._profile)
|
||||||
|
self._fav_click_mode = FavClickMode(prp.get("fav_click_mode", FavClickMode.DISABLED))
|
||||||
|
|
||||||
if prp is Profile.NEUTRINO_MP or not prp.get("http_api_support", False):
|
if prp is Profile.NEUTRINO_MP or not prp.get("http_api_support", False):
|
||||||
self.update_info_boxes_visible(False)
|
self.update_info_boxes_visible(False)
|
||||||
return
|
return
|
||||||
|
|
||||||
self._http_api = http_request(prp.get("host", "127.0.0.1"), prp.get("http_port", "80"),
|
self._http_api = http_request(prp.get("host", "127.0.0.1"), prp.get("http_port", "80"),
|
||||||
prp.get("http_user", ""), prp.get("http_password", ""))
|
prp.get("http_user", ""), prp.get("http_password", ""))
|
||||||
|
|
||||||
next(self._http_api)
|
next(self._http_api)
|
||||||
GLib.timeout_add_seconds(1, self.update_receiver_info)
|
GLib.timeout_add_seconds(1, self.update_receiver_info)
|
||||||
|
|
||||||
@run_idle
|
|
||||||
def on_watch(self):
|
def on_watch(self):
|
||||||
""" Switch to the channel and watch in the player """
|
""" Switch to the channel and watch in the player """
|
||||||
m3u = self._http_api.send((HttpRequestType.STREAM, None))
|
m3u = self._http_api.send((HttpRequestType.STREAM, None))
|
||||||
@@ -1624,7 +1725,7 @@ class Application(Gtk.Application):
|
|||||||
def on_bouquets_edit(self, view):
|
def on_bouquets_edit(self, view):
|
||||||
""" Rename bouquets """
|
""" Rename bouquets """
|
||||||
if not self._bq_selected:
|
if not self._bq_selected:
|
||||||
show_dialog(DialogType.ERROR, self._main_window, "This item is not allowed to edit!")
|
self.show_error_dialog("This item is not allowed to edit!")
|
||||||
return
|
return
|
||||||
|
|
||||||
model, paths = view.get_selection().get_selected_rows()
|
model, paths = view.get_selection().get_selected_rows()
|
||||||
@@ -1659,7 +1760,7 @@ class Application(Gtk.Application):
|
|||||||
cur_name, srv_type, fav_id = data[Column.FAV_SERVICE], data[Column.FAV_TYPE], data[Column.FAV_ID]
|
cur_name, srv_type, fav_id = data[Column.FAV_SERVICE], data[Column.FAV_TYPE], data[Column.FAV_ID]
|
||||||
|
|
||||||
if srv_type == BqServiceType.IPTV.name or srv_type == BqServiceType.MARKER.name:
|
if srv_type == BqServiceType.IPTV.name or srv_type == BqServiceType.MARKER.name:
|
||||||
show_dialog(DialogType.ERROR, self._main_window, "Not allowed in this context!")
|
self.show_error_dialog("Not allowed in this context!")
|
||||||
return
|
return
|
||||||
|
|
||||||
response = show_dialog(DialogType.INPUT, self._main_window, cur_name)
|
response = show_dialog(DialogType.INPUT, self._main_window, cur_name)
|
||||||
@@ -1693,11 +1794,11 @@ class Application(Gtk.Application):
|
|||||||
ex_bq = self._extra_bouquets.get(self._bq_selected, None)
|
ex_bq = self._extra_bouquets.get(self._bq_selected, None)
|
||||||
|
|
||||||
if not ex_bq:
|
if not ex_bq:
|
||||||
show_dialog(DialogType.ERROR, self._main_window, "No changes required!")
|
self.show_error_dialog("No changes required!")
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
if not ex_bq.pop(fav_id, None):
|
if not ex_bq.pop(fav_id, None):
|
||||||
show_dialog(DialogType.ERROR, self._main_window, "No changes required!")
|
self.show_error_dialog("No changes required!")
|
||||||
return
|
return
|
||||||
if not ex_bq:
|
if not ex_bq:
|
||||||
self._extra_bouquets.pop(self._bq_selected, None)
|
self._extra_bouquets.pop(self._bq_selected, None)
|
||||||
@@ -1746,6 +1847,12 @@ class Application(Gtk.Application):
|
|||||||
""" Copying picon id to clipboard """
|
""" Copying picon id to clipboard """
|
||||||
copy_picon_reference(self.get_target_view(view), view, self._services, self._clipboard, self._main_window)
|
copy_picon_reference(self.get_target_view(view), view, self._services, self._clipboard, self._main_window)
|
||||||
|
|
||||||
|
def on_remove_unused_picons(self, item):
|
||||||
|
if show_dialog(DialogType.QUESTION, self._main_window) == Gtk.ResponseType.CANCEL:
|
||||||
|
return
|
||||||
|
|
||||||
|
remove_all_unused_picons(self._options.get(self._profile), self._picons, self._services.values())
|
||||||
|
|
||||||
def get_target_view(self, view):
|
def get_target_view(self, view):
|
||||||
return ViewTarget.SERVICES if Gtk.Buildable.get_name(view) == "services_tree_view" else ViewTarget.FAV
|
return ViewTarget.SERVICES if Gtk.Buildable.get_name(view) == "services_tree_view" else ViewTarget.FAV
|
||||||
|
|
||||||
@@ -1790,6 +1897,10 @@ class Application(Gtk.Application):
|
|||||||
self._signal_box.set_visible(visible)
|
self._signal_box.set_visible(visible)
|
||||||
self._receiver_info_box.set_visible(visible)
|
self._receiver_info_box.set_visible(visible)
|
||||||
|
|
||||||
|
@run_idle
|
||||||
|
def show_error_dialog(self, message):
|
||||||
|
show_dialog(DialogType.ERROR, self._main_window, message)
|
||||||
|
|
||||||
|
|
||||||
def start_app():
|
def start_app():
|
||||||
app = Application()
|
app = Application()
|
||||||
|
|||||||
@@ -435,15 +435,7 @@ def remove_picon(target, srv_view, fav_view, picons, options):
|
|||||||
fav_view.get_model().foreach(remove) if target is ViewTarget.SERVICES else get_base_model(
|
fav_view.get_model().foreach(remove) if target is ViewTarget.SERVICES else get_base_model(
|
||||||
srv_view.get_model()).foreach(remove)
|
srv_view.get_model()).foreach(remove)
|
||||||
|
|
||||||
pions_path = options.get("picons_dir_path")
|
remove_picons(options, picon_ids, picons)
|
||||||
backup_path = options.get("data_dir_path") + "backup/picons/"
|
|
||||||
os.makedirs(os.path.dirname(backup_path), exist_ok=True)
|
|
||||||
|
|
||||||
for p_id in picon_ids:
|
|
||||||
picons[p_id] = None
|
|
||||||
src = pions_path + p_id
|
|
||||||
if os.path.isfile(src):
|
|
||||||
shutil.move(src, backup_path + p_id)
|
|
||||||
|
|
||||||
|
|
||||||
def copy_picon_reference(target, view, services, clipboard, transient):
|
def copy_picon_reference(target, view, services, clipboard, transient):
|
||||||
@@ -467,6 +459,23 @@ def copy_picon_reference(target, view, services, clipboard, transient):
|
|||||||
show_dialog(DialogType.ERROR, transient, "No reference is present!")
|
show_dialog(DialogType.ERROR, transient, "No reference is present!")
|
||||||
|
|
||||||
|
|
||||||
|
def remove_all_unused_picons(options, picons, services):
|
||||||
|
ids = {s.picon_id for s in services}
|
||||||
|
pcs = list(filter(lambda x: x not in ids, picons))
|
||||||
|
remove_picons(options, pcs, picons)
|
||||||
|
|
||||||
|
|
||||||
|
def remove_picons(options, picon_ids, picons):
|
||||||
|
pions_path = options.get("picons_dir_path")
|
||||||
|
backup_path = options.get("backup_dir_path") + "picons/"
|
||||||
|
os.makedirs(os.path.dirname(backup_path), exist_ok=True)
|
||||||
|
for p_id in picon_ids:
|
||||||
|
picons[p_id] = None
|
||||||
|
src = pions_path + p_id
|
||||||
|
if os.path.isfile(src):
|
||||||
|
shutil.move(src, backup_path + p_id)
|
||||||
|
|
||||||
|
|
||||||
def is_only_one_item_selected(paths, transient):
|
def is_only_one_item_selected(paths, transient):
|
||||||
if len(paths) > 1:
|
if len(paths) > 1:
|
||||||
show_dialog(DialogType.ERROR, transient, "Please, select only one item!")
|
show_dialog(DialogType.ERROR, transient, "Please, select only one item!")
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -5,6 +5,7 @@ from math import fabs
|
|||||||
|
|
||||||
from app.commons import run_idle, run_task
|
from app.commons import run_idle, run_task
|
||||||
from app.eparser import get_satellites, write_satellites, Satellite, Transponder
|
from app.eparser import get_satellites, write_satellites, Satellite, Transponder
|
||||||
|
from app.eparser.ecommons import PLS_MODE, get_key_by_value
|
||||||
from app.tools.satellites import SatellitesParser, SatelliteSource
|
from app.tools.satellites import SatellitesParser, SatelliteSource
|
||||||
from .search import SearchProvider
|
from .search import SearchProvider
|
||||||
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, TEXT_DOMAIN, MOVE_KEYS, KeyboardKey
|
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, TEXT_DOMAIN, MOVE_KEYS, KeyboardKey
|
||||||
@@ -360,7 +361,7 @@ class TransponderDialog:
|
|||||||
self._fec_box.set_active_id(transponder.fec_inner)
|
self._fec_box.set_active_id(transponder.fec_inner)
|
||||||
self._sys_box.set_active_id(transponder.system)
|
self._sys_box.set_active_id(transponder.system)
|
||||||
self._mod_box.set_active_id(transponder.modulation)
|
self._mod_box.set_active_id(transponder.modulation)
|
||||||
self._pls_mode_box.set_active_id(transponder.pls_mode)
|
self._pls_mode_box.set_active_id(PLS_MODE.get(transponder.pls_mode, None))
|
||||||
self._is_id_entry.set_text(transponder.is_id if transponder.is_id else "")
|
self._is_id_entry.set_text(transponder.is_id if transponder.is_id else "")
|
||||||
self._pls_code_entry.set_text(transponder.pls_code if transponder.pls_code else "")
|
self._pls_code_entry.set_text(transponder.pls_code if transponder.pls_code else "")
|
||||||
|
|
||||||
@@ -371,7 +372,7 @@ class TransponderDialog:
|
|||||||
fec_inner=self._fec_box.get_active_id(),
|
fec_inner=self._fec_box.get_active_id(),
|
||||||
system=self._sys_box.get_active_id(),
|
system=self._sys_box.get_active_id(),
|
||||||
modulation=self._mod_box.get_active_id(),
|
modulation=self._mod_box.get_active_id(),
|
||||||
pls_mode=self._pls_mode_box.get_active_id(),
|
pls_mode=get_key_by_value(PLS_MODE, self._pls_mode_box.get_active_id()),
|
||||||
pls_code=self._pls_code_entry.get_text(),
|
pls_code=self._pls_code_entry.get_text(),
|
||||||
is_id=self._is_id_entry.get_text())
|
is_id=self._is_id_entry.get_text())
|
||||||
|
|
||||||
|
|||||||
@@ -59,17 +59,15 @@ Author: Dmitriy Yefremov
|
|||||||
<object class="GtkHeaderBar" id="header_bar">
|
<object class="GtkHeaderBar" id="header_bar">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="title" translatable="yes">Options</property>
|
|
||||||
<property name="subtitle" translatable="yes">Profile: Enigma2</property>
|
|
||||||
<property name="spacing">2</property>
|
<property name="spacing">2</property>
|
||||||
<property name="show_close_button">True</property>
|
<property name="show_close_button">True</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkButton" id="ok_button">
|
<object class="GtkButton" id="ok_button">
|
||||||
<property name="width_request">48</property>
|
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="receives_default">True</property>
|
<property name="receives_default">True</property>
|
||||||
<property name="tooltip_text" translatable="yes">Ok</property>
|
<property name="tooltip_text" translatable="yes">Ok</property>
|
||||||
|
<property name="margin_top">10</property>
|
||||||
<property name="always_show_image">True</property>
|
<property name="always_show_image">True</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkImage" id="ok_button_image">
|
<object class="GtkImage" id="ok_button_image">
|
||||||
@@ -82,11 +80,11 @@ Author: Dmitriy Yefremov
|
|||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkButton" id="apply_button">
|
<object class="GtkButton" id="apply_button">
|
||||||
<property name="width_request">48</property>
|
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="receives_default">True</property>
|
<property name="receives_default">True</property>
|
||||||
<property name="tooltip_text" translatable="yes">Save</property>
|
<property name="tooltip_text" translatable="yes">Save</property>
|
||||||
|
<property name="margin_top">10</property>
|
||||||
<signal name="clicked" handler="apply_settings" swapped="no"/>
|
<signal name="clicked" handler="apply_settings" swapped="no"/>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkImage" id="apply_button_image">
|
<object class="GtkImage" id="apply_button_image">
|
||||||
@@ -100,6 +98,92 @@ Author: Dmitriy Yefremov
|
|||||||
<property name="position">2</property>
|
<property name="position">2</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
<child type="title">
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="margin_left">10</property>
|
||||||
|
<property name="margin_right">10</property>
|
||||||
|
<property name="margin_top">5</property>
|
||||||
|
<property name="margin_bottom">5</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="spacing">5</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Options</property>
|
||||||
|
<attributes>
|
||||||
|
<attribute name="weight" value="semibold"/>
|
||||||
|
</attributes>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox" id="settings_profile_box">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="margin_left">10</property>
|
||||||
|
<property name="margin_right">10</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="active_profile_label">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="margin_right">2</property>
|
||||||
|
<property name="label" translatable="yes">Profile:</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkRadioButton" id="enigma_radio_button">
|
||||||
|
<property name="label">Enigma2 </property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="halign">center</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
<property name="group">neutrino_radio_button</property>
|
||||||
|
<signal name="toggled" handler="on_profile_changed" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkRadioButton" id="neutrino_radio_button">
|
||||||
|
<property name="label">Neutrino-MP(experimental)</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="halign">center</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
<property name="group">enigma_radio_button</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">4</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkButton" id="reset_button">
|
<object class="GtkButton" id="reset_button">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
@@ -108,8 +192,8 @@ Author: Dmitriy Yefremov
|
|||||||
<property name="tooltip_text" translatable="yes">Reset profile</property>
|
<property name="tooltip_text" translatable="yes">Reset profile</property>
|
||||||
<property name="halign">end</property>
|
<property name="halign">end</property>
|
||||||
<property name="margin_left">5</property>
|
<property name="margin_left">5</property>
|
||||||
<property name="margin_right">5</property>
|
<property name="margin_right">2</property>
|
||||||
<property name="margin_bottom">5</property>
|
<property name="margin_top">10</property>
|
||||||
<property name="always_show_image">True</property>
|
<property name="always_show_image">True</property>
|
||||||
<signal name="clicked" handler="on_reset" swapped="no"/>
|
<signal name="clicked" handler="on_reset" swapped="no"/>
|
||||||
<child>
|
<child>
|
||||||
@@ -177,7 +261,6 @@ Author: Dmitriy Yefremov
|
|||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="margin_left">6</property>
|
<property name="margin_left">6</property>
|
||||||
<property name="margin_right">5</property>
|
<property name="margin_right">5</property>
|
||||||
<property name="margin_top">5</property>
|
|
||||||
<property name="orientation">vertical</property>
|
<property name="orientation">vertical</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkFrame" id="network_settings_frame">
|
<object class="GtkFrame" id="network_settings_frame">
|
||||||
@@ -709,7 +792,6 @@ Author: Dmitriy Yefremov
|
|||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="margin_left">5</property>
|
<property name="margin_left">5</property>
|
||||||
<property name="margin_right">5</property>
|
<property name="margin_right">5</property>
|
||||||
<property name="margin_top">5</property>
|
|
||||||
<property name="orientation">vertical</property>
|
<property name="orientation">vertical</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkFrame" id="stb_paths_frame">
|
<object class="GtkFrame" id="stb_paths_frame">
|
||||||
@@ -840,6 +922,7 @@ Author: Dmitriy Yefremov
|
|||||||
<object class="GtkFrame" id="local_file_paths_frame">
|
<object class="GtkFrame" id="local_file_paths_frame">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
|
<property name="margin_top">5</property>
|
||||||
<property name="label_xalign">0.019999999552965164</property>
|
<property name="label_xalign">0.019999999552965164</property>
|
||||||
<property name="shadow_type">in</property>
|
<property name="shadow_type">in</property>
|
||||||
<child>
|
<child>
|
||||||
@@ -965,74 +1048,6 @@ Author: Dmitriy Yefremov
|
|||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="orientation">vertical</property>
|
<property name="orientation">vertical</property>
|
||||||
<child>
|
|
||||||
<object class="GtkFrame" id="settings_profile_frame">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">False</property>
|
|
||||||
<property name="margin_left">5</property>
|
|
||||||
<property name="margin_right">5</property>
|
|
||||||
<property name="margin_top">5</property>
|
|
||||||
<property name="margin_bottom">5</property>
|
|
||||||
<property name="label_xalign">0.019999999552965164</property>
|
|
||||||
<property name="shadow_type">in</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkBox" id="settings_profile_box">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">False</property>
|
|
||||||
<property name="margin_left">10</property>
|
|
||||||
<property name="margin_right">10</property>
|
|
||||||
<property name="margin_bottom">5</property>
|
|
||||||
<property name="spacing">5</property>
|
|
||||||
<property name="homogeneous">True</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkRadioButton" id="enigma_radio_button">
|
|
||||||
<property name="label">Enigma2 </property>
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">True</property>
|
|
||||||
<property name="receives_default">False</property>
|
|
||||||
<property name="halign">center</property>
|
|
||||||
<property name="draw_indicator">True</property>
|
|
||||||
<property name="group">neutrino_radio_button</property>
|
|
||||||
<signal name="toggled" handler="on_profile_changed" swapped="no"/>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="GtkRadioButton" id="neutrino_radio_button">
|
|
||||||
<property name="label">Neutrino-MP(experimental)</property>
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">True</property>
|
|
||||||
<property name="receives_default">False</property>
|
|
||||||
<property name="halign">center</property>
|
|
||||||
<property name="draw_indicator">True</property>
|
|
||||||
<property name="group">enigma_radio_button</property>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">4</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child type="label">
|
|
||||||
<object class="GtkLabel" id="active_profile_label">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">False</property>
|
|
||||||
<property name="label" translatable="yes">Active profile:</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
<packing>
|
|
||||||
<property name="expand">False</property>
|
|
||||||
<property name="fill">True</property>
|
|
||||||
<property name="position">0</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkFrame" id="backup_frame">
|
<object class="GtkFrame" id="backup_frame">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
@@ -1077,6 +1092,7 @@ Author: Dmitriy Yefremov
|
|||||||
<object class="GtkLabel">
|
<object class="GtkLabel">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
|
<property name="margin_bottom">1</property>
|
||||||
<property name="hexpand">True</property>
|
<property name="hexpand">True</property>
|
||||||
<property name="label" translatable="yes">Before saving</property>
|
<property name="label" translatable="yes">Before saving</property>
|
||||||
<property name="xalign">0</property>
|
<property name="xalign">0</property>
|
||||||
@@ -1111,22 +1127,22 @@ Author: Dmitriy Yefremov
|
|||||||
<packing>
|
<packing>
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
<property name="fill">True</property>
|
<property name="fill">True</property>
|
||||||
<property name="position">1</property>
|
<property name="position">0</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkBox" id="program_box">
|
<object class="GtkBox" id="program_box">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="sensitive">False</property>
|
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="margin_top">5</property>
|
|
||||||
<property name="orientation">vertical</property>
|
<property name="orientation">vertical</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkFrame" id="program_frame">
|
<object class="GtkFrame" id="program_frame">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
<property name="sensitive">False</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="margin_left">5</property>
|
<property name="margin_left">5</property>
|
||||||
<property name="margin_right">5</property>
|
<property name="margin_right">5</property>
|
||||||
|
<property name="margin_top">5</property>
|
||||||
<property name="margin_bottom">5</property>
|
<property name="margin_bottom">5</property>
|
||||||
<property name="label_xalign">0</property>
|
<property name="label_xalign">0</property>
|
||||||
<property name="shadow_type">in</property>
|
<property name="shadow_type">in</property>
|
||||||
@@ -1183,7 +1199,6 @@ Author: Dmitriy Yefremov
|
|||||||
<property name="sensitive">False</property>
|
<property name="sensitive">False</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="margin_top">5</property>
|
<property name="margin_top">5</property>
|
||||||
<property name="margin_bottom">5</property>
|
|
||||||
<property name="row_spacing">5</property>
|
<property name="row_spacing">5</property>
|
||||||
<property name="column_spacing">20</property>
|
<property name="column_spacing">20</property>
|
||||||
<child>
|
<child>
|
||||||
@@ -1262,43 +1277,166 @@ Author: Dmitriy Yefremov
|
|||||||
<property name="label_xalign">0.019999999552965164</property>
|
<property name="label_xalign">0.019999999552965164</property>
|
||||||
<property name="shadow_type">in</property>
|
<property name="shadow_type">in</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkGrid" id="extra_support_grid">
|
<object class="GtkBox" id="parogram_extra_box">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">False</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="halign">center</property>
|
<property name="margin_left">5</property>
|
||||||
<property name="valign">start</property>
|
<property name="margin_right">5</property>
|
||||||
<property name="margin_left">10</property>
|
<property name="margin_bottom">5</property>
|
||||||
<property name="margin_right">10</property>
|
<property name="orientation">vertical</property>
|
||||||
<property name="margin_bottom">10</property>
|
|
||||||
<property name="row_spacing">5</property>
|
|
||||||
<property name="column_spacing">50</property>
|
|
||||||
<property name="column_homogeneous">True</property>
|
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkCheckButton" id="support_ver5_check_button">
|
<object class="GtkGrid" id="extra_support_grid">
|
||||||
<property name="label" translatable="yes">Ver. 5 support
|
|
||||||
(experimental)</property>
|
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="receives_default">False</property>
|
<property name="row_spacing">5</property>
|
||||||
<property name="draw_indicator">True</property>
|
<property name="column_spacing">5</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkSwitch" id="support_ver5_check_button">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="halign">end</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkSwitch" id="support_http_api_check_button">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="halign">end</property>
|
||||||
|
<signal name="state-set" handler="on_http_mode_switch_state" swapped="no"/>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="halign">start</property>
|
||||||
|
<property name="hexpand">True</property>
|
||||||
|
<property name="label" translatable="yes">Enable ver. 5 support (experimental)</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="halign">start</property>
|
||||||
|
<property name="hexpand">True</property>
|
||||||
|
<property name="label" translatable="yes">Enable HTTP API (experimental)</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="left_attach">0</property>
|
<property name="expand">True</property>
|
||||||
<property name="top_attach">0</property>
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkCheckButton" id="support_http_api_check_button">
|
<object class="GtkLabel">
|
||||||
<property name="label" translatable="yes">Enable HTTP API
|
|
||||||
(experimental)</property>
|
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="receives_default">False</property>
|
<property name="halign">start</property>
|
||||||
<property name="draw_indicator">True</property>
|
<property name="label" translatable="yes">Double click on the service in the bouquet list:</property>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="left_attach">1</property>
|
<property name="expand">True</property>
|
||||||
<property name="top_attach">0</property>
|
<property name="fill">False</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkGrid" id="double_click_mode_grid">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="halign">center</property>
|
||||||
|
<property name="margin_bottom">5</property>
|
||||||
|
<property name="column_spacing">5</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkRadioButton" id="click_mode_zap_button">
|
||||||
|
<property name="label" translatable="yes">Zap</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="sensitive">False</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="tooltip_text" translatable="yes">Switch(zap) the channel(Ctrl + Z)</property>
|
||||||
|
<property name="active">True</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
<property name="group">click_mode_disabled_button</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">0</property>
|
||||||
|
<property name="top_attach">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkRadioButton" id="click_mode_play_button">
|
||||||
|
<property name="label" translatable="yes">Play</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="sensitive">False</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="tooltip_text" translatable="yes">Switch the channel and watch in the program(Ctrl + W)</property>
|
||||||
|
<property name="active">True</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
<property name="group">click_mode_stream_button</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="top_attach">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkRadioButton" id="click_mode_stream_button">
|
||||||
|
<property name="label" translatable="yes">Play stream</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="tooltip_text" translatable="yes">Play IPTV or other stream in the program(Ctrl + P)</property>
|
||||||
|
<property name="active">True</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
<property name="group">click_mode_play_button</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">2</property>
|
||||||
|
<property name="top_attach">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkRadioButton" id="click_mode_disabled_button">
|
||||||
|
<property name="label" translatable="yes">Disabled</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="receives_default">False</property>
|
||||||
|
<property name="tooltip_text" translatable="yes">Disabled</property>
|
||||||
|
<property name="active">True</property>
|
||||||
|
<property name="draw_indicator">True</property>
|
||||||
|
<property name="group">click_mode_play_button</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">3</property>
|
||||||
|
<property name="top_attach">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">2</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
@@ -1321,7 +1459,7 @@ Author: Dmitriy Yefremov
|
|||||||
<packing>
|
<packing>
|
||||||
<property name="expand">True</property>
|
<property name="expand">True</property>
|
||||||
<property name="fill">True</property>
|
<property name="fill">True</property>
|
||||||
<property name="position">2</property>
|
<property name="position">1</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
from gi.repository import Gdk
|
|
||||||
|
|
||||||
from app.commons import run_task, run_idle
|
from app.commons import run_task, run_idle
|
||||||
from app.connections import test_telnet, test_ftp, TestException, test_http
|
from app.connections import test_telnet, test_ftp, TestException, test_http
|
||||||
from app.properties import write_config, Profile, get_default_settings
|
from app.properties import write_config, Profile, get_default_settings
|
||||||
from app.ui.dialogs import get_message
|
from app.ui.dialogs import get_message
|
||||||
from .uicommons import Gtk, UI_RESOURCES_PATH, TEXT_DOMAIN, NEW_COLOR, EXTRA_COLOR
|
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, TEXT_DOMAIN, NEW_COLOR, EXTRA_COLOR, FavClickMode
|
||||||
from .main_helper import update_entry_data
|
from .main_helper import update_entry_data
|
||||||
|
|
||||||
|
|
||||||
@@ -29,7 +27,8 @@ class SettingsDialog:
|
|||||||
"apply_settings": self.apply_settings,
|
"apply_settings": self.apply_settings,
|
||||||
"on_connection_test": self.on_connection_test,
|
"on_connection_test": self.on_connection_test,
|
||||||
"on_info_bar_close": self.on_info_bar_close,
|
"on_info_bar_close": self.on_info_bar_close,
|
||||||
"on_set_color_switch_state": self.on_set_color_switch_state}
|
"on_set_color_switch_state": self.on_set_color_switch_state,
|
||||||
|
"on_http_mode_switch_state": self.on_http_mode_switch_state}
|
||||||
|
|
||||||
builder = Gtk.Builder()
|
builder = Gtk.Builder()
|
||||||
builder.set_translation_domain(TEXT_DOMAIN)
|
builder.set_translation_domain(TEXT_DOMAIN)
|
||||||
@@ -72,11 +71,16 @@ class SettingsDialog:
|
|||||||
# Program
|
# Program
|
||||||
self._before_save_switch = builder.get_object("before_save_switch")
|
self._before_save_switch = builder.get_object("before_save_switch")
|
||||||
self._before_downloading_switch = builder.get_object("before_downloading_switch")
|
self._before_downloading_switch = builder.get_object("before_downloading_switch")
|
||||||
self._program_box = builder.get_object("program_box")
|
self._program_frame = builder.get_object("program_frame")
|
||||||
|
self._extra_support_grid = builder.get_object("extra_support_grid")
|
||||||
self._colors_grid = builder.get_object("colors_grid")
|
self._colors_grid = builder.get_object("colors_grid")
|
||||||
self._set_color_switch = builder.get_object("set_color_switch")
|
self._set_color_switch = builder.get_object("set_color_switch")
|
||||||
self._new_color_button = builder.get_object("new_color_button")
|
self._new_color_button = builder.get_object("new_color_button")
|
||||||
self._extra_color_button = builder.get_object("extra_color_button")
|
self._extra_color_button = builder.get_object("extra_color_button")
|
||||||
|
self._click_mode_disabled_button = builder.get_object("click_mode_disabled_button")
|
||||||
|
self._click_mode_stream_button = builder.get_object("click_mode_stream_button")
|
||||||
|
self._click_mode_play_button = builder.get_object("click_mode_play_button")
|
||||||
|
self._click_mode_zap_button = builder.get_object("click_mode_zap_button")
|
||||||
# Options
|
# Options
|
||||||
self._options = options
|
self._options = options
|
||||||
self._active_profile = options.get("profile")
|
self._active_profile = options.get("profile")
|
||||||
@@ -87,8 +91,11 @@ class SettingsDialog:
|
|||||||
is_enigma_profile = profile is Profile.ENIGMA_2
|
is_enigma_profile = profile is Profile.ENIGMA_2
|
||||||
self._neutrino_radio_button.set_active(profile is Profile.NEUTRINO_MP)
|
self._neutrino_radio_button.set_active(profile is Profile.NEUTRINO_MP)
|
||||||
self._settings_stack.get_child_by_name(Property.HTTP.value).set_visible(is_enigma_profile)
|
self._settings_stack.get_child_by_name(Property.HTTP.value).set_visible(is_enigma_profile)
|
||||||
self._program_box.set_sensitive(is_enigma_profile)
|
self._program_frame.set_sensitive(is_enigma_profile)
|
||||||
self.update_subtitle(profile)
|
self._extra_support_grid.set_sensitive(is_enigma_profile)
|
||||||
|
http_active = self._support_http_api_check_button.get_active()
|
||||||
|
self._click_mode_zap_button.set_sensitive(is_enigma_profile and http_active)
|
||||||
|
self._click_mode_play_button.set_sensitive(is_enigma_profile and http_active)
|
||||||
|
|
||||||
def show(self):
|
def show(self):
|
||||||
response = self._dialog.run()
|
response = self._dialog.run()
|
||||||
@@ -107,10 +114,6 @@ class SettingsDialog:
|
|||||||
self.set_settings()
|
self.set_settings()
|
||||||
self.init_ui_elements(profile)
|
self.init_ui_elements(profile)
|
||||||
|
|
||||||
def update_subtitle(self, profile):
|
|
||||||
sub = "{} Enigma2" if profile is Profile.ENIGMA_2 else "{} Neutrino-MP"
|
|
||||||
self._header_bar.set_subtitle(sub.format(get_message("Profile:")))
|
|
||||||
|
|
||||||
def set_profile(self, profile):
|
def set_profile(self, profile):
|
||||||
self._active_profile = profile.value
|
self._active_profile = profile.value
|
||||||
self.set_settings()
|
self.set_settings()
|
||||||
@@ -129,6 +132,7 @@ class SettingsDialog:
|
|||||||
def set_settings(self):
|
def set_settings(self):
|
||||||
def_settings = get_default_settings().get(self._active_profile)
|
def_settings = get_default_settings().get(self._active_profile)
|
||||||
options = self._options.get(self._active_profile)
|
options = self._options.get(self._active_profile)
|
||||||
|
|
||||||
self._host_field.set_text(options.get("host", def_settings["host"]))
|
self._host_field.set_text(options.get("host", def_settings["host"]))
|
||||||
self._port_field.set_text(options.get("port", def_settings["port"]))
|
self._port_field.set_text(options.get("port", def_settings["port"]))
|
||||||
self._login_field.set_text(options.get("user", def_settings["user"]))
|
self._login_field.set_text(options.get("user", def_settings["user"]))
|
||||||
@@ -150,6 +154,7 @@ class SettingsDialog:
|
|||||||
self._before_save_switch.set_active(options.get("backup_before_save", def_settings["backup_before_save"]))
|
self._before_save_switch.set_active(options.get("backup_before_save", def_settings["backup_before_save"]))
|
||||||
self._before_downloading_switch.set_active(options.get("backup_before_downloading",
|
self._before_downloading_switch.set_active(options.get("backup_before_downloading",
|
||||||
def_settings["backup_before_downloading"]))
|
def_settings["backup_before_downloading"]))
|
||||||
|
self.set_fav_click_mode(options.get("fav_click_mode", def_settings["fav_click_mode"]))
|
||||||
|
|
||||||
if Profile(self._active_profile) is Profile.ENIGMA_2:
|
if Profile(self._active_profile) is Profile.ENIGMA_2:
|
||||||
self._support_ver5_check_button.set_active(options.get("v5_support", False))
|
self._support_ver5_check_button.set_active(options.get("v5_support", False))
|
||||||
@@ -187,6 +192,7 @@ class SettingsDialog:
|
|||||||
options["backup_dir_path"] = self._backup_dir_field.get_text()
|
options["backup_dir_path"] = self._backup_dir_field.get_text()
|
||||||
options["backup_before_save"] = self._before_save_switch.get_active()
|
options["backup_before_save"] = self._before_save_switch.get_active()
|
||||||
options["backup_before_downloading"] = self._before_downloading_switch.get_active()
|
options["backup_before_downloading"] = self._before_downloading_switch.get_active()
|
||||||
|
options["fav_click_mode"] = self.get_fav_click_mode()
|
||||||
|
|
||||||
if profile is Profile.ENIGMA_2:
|
if profile is Profile.ENIGMA_2:
|
||||||
options["v5_support"] = self._support_ver5_check_button.get_active()
|
options["v5_support"] = self._support_ver5_check_button.get_active()
|
||||||
@@ -258,6 +264,30 @@ class SettingsDialog:
|
|||||||
def on_set_color_switch_state(self, switch, state):
|
def on_set_color_switch_state(self, switch, state):
|
||||||
self._colors_grid.set_sensitive(state)
|
self._colors_grid.set_sensitive(state)
|
||||||
|
|
||||||
|
def on_http_mode_switch_state(self, switch, state):
|
||||||
|
self._click_mode_play_button.set_sensitive(state)
|
||||||
|
self._click_mode_zap_button.set_sensitive(state)
|
||||||
|
if self._click_mode_play_button.get_active() or self._click_mode_zap_button.get_active():
|
||||||
|
self._click_mode_disabled_button.set_active(True)
|
||||||
|
|
||||||
|
@run_idle
|
||||||
|
def set_fav_click_mode(self, mode):
|
||||||
|
mode = FavClickMode(mode)
|
||||||
|
self._click_mode_disabled_button.set_active(mode is FavClickMode.DISABLED)
|
||||||
|
self._click_mode_stream_button.set_active(mode is FavClickMode.STREAM)
|
||||||
|
self._click_mode_play_button.set_active(mode is FavClickMode.PLAY)
|
||||||
|
self._click_mode_zap_button.set_active(mode is FavClickMode.ZAP)
|
||||||
|
|
||||||
|
def get_fav_click_mode(self):
|
||||||
|
if self._click_mode_zap_button.get_active():
|
||||||
|
return FavClickMode.ZAP
|
||||||
|
if self._click_mode_play_button.get_active():
|
||||||
|
return FavClickMode.PLAY
|
||||||
|
if self._click_mode_stream_button.get_active():
|
||||||
|
return FavClickMode.STREAM
|
||||||
|
|
||||||
|
return FavClickMode.DISABLED
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -32,17 +32,22 @@ EXTRA_COLOR = "rgb(179,230,204)" # Color for services with a extra name for the
|
|||||||
|
|
||||||
|
|
||||||
class KeyboardKey(Enum):
|
class KeyboardKey(Enum):
|
||||||
""" The raw(hardware) codes of the keyboard keys """
|
""" The raw(hardware) codes of the keyboard keys. """
|
||||||
|
Q = 24
|
||||||
E = 26
|
E = 26
|
||||||
R = 27
|
R = 27
|
||||||
T = 28
|
T = 28
|
||||||
|
U = 30
|
||||||
|
O = 32
|
||||||
P = 33
|
P = 33
|
||||||
S = 39
|
S = 39
|
||||||
|
D = 40
|
||||||
H = 43
|
H = 43
|
||||||
L = 46
|
L = 46
|
||||||
X = 53
|
X = 53
|
||||||
C = 54
|
C = 54
|
||||||
V = 55
|
V = 55
|
||||||
|
B = 56
|
||||||
W = 25
|
W = 25
|
||||||
Z = 52
|
Z = 52
|
||||||
INSERT = 118
|
INSERT = 118
|
||||||
@@ -55,6 +60,7 @@ class KeyboardKey(Enum):
|
|||||||
LEFT = 113
|
LEFT = 113
|
||||||
RIGHT = 114
|
RIGHT = 114
|
||||||
F2 = 68
|
F2 = 68
|
||||||
|
SPACE = 65
|
||||||
DELETE = 119
|
DELETE = 119
|
||||||
BACK_SPACE = 22
|
BACK_SPACE = 22
|
||||||
CTRL_L = 37
|
CTRL_L = 37
|
||||||
@@ -75,15 +81,23 @@ MOVE_KEYS = (KeyboardKey.UP, KeyboardKey.PAGE_UP, KeyboardKey.DOWN, KeyboardKey.
|
|||||||
KeyboardKey.END, KeyboardKey.HOME_KP, KeyboardKey.END_KP, KeyboardKey.PAGE_UP_KP, KeyboardKey.PAGE_DOWN_KP)
|
KeyboardKey.END, KeyboardKey.HOME_KP, KeyboardKey.END_KP, KeyboardKey.PAGE_UP_KP, KeyboardKey.PAGE_DOWN_KP)
|
||||||
|
|
||||||
|
|
||||||
|
class FavClickMode(IntEnum):
|
||||||
|
""" Double click mode on the service in the bouquet(FAV) list. """
|
||||||
|
DISABLED = 0
|
||||||
|
STREAM = 1
|
||||||
|
PLAY = 2
|
||||||
|
ZAP = 3
|
||||||
|
|
||||||
|
|
||||||
class ViewTarget(Enum):
|
class ViewTarget(Enum):
|
||||||
""" Used for set target view """
|
""" Used for set target view. """
|
||||||
BOUQUET = 0
|
BOUQUET = 0
|
||||||
FAV = 1
|
FAV = 1
|
||||||
SERVICES = 2
|
SERVICES = 2
|
||||||
|
|
||||||
|
|
||||||
class BqGenType(Enum):
|
class BqGenType(Enum):
|
||||||
""" Bouquet generation type """
|
""" Bouquet generation type. """
|
||||||
SAT = 0
|
SAT = 0
|
||||||
EACH_SAT = 1
|
EACH_SAT = 1
|
||||||
PACKAGE = 2
|
PACKAGE = 2
|
||||||
@@ -129,6 +143,11 @@ class Column(IntEnum):
|
|||||||
FAV_PICON = 8
|
FAV_PICON = 8
|
||||||
FAV_TOOLTIP = 9
|
FAV_TOOLTIP = 9
|
||||||
FAV_BACKGROUND = 10
|
FAV_BACKGROUND = 10
|
||||||
|
# bouquets view
|
||||||
|
BQ_NAME = 0
|
||||||
|
BQ_LOCKED = 1
|
||||||
|
BQ_HIDDEN = 2
|
||||||
|
BQ_TYPE = 3
|
||||||
|
|
||||||
def __index__(self):
|
def __index__(self):
|
||||||
""" Overridden to get the index in slices directly """
|
""" Overridden to get the index in slices directly """
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
VER="0.4.3_Pre-alpha"
|
VER="0.4.4_Pre-alpha"
|
||||||
B_PATH="dist/DemonEditor"
|
B_PATH="dist/DemonEditor"
|
||||||
DEB_PATH="$B_PATH/usr/share/demoneditor"
|
DEB_PATH="$B_PATH/usr/share/demoneditor"
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ Enigma2 channel and satellites list editor for GNU/Linux.
|
|||||||
|
|
||||||
Experimental support of Neutrino-MP or others on the same basis (BPanther, etc).
|
Experimental support of Neutrino-MP or others on the same basis (BPanther, etc).
|
||||||
Focused on the convenience of working in lists from the keyboard. The mouse is also fully supported (Drag and Drop etc)
|
Focused on the convenience of working in lists from the keyboard. The mouse is also fully supported (Drag and Drop etc)
|
||||||
Keyboard shortcuts:
|
|
||||||
|
|
||||||
|
Keyboard shortcuts:
|
||||||
Ctrl + Insert - copies the selected channels from the main list to the the bouquet beginning
|
Ctrl + Insert - copies the selected channels from the main list to the the bouquet beginning
|
||||||
or inserts (creates) a new bouquet.
|
or inserts (creates) a new bouquet.
|
||||||
Ctrl + BackSpace - copies the selected channels from the main list to the bouquet end.
|
Ctrl + BackSpace - copies the selected channels from the main list to the bouquet end.
|
||||||
@@ -24,18 +24,18 @@ Keyboard shortcuts:
|
|||||||
Space - select/deselect.
|
Space - select/deselect.
|
||||||
Left/Right - remove selection.
|
Left/Right - remove selection.
|
||||||
Ctrl + Up, Down, PageUp, PageDown, Home, End - move selected items in the list.
|
Ctrl + Up, Down, PageUp, PageDown, Home, End - move selected items in the list.
|
||||||
|
Ctrl + O - (re)load user data from current dir.
|
||||||
|
Ctrl + D - load data from receiver.
|
||||||
|
Ctrl + U/B upload data/bouquets to receiver.
|
||||||
|
|
||||||
Extra:
|
Extra:
|
||||||
|
|
||||||
Multiple selections in lists only with Space key (as in file managers).
|
Multiple selections in lists only with Space key (as in file managers).
|
||||||
Ability to import IPTV into bouquet (Neutrino WEBTV) from m3u files.
|
Ability to import IPTV into bouquet (Neutrino WEBTV) from m3u files.
|
||||||
Ability to download picons and update satellites (transponders) from web.
|
Ability to download picons and update satellites (transponders) from web.
|
||||||
Preview (playing) IPTV or other streams directly from the bouquet list(should be installed VLC).
|
Preview (playing) IPTV or other streams directly from the bouquet list(should be installed VLC).
|
||||||
|
|
||||||
Minimum requirements:
|
Minimum requirements:
|
||||||
|
Python >= 3.5.2 and GTK+ >= 3.16 with PyGObject bindings.
|
||||||
Python >= 3.5.2 and GTK+ >= 3.16 with PyGObject bindings.
|
|
||||||
Launching
|
|
||||||
|
|
||||||
Terrestrial(DVB-T/T2) and cable channels are supported(Enigma2 only) with limitation!
|
Terrestrial(DVB-T/T2) and cable channels are supported(Enigma2 only) with limitation!
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
Package: DemonEditor
|
Package: DemonEditor
|
||||||
Version: 0.4.3-Pre-alpha
|
Version: 0.4.4-Pre-alpha
|
||||||
Section: utils
|
Section: utils
|
||||||
Priority: optional
|
Priority: optional
|
||||||
Architecture: all
|
Architecture: all
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ Source: https://github.com/DYefremov/DemonEditor
|
|||||||
Files: *
|
Files: *
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2018 Dmitriy Yefremov
|
Copyright (c) 2018-2019 Dmitriy Yefremov
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,7 +1,7 @@
|
|||||||
# Copyright (C) 2018 Frank Neirynck
|
# Copyright (C) 2018-2019 Frank Neirynck
|
||||||
# This file is distributed under the MIT license.
|
# This file is distributed under the MIT license.
|
||||||
#
|
#
|
||||||
#Frank Neirynck <frank@insink.be>, 2018.
|
# Frank Neirynck <frank@insink.be>, 2018-2019.
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -10,6 +10,11 @@ msgstr ""
|
|||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Project-Id-Version: \n"
|
||||||
|
"POT-Creation-Date: \n"
|
||||||
|
"PO-Revision-Date: \n"
|
||||||
|
"Language-Team: \n"
|
||||||
|
"X-Generator: Poedit 2.2.1\n"
|
||||||
|
|
||||||
msgid "translator-credits"
|
msgid "translator-credits"
|
||||||
msgstr "Frank Neirynck <frank@insink.be>"
|
msgstr "Frank Neirynck <frank@insink.be>"
|
||||||
@@ -336,8 +341,13 @@ msgstr "Recibir picons para proovedor"
|
|||||||
msgid "Load satellite providers."
|
msgid "Load satellite providers."
|
||||||
msgstr "Cargar proovedores Satélite."
|
msgstr "Cargar proovedores Satélite."
|
||||||
|
|
||||||
msgid "To automatically set the identifiers for picons,\nfirst load the required services list into the main application window."
|
msgid ""
|
||||||
msgstr "Para configurar automáticamente los identificadores para picons, \nprimero cargue la lista de serviços requeridos en la ventana principal."
|
"To automatically set the identifiers for picons,\n"
|
||||||
|
"first load the required services list into the main application window."
|
||||||
|
|
||||||
|
msgstr ""
|
||||||
|
"Para configurar automáticamente los identificadores para picons, \n"
|
||||||
|
"primero cargue la lista de serviços requeridos en la ventana principal."
|
||||||
|
|
||||||
# Satellites editor
|
# Satellites editor
|
||||||
msgid "Satellites edit tool"
|
msgid "Satellites edit tool"
|
||||||
@@ -384,8 +394,12 @@ msgstr "Datos servicio"
|
|||||||
msgid "Transponder details"
|
msgid "Transponder details"
|
||||||
msgstr "Detalles Transpondedor"
|
msgstr "Detalles Transpondedor"
|
||||||
|
|
||||||
msgid "Changes will be applied to all services of this transponder!\nContinue?"
|
msgid ""
|
||||||
msgstr "Los cambios se aplicarán a todos los servicios de este transpondedor!\nContinuar?"
|
"Changes will be applied to all services of this transponder!\n"
|
||||||
|
"Continue?"
|
||||||
|
msgstr ""
|
||||||
|
"Los cambios se aplicarán a todos los servicios de este transpondedor!\n"
|
||||||
|
"Continuar?"
|
||||||
|
|
||||||
msgid "Reference"
|
msgid "Reference"
|
||||||
msgstr "Referencia"
|
msgstr "Referencia"
|
||||||
@@ -434,7 +448,7 @@ msgstr "Restablecer a predeterminado"
|
|||||||
msgid "IPTV streams list configuration"
|
msgid "IPTV streams list configuration"
|
||||||
msgstr "Configurar lista de Secuencias IPTV"
|
msgstr "Configurar lista de Secuencias IPTV"
|
||||||
|
|
||||||
#Settings dialog
|
# Settings dialog
|
||||||
msgid "Preferences"
|
msgid "Preferences"
|
||||||
msgstr "Preferencias"
|
msgstr "Preferencias"
|
||||||
|
|
||||||
@@ -593,6 +607,9 @@ msgstr "Backup"
|
|||||||
msgid "Backups"
|
msgid "Backups"
|
||||||
msgstr "Backups"
|
msgstr "Backups"
|
||||||
|
|
||||||
|
msgid "Backup path:"
|
||||||
|
msgstr "Ruta del backup:"
|
||||||
|
|
||||||
msgid "Restore bouquets"
|
msgid "Restore bouquets"
|
||||||
msgstr "Restaurar ramos"
|
msgstr "Restaurar ramos"
|
||||||
|
|
||||||
@@ -614,8 +631,66 @@ msgstr "Marcado como nuevo:"
|
|||||||
msgid "With an extra name in the bouquet:"
|
msgid "With an extra name in the bouquet:"
|
||||||
msgstr "Con nombre adicional en ramo:"
|
msgstr "Con nombre adicional en ramo:"
|
||||||
|
|
||||||
|
msgid "Select"
|
||||||
|
msgstr "Seleccione"
|
||||||
|
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "Sobre"
|
msgstr "Sobre"
|
||||||
|
|
||||||
msgid "Exit"
|
msgid "Exit"
|
||||||
msgstr "Salir"
|
msgstr "Salir"
|
||||||
|
|
||||||
|
msgid "Tools"
|
||||||
|
msgstr "Herramientas"
|
||||||
|
|
||||||
|
# Import
|
||||||
|
msgid "Import"
|
||||||
|
msgstr "Importar"
|
||||||
|
|
||||||
|
msgid "Bouquet"
|
||||||
|
msgstr "Ramo"
|
||||||
|
|
||||||
|
msgid "Bouquets and services"
|
||||||
|
msgstr "Ramos y servicios"
|
||||||
|
|
||||||
|
msgid "The main list does not contain services for this bouquet!"
|
||||||
|
msgstr "La lista principal no contiene servicios para este ramo!"
|
||||||
|
|
||||||
|
msgid "No bouquet file is selected!"
|
||||||
|
msgstr "Nigún fichero de ramo ha sido seleccionado!"
|
||||||
|
|
||||||
|
msgid "Remove all unused"
|
||||||
|
msgstr "Quite todos los"
|
||||||
|
|
||||||
|
msgid "Test"
|
||||||
|
msgstr "Prueba"
|
||||||
|
|
||||||
|
msgid "Test connection"
|
||||||
|
msgstr "Probar conexión"
|
||||||
|
|
||||||
|
msgid "Double click on the service in the bouquet list:"
|
||||||
|
msgstr "Haga doble clic en el servicio en la lista de bouquet:"
|
||||||
|
|
||||||
|
msgid "Zap"
|
||||||
|
msgstr "Zapear"
|
||||||
|
|
||||||
|
msgid "Play stream"
|
||||||
|
msgstr "Reproducir secuencia"
|
||||||
|
|
||||||
|
msgid "Disabled"
|
||||||
|
msgstr "Desactivado"
|
||||||
|
|
||||||
|
msgid "Enable ver. 5 support (experimental)"
|
||||||
|
msgstr "Soporte para ver. 5 (experimental)"
|
||||||
|
|
||||||
|
msgid "Enable HTTP API (experimental)"
|
||||||
|
msgstr "Habilitar API HTTP (experimental)"
|
||||||
|
|
||||||
|
msgid "Switch(zap) the channel(Ctrl + Z)"
|
||||||
|
msgstr "Cambiar (ZAP) el canal (Ctrl + Z)"
|
||||||
|
|
||||||
|
msgid "Switch the channel and watch in the program(Ctrl + W)"
|
||||||
|
msgstr "Cambiar el canal y ver en el programa (Ctrl + W)"
|
||||||
|
|
||||||
|
msgid "Play IPTV or other stream in the program(Ctrl + P)"
|
||||||
|
msgstr "Reproducir IPTV u otro flujo en el programa (Ctrl + P)"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Copyright (C) 2018 Frank Neirynck
|
# Copyright (C) 2018-2019 Frank Neirynck
|
||||||
# This file is distributed under the MIT license.
|
# This file is distributed under the MIT license.
|
||||||
#
|
#
|
||||||
#Frank Neirynck <frank@insink.be>, 2018.
|
# Frank Neirynck <frank@insink.be>, 2018-2019.
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -10,6 +10,11 @@ msgstr ""
|
|||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Project-Id-Version: \n"
|
||||||
|
"POT-Creation-Date: \n"
|
||||||
|
"PO-Revision-Date: \n"
|
||||||
|
"Language-Team: \n"
|
||||||
|
"X-Generator: Poedit 2.2.1\n"
|
||||||
|
|
||||||
msgid "translator-credits"
|
msgid "translator-credits"
|
||||||
msgstr "Frank Neirynck <frank@insink.be>"
|
msgstr "Frank Neirynck <frank@insink.be>"
|
||||||
@@ -336,8 +341,12 @@ msgstr "Ontvang picons voor leveranciers"
|
|||||||
msgid "Load satellite providers."
|
msgid "Load satellite providers."
|
||||||
msgstr "Laad satelliet leveranciers."
|
msgstr "Laad satelliet leveranciers."
|
||||||
|
|
||||||
msgid "To automatically set the identifiers for picons,\nfirst load the required services list into the main application window."
|
msgid ""
|
||||||
msgstr "Om automatisch de ID in te stellen voor picons,\nlaad eerst de vereiste serviceslijst in via het hoofdvenster van het programma."
|
"To automatically set the identifiers for picons,\n"
|
||||||
|
"first load the required services list into the main application window."
|
||||||
|
msgstr ""
|
||||||
|
"Om automatisch de ID in te stellen voor picons,\n"
|
||||||
|
"laad eerst de vereiste serviceslijst in via het hoofdvenster van het programma."
|
||||||
|
|
||||||
# Satellites editor
|
# Satellites editor
|
||||||
msgid "Satellites edit tool"
|
msgid "Satellites edit tool"
|
||||||
@@ -384,8 +393,12 @@ msgstr "Gegevens Dienst"
|
|||||||
msgid "Transponder details"
|
msgid "Transponder details"
|
||||||
msgstr "Details Transponder"
|
msgstr "Details Transponder"
|
||||||
|
|
||||||
msgid "Changes will be applied to all services of this transponder!\nContinue?"
|
msgid ""
|
||||||
msgstr "Wijzigingen zullen worden doorgevoerd op alle diensten van deze transponder!\nDoorgaan?"
|
"Changes will be applied to all services of this transponder!\n"
|
||||||
|
"Continue?"
|
||||||
|
msgstr ""
|
||||||
|
"Wijzigingen zullen worden doorgevoerd op alle diensten van deze transponder!\n"
|
||||||
|
"Doorgaan?"
|
||||||
|
|
||||||
msgid "Reference"
|
msgid "Reference"
|
||||||
msgstr "Referentie"
|
msgstr "Referentie"
|
||||||
@@ -434,7 +447,7 @@ msgstr "Reset naar standaard"
|
|||||||
msgid "IPTV streams list configuration"
|
msgid "IPTV streams list configuration"
|
||||||
msgstr "Configureren IPTV Streamlijst"
|
msgstr "Configureren IPTV Streamlijst"
|
||||||
|
|
||||||
#Settings dialog
|
# Settings dialog
|
||||||
msgid "Preferences"
|
msgid "Preferences"
|
||||||
msgstr "Voorkeuren"
|
msgstr "Voorkeuren"
|
||||||
|
|
||||||
@@ -593,8 +606,11 @@ msgstr "Backup"
|
|||||||
msgid "Backups"
|
msgid "Backups"
|
||||||
msgstr "Backups"
|
msgstr "Backups"
|
||||||
|
|
||||||
|
msgid "Backup path:"
|
||||||
|
msgstr "Backup pad:"
|
||||||
|
|
||||||
msgid "Restore bouquets"
|
msgid "Restore bouquets"
|
||||||
msgstr "Herstek boeketten"
|
msgstr "Herstel boeketten"
|
||||||
|
|
||||||
msgid "Restore all"
|
msgid "Restore all"
|
||||||
msgstr "Herstel alles"
|
msgstr "Herstel alles"
|
||||||
@@ -614,8 +630,66 @@ msgstr "Gemarkeerd als nieuw:"
|
|||||||
msgid "With an extra name in the bouquet:"
|
msgid "With an extra name in the bouquet:"
|
||||||
msgstr "Met een extra naam in het boeket:"
|
msgstr "Met een extra naam in het boeket:"
|
||||||
|
|
||||||
|
msgid "Select"
|
||||||
|
msgstr "Over"
|
||||||
|
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "Over"
|
msgstr "Over"
|
||||||
|
|
||||||
msgid "Exit"
|
msgid "Exit"
|
||||||
msgstr "Exit"
|
msgstr "Exit"
|
||||||
|
|
||||||
|
msgid "Tools"
|
||||||
|
msgstr "Tools"
|
||||||
|
|
||||||
|
# Import
|
||||||
|
msgid "Import"
|
||||||
|
msgstr "Importeer"
|
||||||
|
|
||||||
|
msgid "Bouquet"
|
||||||
|
msgstr "Boeket"
|
||||||
|
|
||||||
|
msgid "Bouquets and services"
|
||||||
|
msgstr "Boeketten en diensten"
|
||||||
|
|
||||||
|
msgid "The main list does not contain services for this bouquet!"
|
||||||
|
msgstr "De hoofdlijst bevat geen diensten voor dit boeket!"
|
||||||
|
|
||||||
|
msgid "No bouquet file is selected!"
|
||||||
|
msgstr "Geen boeket geselecteerd!"
|
||||||
|
|
||||||
|
msgid "Remove all unused"
|
||||||
|
msgstr "Verwijder alle ongebruikte"
|
||||||
|
|
||||||
|
msgid "Test"
|
||||||
|
msgstr "Test"
|
||||||
|
|
||||||
|
msgid "Test connection"
|
||||||
|
msgstr "Test verbinding"
|
||||||
|
|
||||||
|
msgid "Double click on the service in the bouquet list:"
|
||||||
|
msgstr "Dubbelklik op de dienst in de boeket lijst:"
|
||||||
|
|
||||||
|
msgid "Zap"
|
||||||
|
msgstr "Zap"
|
||||||
|
|
||||||
|
msgid "Play stream"
|
||||||
|
msgstr "Speel stream af"
|
||||||
|
|
||||||
|
msgid "Disabled"
|
||||||
|
msgstr "Uitgeschakeld"
|
||||||
|
|
||||||
|
msgid "Enable ver. 5 support (experimental)"
|
||||||
|
msgstr "Ondersteuning voor ver. 5 inschakelen (experimenteel)"
|
||||||
|
|
||||||
|
msgid "Enable HTTP API (experimental)"
|
||||||
|
msgstr "HTTP API inschakelen (experimenteel)"
|
||||||
|
|
||||||
|
msgid "Switch(zap) the channel(Ctrl + Z)"
|
||||||
|
msgstr "Schakelaar (ZAP) naar het kanaal (CTRL + Z)"
|
||||||
|
|
||||||
|
msgid "Switch the channel and watch in the program(Ctrl + W)"
|
||||||
|
msgstr "Schakel het kanaal in en bekijk het programma (CTRL + W)"
|
||||||
|
|
||||||
|
msgid "Play IPTV or other stream in the program(Ctrl + P)"
|
||||||
|
msgstr "Speel IPTV of andere stream af en bekijk het programma (CTRL + P)"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Copyright (C) 2018 Frank Neirynck
|
# Copyright (C) 2018-2019 Frank Neirynck
|
||||||
# This file is distributed under the MIT license.
|
# This file is distributed under the MIT license.
|
||||||
#
|
#
|
||||||
#Frank Neirynck <frank@insink.be>, 2018.
|
#Frank Neirynck <frank@insink.be>, 2018-2019.
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -593,6 +593,9 @@ msgstr "Backup"
|
|||||||
msgid "Backups"
|
msgid "Backups"
|
||||||
msgstr "Backups"
|
msgstr "Backups"
|
||||||
|
|
||||||
|
msgid "Backup path:"
|
||||||
|
msgstr "Rota do backup:"
|
||||||
|
|
||||||
msgid "Restore bouquets"
|
msgid "Restore bouquets"
|
||||||
msgstr "Restaurar ramos"
|
msgstr "Restaurar ramos"
|
||||||
|
|
||||||
@@ -614,8 +617,66 @@ msgstr "Marcado como novo:"
|
|||||||
msgid "With an extra name in the bouquet:"
|
msgid "With an extra name in the bouquet:"
|
||||||
msgstr "Com nome adicional em ramo:"
|
msgstr "Com nome adicional em ramo:"
|
||||||
|
|
||||||
|
msgid "Select"
|
||||||
|
msgstr "Selecione"
|
||||||
|
|
||||||
msgid "About"
|
msgid "About"
|
||||||
msgstr "Acerca"
|
msgstr "Acerca"
|
||||||
|
|
||||||
msgid "Exit"
|
msgid "Exit"
|
||||||
msgstr "Sair"
|
msgstr "Sair"
|
||||||
|
|
||||||
|
msgid "Tools"
|
||||||
|
msgstr "Tools"
|
||||||
|
|
||||||
|
#Import
|
||||||
|
msgid "Import"
|
||||||
|
msgstr "Importar"
|
||||||
|
|
||||||
|
msgid "Bouquet"
|
||||||
|
msgstr "Ramo"
|
||||||
|
|
||||||
|
msgid "Bouquets and services"
|
||||||
|
msgstr "Ramos e serviços"
|
||||||
|
|
||||||
|
msgid "The main list does not contain services for this bouquet!"
|
||||||
|
msgstr "A lista pricipal no tem serviços em esta ramo!"
|
||||||
|
|
||||||
|
msgid "No bouquet file is selected!"
|
||||||
|
msgstr "Nemhuma ficheiro de ramo foi selecionado!"
|
||||||
|
|
||||||
|
msgid "Remove all unused"
|
||||||
|
msgstr "Remova todos os não utilizados"
|
||||||
|
|
||||||
|
msgid "Test"
|
||||||
|
msgstr "Test"
|
||||||
|
|
||||||
|
msgid "Test connection"
|
||||||
|
msgstr "Testar a conexão"
|
||||||
|
|
||||||
|
msgid "Double click on the service in the bouquet list:"
|
||||||
|
msgstr "Clique duas vezes no serviço na lista de ramos:"
|
||||||
|
|
||||||
|
msgid "Zap"
|
||||||
|
msgstr "Zap"
|
||||||
|
|
||||||
|
msgid "Play stream"
|
||||||
|
msgstr "Play stream"
|
||||||
|
|
||||||
|
msgid "Disabled"
|
||||||
|
msgstr "Desativado"
|
||||||
|
|
||||||
|
msgid "Enable ver. 5 support (experimental)"
|
||||||
|
msgstr "Ativar ver. 5 suporte (experimental)"
|
||||||
|
|
||||||
|
msgid "Enable HTTP API (experimental)"
|
||||||
|
msgstr "Ativar HTTP API (experimental)"
|
||||||
|
|
||||||
|
msgid "Switch(zap) the channel(Ctrl + Z)"
|
||||||
|
msgstr "Mudar(zap) o canal(Ctrl + Z)"
|
||||||
|
|
||||||
|
msgid "Switch the channel and watch in the program(Ctrl + W)"
|
||||||
|
msgstr "Troque o canal e ver no programa(Ctrl + W)."
|
||||||
|
|
||||||
|
msgid "Play IPTV or other stream in the program(Ctrl + P)"
|
||||||
|
msgstr "Tocar IPTV ou outro fluxo no programa(Ctrl + P)"
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
# Copyright (C) 2018 Dmitriy Yefremov
|
# Copyright (C) 2018-2019 Dmitriy Yefremov
|
||||||
# This file is distributed under the MIT license.
|
# This file is distributed under the MIT license.
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Last-Translator: Dmitry Yefremov\n"
|
"Last-Translator: Dmitriy Yefremov\n"
|
||||||
"Language: ru\n"
|
"Language: ru\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
@@ -625,6 +625,67 @@ msgstr "О программе"
|
|||||||
msgid "Exit"
|
msgid "Exit"
|
||||||
msgstr "Выход"
|
msgstr "Выход"
|
||||||
|
|
||||||
|
msgid "Tools"
|
||||||
|
msgstr "Инструменты"
|
||||||
|
|
||||||
|
#Import
|
||||||
|
msgid "Import"
|
||||||
|
msgstr "Импорт"
|
||||||
|
|
||||||
|
msgid "Bouquet"
|
||||||
|
msgstr "Букета"
|
||||||
|
|
||||||
|
msgid "Bouquets and services"
|
||||||
|
msgstr "Букетов и сервисов"
|
||||||
|
|
||||||
|
msgid "The main list does not contain services for this bouquet!"
|
||||||
|
msgstr "Основной список не содержит сервисов для данного букета!"
|
||||||
|
|
||||||
|
msgid "No bouquet file is selected!"
|
||||||
|
msgstr "Не выбран файл букета!"
|
||||||
|
|
||||||
|
msgid "Remove all unused"
|
||||||
|
msgstr "Удалить все неиспользуемые"
|
||||||
|
|
||||||
|
msgid "Test"
|
||||||
|
msgstr "Тестировать"
|
||||||
|
|
||||||
|
msgid "Test connection"
|
||||||
|
msgstr "Тестировать соединение"
|
||||||
|
|
||||||
|
msgid "Double click on the service in the bouquet list:"
|
||||||
|
msgstr "Двойной клик по сервису в списке букетов:"
|
||||||
|
|
||||||
|
msgid "Zap"
|
||||||
|
msgstr "Переключить"
|
||||||
|
|
||||||
|
msgid "Play stream"
|
||||||
|
msgstr "Воспр. потока"
|
||||||
|
|
||||||
|
msgid "Disabled"
|
||||||
|
msgstr "Выкл."
|
||||||
|
|
||||||
|
msgid "Enable ver. 5 support (experimental)"
|
||||||
|
msgstr "Включить поддержку вер. 5 (экспериментально)"
|
||||||
|
|
||||||
|
msgid "Enable HTTP API (experimental)"
|
||||||
|
msgstr "Включить HTTP API (экспериментально)"
|
||||||
|
|
||||||
|
msgid "Switch(zap) the channel(Ctrl + Z)"
|
||||||
|
msgstr "Переключить канал(Ctrl + Z)"
|
||||||
|
|
||||||
|
msgid "Switch the channel and watch in the program(Ctrl + W)"
|
||||||
|
msgstr "Переклють канал и просмотр в программе(Ctrl + W)."
|
||||||
|
|
||||||
|
msgid "Play IPTV or other stream in the program(Ctrl + P)"
|
||||||
|
msgstr "Воспроизведение IPTV или другого потока в программе(Ctrl + P)"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user