Compare commits

...

29 Commits
0.2.0 ... 0.2.2

Author SHA1 Message Date
Dmitriy Yefremov
d9390aa7be Update README.md 2018-01-26 21:26:03 +03:00
Dmitriy Yefremov
e12cc86e5f Update readme 2018-01-26 21:21:40 +03:00
DYefremov
f1ef9fe4aa decoupling deletion, deletion with considering filter 2018-01-26 15:15:39 +03:00
Dmitriy Yefremov
728bfd0b20 added remove selection keys 2018-01-25 21:43:48 +03:00
Dmitriy Yefremov
1d6022b6db fix lock\hide 2018-01-25 21:05:24 +03:00
DYefremov
8609d30ac9 bouquets fix, new implementation of services filter 2018-01-25 16:11:52 +03:00
DYefremov
fde06dca89 filter revert 2018-01-24 13:39:11 +03:00
Dmitriy Yefremov
e41bf5f58f little gui changes 2018-01-24 00:05:15 +03:00
Dmitriy Yefremov
b1488df9ce little gui changes 2018-01-23 22:58:43 +03:00
DYefremov
c6e4b3624b services filter skeleton 2018-01-23 16:18:28 +03:00
DYefremov
26b843921b force ctrl for fav and services lists 2018-01-22 14:51:34 +03:00
Dmitriy Yefremov
e73638d006 resize option for picons 2018-01-20 22:17:18 +03:00
Dmitriy Yefremov
cf3c05f324 mkdir if not exist for picons 2018-01-20 14:04:07 +03:00
Dmitriy Yefremov
030b7c4957 upload data fix 2018-01-20 11:29:34 +03:00
Dmitriy Yefremov
d7ed3e20a4 Update README.md 2018-01-19 13:15:49 +03:00
Dmitriy Yefremov
c69b0ac9e1 neutrino fav id fix 2018-01-19 11:15:35 +03:00
Dmitriy Yefremov
c5c88a8958 telnet options 2018-01-18 12:38:58 +03:00
Dmitriy Yefremov
24c064b450 telnet options 2018-01-18 00:57:58 +03:00
Dmitriy Yefremov
240d724b59 picons name format for neutrino 2018-01-17 01:18:02 +03:00
Dmitriy Yefremov
5b410241a9 upload picons impl 2018-01-16 18:51:08 +03:00
Dmitriy Yefremov
a6ffe4999a termination of process for picons 2018-01-16 12:11:54 +03:00
Dmitriy Yefremov
f67a79e869 base implementation of picons parser 2018-01-16 01:16:03 +03:00
Dmitriy Yefremov
d37c088112 load providers skeleton for picons 2018-01-15 14:56:17 +03:00
Dmitriy Yefremov
adf117c88d picons parser skeleton 2018-01-12 14:32:36 +03:00
Dmitriy Yefremov
98da7acd96 changes in dialogues 2018-01-11 17:59:59 +03:00
Dmitriy Yefremov
c82763081a added telnet options 2018-01-10 22:13:25 +03:00
Dmitriy Yefremov
1a39557964 properties for picons 2018-01-10 18:09:44 +03:00
Dmitriy Yefremov
c274c9e91d skeleton for picons dialog 2018-01-10 12:15:41 +03:00
Dmitriy Yefremov
dd1ec89592 GUI skeleton for picons 2018-01-08 22:00:48 +03:00
20 changed files with 1815 additions and 261 deletions

View File

@@ -1,8 +1,8 @@
[Desktop Entry]
Version=1.0
Name=DemonEditor
Comment=Channels and satellites editor for Enigma2
Comment[ru]=Редактор каналов и спутников для Enigma2
Comment=Channels and satellites list editor for Enigma2
Comment[ru]=Редактор списка каналов и спутников для Enigma2
Icon=accessories-text-editor
Exec=bash -c 'cd $(dirname %k) && ./start.py'
Terminal=false

View File

@@ -5,16 +5,21 @@ 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)
Keyboard shortcuts:
Ctrl + X, C, V, Up, Down, PageUp, PageDown, S, T, E, L, H, Space; Insert, Delete, F2.
Ctrl + X, C, V, Up, Down, PageUp, PageDown, S, T, E, L, H, Space; Insert, Delete, F2.
Insert - copies the selected channels from the main list to the bouquet or inserts (creates) a new bouquet.
Ctrl + X - only in bouquet list. Ctrl + C - only in services list.
Clipboard is "rubber". There is an accumulation before the insertion!
Ctrl + E, F2 - edit/rename.
Ctrl + S, T, E in Satellites edit tool for create and edit satellite or transponder.
Ctrl + L - parental lock.
Ctrl + L - parental lock.
Ctrl + H - hide/skip.
Left/Right - remove selection.
Ability to import IPTV into bouquet from m3u files!
Multiple selections in lists only with Space key (as in file managers)!
Extra:
Ability to import IPTV into bouquet from m3u files(Enigma2 only)!
Tool for downloading picons from lyngsat.com.
Tests only in image based on OpenPLi or last BPanther(neutrino) images with GM 990 Spark Reloaded receiver
in my preferred linux distro (Last Linux Mint 18.* - MATE 64-bit)!

View File

@@ -1,7 +1,6 @@
""" Module for parsing bouquets """
from app.eparser.ecommons import BqServiceType, BouquetService, Bouquets, Bouquet
_BOUQUETS_PATH = "../data/"
_TV_ROOT_FILE_NAME = "bouquets.tv"
_RADIO_ROOT_FILE_NAME = "bouquets.radio"

View File

@@ -9,7 +9,6 @@ from .blacklist import get_blacklist
from ..ecommons import Service, POLARIZATION, SYSTEM, FEC, SERVICE_TYPE, FLAG
_HEADER = "eDVB services /4/"
_FILE_PATH = "../data/lamedb"
_SEP = ":" # separator
_FILE_NAME = "lamedb"

View File

@@ -4,7 +4,7 @@ from enum import Enum
from xml.dom.minidom import parse, Document
from app.ui import LOCKED_ICON, HIDE_ICON
from ..ecommons import Bouquets, Bouquet, BouquetService, BqServiceType
from ..ecommons import Bouquets, Bouquet, BouquetService, BqServiceType, PROVIDER
_FILE = "bouquets.xml"
_U_FILE = "ubouquets.xml"
@@ -40,7 +40,8 @@ def parse_bouquets(file, name, bq_type):
if srv_elem.hasAttributes():
ssid = srv_elem.attributes["i"].value
on = srv_elem.attributes["on"].value
fav_id = "{}:{}".format(on, ssid)
tr_id = srv_elem.attributes["t"].value
fav_id = "{}:{}:{}".format(tr_id, on, ssid)
services.append(BouquetService(None, BqServiceType.DEFAULT, fav_id, 0))
bouquets[2].append(Bouquet(name=bq_name,
type=bq_type,
@@ -48,6 +49,15 @@ def parse_bouquets(file, name, bq_type):
locked=LOCKED_ICON if locked == "1" else None,
hidden=HIDE_ICON if hidden == "1" else None))
if BqType(bq_type) is BqType.BOUQUET:
for bq in bouquets.bouquets:
if bq.services:
name = bq.name
name = name[name.index("]") + 1:]
key = int(bq.services[0].data.split(":")[1], 16)
if key not in PROVIDER:
PROVIDER[key] = name
return bouquets
@@ -78,11 +88,11 @@ def write_bouquet(file, bouquet):
root.appendChild(bq_elem)
for srv in bq.services:
on, sep, ssid = srv.fav_id.partition(":")
tr_id, on, ssid = srv.fav_id.split(":")
srv_elem = doc.createElement("S")
srv_elem.setAttribute("i", ssid)
srv_elem.setAttribute("n", srv.service)
srv_elem.setAttribute("t", srv.transponder.split(":")[0].lstrip("0"))
srv_elem.setAttribute("t", tr_id)
srv_elem.setAttribute("on", on)
srv_elem.setAttribute("s", srv.pos.replace(".", ""))
srv_elem.setAttribute("frq", srv.freq[:-3])

View File

@@ -117,6 +117,9 @@ def parse_transponder(api, sat, sat_pos, services, tr_elem):
tr = "{}:{}:{}:{}:{}:{}:{}:{}:{}".format(tr_id, on, freq, inv, rate, fec, pol, mod, sys)
tr_id = tr_id.lstrip("0")
on = on.lstrip("0")
for srv_elem in tr_elem.getElementsByTagName("S"):
if srv_elem.hasAttributes():
ssid = srv_elem.attributes["i"].value
@@ -128,7 +131,6 @@ def parse_transponder(api, sat, sat_pos, services, tr_elem):
f = srv_elem.attributes.get("f")
f = f.value if f else f
v, a, p, pmt, tx, vt = [None] * 6
# For v3 is possible so: '<S i="0001" n="name" t="1" s="0" num="770" f="4"/>' (equals v4 api)
if api == "3" and len(srv_elem.attributes) > 6:
v = srv_elem.attributes["v"].value
@@ -139,7 +141,7 @@ def parse_transponder(api, sat, sat_pos, services, tr_elem):
vt = srv_elem.attributes["vt"].value
data_id = "{}:{}:{}:{}:{}:{}:{}:{}:{}:{}:{}".format(api, srv_type, sys, num, f, v, a, p, pmt, tx, vt)
fav_id = "{}:{}".format(on.lstrip("0"), ssid.lstrip("0"))
fav_id = "{}:{}:{}".format(tr_id, on, ssid.lstrip("0"))
srv = Service(flags_cas=sat,
transponder_type=None,

View File

@@ -2,7 +2,7 @@ import os
import socket
import time
from enum import Enum
from ftplib import FTP
from ftplib import FTP, error_perm
from telnetlib import Telnet
from app.commons import log
@@ -16,9 +16,10 @@ class DownloadDataType(Enum):
ALL = 0
BOUQUETS = 1
SATELLITES = 2
PICONS = 3
def download_data(*, properties, download_type=DownloadDataType.ALL):
def download_data(*, properties, download_type=DownloadDataType.ALL, callback=None):
with FTP(host=properties["host"]) as ftp:
ftp.login(user=properties["user"], passwd=properties["password"])
save_path = properties["data_dir_path"]
@@ -48,13 +49,17 @@ def download_data(*, properties, download_type=DownloadDataType.ALL):
with open(save_path + xml_file, 'wb') as f:
ftp.retrbinary("RETR " + xml_file, f.write)
if callback is not None:
callback()
def upload_data(*, properties, download_type=DownloadDataType.ALL, remove_unused=False, profile=Profile.ENIGMA_2):
def upload_data(*, properties, download_type=DownloadDataType.ALL, remove_unused=False, profile=Profile.ENIGMA_2,
callback=None):
data_path = properties["data_dir_path"]
host = properties["host"]
# telnet
tn = telnet(host=host, user=None if profile is Profile.ENIGMA_2 else "root", password=None,
timeout=5 if profile is Profile.ENIGMA_2 else 1)
tn = telnet(host=host, user=properties.get("telnet_user", "root"), password=properties.get("telnet_password", ""),
timeout=properties.get("telnet_timeout", 5))
next(tn)
# terminate enigma or enigma
tn.send("init 4")
@@ -83,10 +88,38 @@ def upload_data(*, properties, download_type=DownloadDataType.ALL, remove_unused
for file_name in os.listdir(data_path):
if file_name == "satellites.xml":
continue
file_name, send_file(file_name, data_path, ftp)
if file_name.endswith(__DATA_FILES_LIST):
send_file(file_name, data_path, ftp)
if download_type is DownloadDataType.PICONS:
picons_dir_path = properties.get("picons_dir_path")
picons_path = properties.get("picons_path")
try:
ftp.cwd(picons_path)
except error_perm as e:
if str(e).startswith("550"):
ftp.mkd(picons_path) # if not exist
ftp.cwd(picons_path)
files = []
ftp.dir(files.append)
picons_suf = (".jpg", ".png")
for file in files:
name = str(file).strip()
if name.endswith(picons_suf):
name = name.split()[-1]
ftp.delete(name)
for file_name in os.listdir(picons_dir_path):
if file_name.endswith(picons_suf):
send_file(file_name, picons_dir_path, ftp)
# resume enigma or restart neutrino
tn.send("init 3" if profile is Profile.ENIGMA_2 else "init 6")
if callback is not None:
callback()
def send_file(file_name, path, ftp):
""" Opens the file in binary mode and transfers into receiver """
@@ -94,7 +127,7 @@ def send_file(file_name, path, ftp):
return ftp.storbinary("STOR " + file_name, f)
def telnet(host, port=23, user=None, password=None, timeout=5):
def telnet(host, port=23, user="", password="", timeout=5):
try:
tn = Telnet(host=host, port=port, timeout=timeout)
except socket.timeout:
@@ -102,11 +135,11 @@ def telnet(host, port=23, user=None, password=None, timeout=5):
else:
time.sleep(1)
command = yield
if user is not None:
if user != "":
tn.read_until(b"login: ")
tn.write(user.encode("utf-8") + b"\n")
time.sleep(timeout)
if password is not None:
if password != "":
tn.read_until(b"Password: ")
tn.write(password.encode("utf-8") + b"\n")
time.sleep(timeout)

0
app/picons/__init__.py Normal file
View File

169
app/picons/picons.py Normal file
View File

@@ -0,0 +1,169 @@
import os
import shutil
from collections import namedtuple
from html.parser import HTMLParser
from app.commons import log
from app.properties import Profile
Provider = namedtuple("Provider", ["logo", "name", "url", "on_id", "selected"])
Picon = namedtuple("Picon", ["ref", "ssid", "v_pid"])
class PiconsParser(HTMLParser):
""" Parser for package html page. (https://www.lyngsat.com/packages/*provider-name*.html) """
def __init__(self, entities=False, separator=' '):
HTMLParser.__init__(self)
self._parse_html_entities = entities
self._separator = separator
self._is_td = False
self._is_th = False
self._current_row = []
self._current_cell = []
self.picons = []
def handle_starttag(self, tag, attrs):
if tag == 'td':
self._is_td = True
if tag == 'th':
self._is_th = True
if tag == "img":
self._current_row.append(attrs[0][1])
def handle_data(self, data):
""" Save content to a cell """
if self._is_td or self._is_th:
self._current_cell.append(data.strip())
def handle_endtag(self, tag):
if tag == 'td':
self._is_td = False
elif tag == 'th':
self._is_th = False
if tag in ('td', 'th'):
final_cell = self._separator.join(self._current_cell).strip()
self._current_row.append(final_cell)
self._current_cell = []
elif tag == 'tr':
row = self._current_row
ln = len(row)
if 9 < ln < 13:
url = None
if row[0].startswith("../logo/"):
url = row[0]
elif row[1].startswith("../logo/"):
url = row[1]
ssid = row[-4]
if url and len(ssid) > 2:
self.picons.append(Picon(url, ssid, row[-3]))
self._current_row = []
def error(self, message):
pass
@staticmethod
def parse(open_path, picons_path, tmp_path, on_id, profile=Profile.ENIGMA_2):
with open(open_path, encoding="utf-8", errors="replace") as f:
parser = PiconsParser()
parser.reset()
parser.feed(f.read())
picons = parser.picons
if picons:
os.makedirs(picons_path, exist_ok=True)
for p in picons:
try:
picon_file_name = picons_path + PiconsParser.format(p.ssid, on_id, p.v_pid, profile)
shutil.copyfile(tmp_path + "www.lyngsat.com/" + p.ref.lstrip("."), picon_file_name)
except (TypeError, ValueError) as e:
log("Picons format parse error: {} {} {}".format(p.ref, p.ssid, p.v_pid) + "\n" + str(e))
print(e)
@staticmethod
def format(ssid, on_id, v_pid, profile: Profile):
tr_id = int(ssid[:-2] if len(ssid) < 4 else ssid[:2])
if profile is Profile.ENIGMA_2:
return "1_0_{}_{:X}_{:X}_{:X}_1680000_0_0_0.png".format(1 if v_pid else 2, int(ssid), tr_id, int(on_id))
elif profile is Profile.NEUTRINO_MP:
return "{:x}{:04x}{:04x}.png".format(tr_id, int(on_id), int(ssid))
else:
return "{}.png".format(ssid)
class ProviderParser(HTMLParser):
""" Parser for satellite html page. (https://www.lyngsat.com/*sat-name*.html) """
def __init__(self, entities=False, separator=' '):
HTMLParser.__init__(self)
self._ON_ID_BLACK_LIST = ("65535", "?", "0", "1")
self._parse_html_entities = entities
self._separator = separator
self._is_td = False
self._is_th = False
self._is_provider = False
self._current_row = []
self._current_cell = []
self.rows = []
self._ids = set()
def handle_starttag(self, tag, attrs):
if tag == 'td':
self._is_td = True
if tag == 'tr':
self._is_th = True
if tag == "img":
if attrs[0][1].startswith("logo/"):
self._current_row.append(attrs[0][1])
if tag == "a":
if "https://www.lyngsat.com/packages/" in attrs[0][1]:
self._current_row.append(attrs[0][1])
def handle_data(self, data):
""" Save content to a cell """
if self._is_td or self._is_th:
self._current_cell.append(data.strip())
def handle_endtag(self, tag):
if tag == 'td':
self._is_td = False
elif tag == 'tr':
self._is_th = False
if tag in ('td', 'th'):
final_cell = self._separator.join(self._current_cell).strip()
self._current_row.append(final_cell)
self._current_cell = []
elif tag == 'tr':
row = self._current_row
if len(row) == 12:
on_id, sep, tid = str(row[-2]).partition("-")
if tid and on_id not in self._ON_ID_BLACK_LIST and on_id not in self._ids:
row[-2] = on_id
self.rows.append(row)
self._ids.add(on_id)
self._current_row = []
def error(self, message):
pass
def parse_providers(open_path):
with open(open_path, encoding="utf-8", errors="replace") as f:
parser = ProviderParser()
parser.reset()
parser.feed(f.read())
rows = parser.rows
if rows:
return [Provider(logo=r[2], name=r[5], url=r[6], on_id=r[-2], selected=True) for r in rows]
if __name__ == "__main__":
pass

View File

@@ -41,17 +41,25 @@ def get_default_settings():
Profile.ENIGMA_2.value: {
"host": "127.0.0.1", "port": "21",
"user": "root", "password": "root",
"telnet_user": "", "telnet_password": "",
"telnet_port": "21", "telnet_timeout": 5,
"services_path": "/etc/enigma2/",
"user_bouquet_path": "/etc/enigma2/",
"satellites_xml_path": "/etc/tuxbox/",
"data_dir_path": DATA_PATH + "enigma2/"},
"picons_path": "/usr/share/enigma2/picon",
"data_dir_path": DATA_PATH + "enigma2/",
"picons_dir_path": DATA_PATH + "enigma2/picons/"},
Profile.NEUTRINO_MP.value: {
"host": "127.0.0.1", "port": "21",
"user": "root", "password": "root",
"telnet_user": "root", "telnet_password": "",
"telnet_port": "21", "telnet_timeout": 1,
"services_path": "/var/tuxbox/config/zapit/",
"user_bouquet_path": "/var/tuxbox/config/zapit/",
"satellites_xml_path": "/var/tuxbox/config/",
"data_dir_path": DATA_PATH + "neutrino/"},
"picons_path": "/usr/share/tuxbox/neutrino/icons/logo/",
"data_dir_path": DATA_PATH + "neutrino/",
"picons_dir_path": DATA_PATH + "neutrino/picons/"},
"profile": Profile.ENIGMA_2.value}

View File

@@ -9,7 +9,7 @@
<property name="icon_name">system-help</property>
<property name="type_hint">normal</property>
<property name="program_name">DemonEditor</property>
<property name="version">0.2.0 Pre-alpha</property>
<property name="version">0.2.2 Pre-alpha</property>
<property name="copyright" translatable="yes">2018 Dmitriy Yefremov
dmitry.v.yefremov@gmail.com
</property>
@@ -116,6 +116,7 @@ dmitry.v.yefremov@gmail.com
<property name="max_width_chars">10</property>
<property name="text" translatable="yes">127.0.0.1</property>
<property name="caps_lock_warning">False</property>
<property name="primary_icon_name">network-transmit-receive-symbolic</property>
</object>
<packing>
<property name="left_attach">0</property>
@@ -196,7 +197,6 @@ dmitry.v.yefremov@gmail.com
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="xalign">0</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">satellites_radio_button</property>
</object>
@@ -213,7 +213,6 @@ dmitry.v.yefremov@gmail.com
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="xalign">0</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">all_radio_button</property>
</object>
@@ -223,6 +222,9 @@ dmitry.v.yefremov@gmail.com
<property name="position">3</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
@@ -603,6 +605,13 @@ dmitry.v.yefremov@gmail.com
</object>
</child>
</object>
<object class="GtkAdjustment" id="telnet_timeout_adjustment">
<property name="lower">1</property>
<property name="upper">11</property>
<property name="value">1</property>
<property name="step_increment">1</property>
<property name="page_increment">10</property>
</object>
<object class="GtkDialog" id="settings_dialog">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Options</property>
@@ -626,11 +635,13 @@ dmitry.v.yefremov@gmail.com
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="cancel_button">
<property name="label">gtk-undo</property>
<property name="label">gtk-cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="margin_right">10</property>
<property name="use_stock">True</property>
<property name="always_show_image">True</property>
</object>
<packing>
<property name="expand">True</property>
@@ -638,6 +649,22 @@ dmitry.v.yefremov@gmail.com
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button5">
<property name="label">gtk-apply</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="apply_settings" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="ok_button">
<property name="label">gtk-ok</property>
@@ -645,6 +672,7 @@ dmitry.v.yefremov@gmail.com
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<property name="always_show_image">True</property>
</object>
<packing>
<property name="expand">True</property>
@@ -656,109 +684,249 @@ dmitry.v.yefremov@gmail.com
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
<property name="position">6</property>
</packing>
</child>
<child>
<object class="GtkGrid" id="grid1">
<object class="GtkNotebook" id="notebook">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="column_spacing">1</property>
<property name="column_homogeneous">True</property>
<property name="can_focus">True</property>
<child>
<object class="GtkGrid" id="ftp_settings_grid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="column_spacing">2</property>
<property name="column_homogeneous">True</property>
<child>
<object class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Host:</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="host_field">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="text" translatable="yes">127.0.0.1</property>
<property name="primary_icon_name">network-transmit-receive-symbolic</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label13">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Login:</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label14">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Password:</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="port_field">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="text" translatable="yes">21</property>
<property name="primary_icon_name">network-workgroup-symbolic</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label15">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Port:</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="login_field">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="text" translatable="yes">root</property>
<property name="primary_icon_name">avatar-default-symbolic</property>
<property name="primary_icon_activatable">False</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">3</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="password_field">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="visibility">False</property>
<property name="invisible_char">●</property>
<property name="text" translatable="yes">root</property>
<property name="primary_icon_name">emblem-readonly</property>
<property name="primary_icon_activatable">False</property>
<property name="input_purpose">password</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">3</property>
</packing>
</child>
</object>
</child>
<child type="tab">
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Host:</property>
<property name="label" translatable="yes">FTP</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
<property name="tab_fill">False</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="host_field">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="text" translatable="yes">127.0.0.1</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label3">
<object class="GtkGrid" id="telnet_settings_grid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Login:</property>
<property name="column_spacing">2</property>
<property name="column_homogeneous">True</property>
<child>
<object class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Port:</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="telnet_password_field">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="primary_icon_name">emblem-readonly</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">3</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="telnet_login_field">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="primary_icon_name">avatar-default-symbolic</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label16">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Loggin:</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label17">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Password:</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="telnet_port_field">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="text" translatable="yes">23</property>
<property name="primary_icon_name">network-workgroup-symbolic</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label19">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Timeout:</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="telnet_timeout_spin_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip_text" translatable="yes">Timeout between commands in seconds</property>
<property name="max_length">2</property>
<property name="primary_icon_name">alarm-symbolic</property>
<property name="input_purpose">number</property>
<property name="adjustment">telnet_timeout_adjustment</property>
<property name="numeric">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Password:</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="port_field">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="text" translatable="yes">21</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<child type="tab">
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Port:</property>
<property name="label" translatable="yes">Telnet</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
<property name="position">1</property>
<property name="tab_fill">False</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="login_field">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="text" translatable="yes">root</property>
<property name="primary_icon_name">avatar-default-symbolic</property>
<property name="primary_icon_activatable">False</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">3</property>
</packing>
<placeholder/>
</child>
<child>
<object class="GtkEntry" id="password_field">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="visibility">False</property>
<property name="invisible_char">●</property>
<property name="text" translatable="yes">root</property>
<property name="primary_icon_name">emblem-readonly</property>
<property name="primary_icon_activatable">False</property>
<property name="input_purpose">password</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">3</property>
</packing>
<child type="tab">
<placeholder/>
</child>
</object>
<packing>
@@ -794,6 +962,7 @@ dmitry.v.yefremov@gmail.com
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Services and Bouquets files:</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
@@ -816,6 +985,7 @@ dmitry.v.yefremov@gmail.com
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">User bouquet files:</property>
<property name="xalign">2.2351741291171123e-10</property>
</object>
<packing>
<property name="left_attach">0</property>
@@ -838,6 +1008,7 @@ dmitry.v.yefremov@gmail.com
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Satellites.xml file:</property>
<property name="xalign">0.019999999552965164</property>
</object>
<packing>
<property name="left_attach">0</property>
@@ -855,6 +1026,29 @@ dmitry.v.yefremov@gmail.com
<property name="top_attach">5</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label20">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Picons:</property>
<property name="xalign">2.2351741291171123e-10</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">6</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="picons_field">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="text" translatable="yes">/usr/share/enigma2/picon</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">7</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
@@ -973,29 +1167,31 @@ dmitry.v.yefremov@gmail.com
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label8">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Data dir:</property>
<property name="lines">0</property>
<property name="xalign">0.019999999552965164</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkGrid" id="grid3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="column_homogeneous">True</property>
<child>
<object class="GtkLabel" id="label8">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Data directory:</property>
<property name="lines">0</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="data_dir_field">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="text" translatable="yes">/data</property>
<property name="secondary_icon_stock">gtk-open</property>
<property name="secondary_icon_name">folder-open-symbolic</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_tooltip_text" translatable="yes">Select</property>
<property name="secondary_icon_tooltip_markup" translatable="yes">Select</property>
@@ -1003,7 +1199,7 @@ dmitry.v.yefremov@gmail.com
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
</object>
@@ -1025,6 +1221,33 @@ dmitry.v.yefremov@gmail.com
<property name="position">6</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label18">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Picons dir:</property>
<property name="xalign">0.019999999552965164</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">8</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="picons_dir_field">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="text" translatable="yes">/data/picons</property>
<property name="secondary_icon_name">folder-open-symbolic</property>
<signal name="icon-press" handler="on_picons_dir_field_icon_press" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">9</property>
</packing>
</child>
</object>
</child>
<action-widgets>

View File

@@ -60,7 +60,7 @@ class DownloadDialog:
def destroy(self):
self._dialog.destroy()
def on_info_bar_close(self, *args):
def on_info_bar_close(self, bar=None, resp=None):
self._info_bar.set_visible(False)
@run_idle
@@ -75,12 +75,12 @@ class DownloadDialog:
upload_data(properties=self._properties,
download_type=d_type,
remove_unused=self._remove_unused_check_button.get_active(),
profile=self._profile)
profile=self._profile,
callback=lambda: self.show_info_message("Done!", Gtk.MessageType.INFO))
except Exception as e:
message = str(getattr(e, "message", str(e)))
self.show_info_message(message, Gtk.MessageType.ERROR)
else:
self.show_info_message("Done!", Gtk.MessageType.INFO)
if download and d_type is not DownloadDataType.SATELLITES:
self._open_data()

View File

@@ -2,7 +2,7 @@ import os
from contextlib import suppress
from functools import lru_cache
from app.commons import run_idle
from app.commons import run_idle, log
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.ecommons import CAS, FLAG
@@ -12,7 +12,8 @@ from . import Gtk, Gdk, UI_RESOURCES_PATH, LOCKED_ICON, HIDE_ICON
from .dialogs import show_dialog, DialogType
from .download_dialog import show_download_dialog
from .main_helper import edit_marker, insert_marker, move_items, edit, ViewTarget, set_flags, locate_in_services, \
scroll_to
scroll_to, get_base_model
from .picons_dialog import PiconsDialog
from .satellites_dialog import show_satellites_dialog
from .settings_dialog import show_settings_dialog
@@ -23,7 +24,7 @@ class MainAppWindow:
_BOUQUETS_LIST_NAME = "bouquets_tree_store"
# dynamically active elements depending on the selected view
_SERVICE_ELEMENTS = ("copy_tool_button", "to_fav_tool_button", "copy_menu_item", "services_to_fav_move_popup_item",
"services_edit_popup_item", "services_copy_popup_item")
"services_edit_popup_item", "services_copy_popup_item", "filter_entry")
_BOUQUET_ELEMENTS = ("edit_tool_button", "new_tool_button",
"bouquets_new_popup_item", "bouquets_edit_popup_item")
@@ -50,7 +51,7 @@ class MainAppWindow:
"bouquets_remove_popup_item", "fav_remove_popup_item", "hide_tool_button",
"import_m3u_tool_button", "fav_import_m3u_popup_item", "fav_insert_marker_popup_item",
"fav_edit_marker_popup_item", "fav_edit_popup_item", "fav_locate_popup_item",
"services_copy_popup_item")
"services_copy_popup_item", "filter_entry")
def __init__(self):
handlers = {"on_close_main_window": self.on_quit,
@@ -88,20 +89,23 @@ class MainAppWindow:
"on_insert_marker": self.on_insert_marker,
"on_edit_marker": self.on_edit_marker,
"on_fav_popup": self.on_fav_popup,
"on_locate_in_services": self.on_locate_in_services}
"on_locate_in_services": self.on_locate_in_services,
"on_picons_loader_show": self.on_picons_loader_show,
"on_filter_changed": self.on_filter_changed}
self.__options = get_config()
self.__profile = self.__options.get("profile")
os.makedirs(os.path.dirname(self.__options.get(self.__profile).get("data_dir_path")), exist_ok=True)
# Used for copy/paste. When adding the previous data will not be deleted.
# Clearing only after the insertion!
self.__rows_buffer = []
self.__services = {}
self.__bouquets = {}
self.__bouquets_to_del = []
self.__blacklist = set()
builder = Gtk.Builder()
builder.add_from_file(UI_RESOURCES_PATH + "main_window.glade")
builder.connect_signals(handlers)
self.__main_window = builder.get_object("main_window")
main_window_size = self.__options.get("window_size", None)
# Setting the last size of the window if it was saved
@@ -126,8 +130,14 @@ class MainAppWindow:
self.__radio_count_label = builder.get_object("radio_count_label")
self.__data_count_label = builder.get_object("data_count_label")
self.__fav_edit_marker_popup_item = builder.get_object("fav_edit_marker_popup_item")
builder.connect_signals(handlers)
# Filter
self.__services_model_filter = builder.get_object("services_model_filter")
self.__services_model_filter.set_visible_func(self.services_filter_function)
self.__filter_entry = builder.get_object("filter_entry")
self.init_drag_and_drop() # drag and drop
# Force ctrl press event for view. Multiple selections in lists only with Space key(as in file managers)!!!
self.__services_view.connect("key-press-event", self.force_ctrl)
self.__fav_view.connect("key-press-event", self.force_ctrl)
self.__main_window.show()
def init_drag_and_drop(self):
@@ -144,6 +154,10 @@ class MainAppWindow:
self.__services_view.drag_source_set_target_list(None)
self.__services_view.drag_source_add_text_targets()
def force_ctrl(self, view, event):
""" Function for force ctrl press event for view """
event.state |= Gdk.ModifierType.CONTROL_MASK
def on_quit(self, *args):
""" Called before app quit """
write_config(self.__options) # storing current config
@@ -208,7 +222,8 @@ class MainAppWindow:
self.on_view_focus(view, None)
def on_edit(self, view):
name = view.get_model().get_name()
model = get_base_model(view.get_model())
name = model.get_name()
if name == self._BOUQUETS_LIST_NAME:
self.on_bouquets_edit(view)
# edit(view, self.__main_window, ViewTarget.BOUQUET)
@@ -226,36 +241,41 @@ class MainAppWindow:
if view.is_focus():
selection = view.get_selection()
model, paths = selection.get_selected_rows()
model_name = model.get_name()
model_name = get_base_model(model).get_name()
itrs = [model.get_iter(path) for path in paths]
rows = [model.get(in_itr, *[x for x in range(model.get_n_columns())]) for in_itr in itrs]
rows = [model[in_itr][:] for in_itr in itrs]
bq_selected = self.is_bouquet_selected()
fav_bouquet = None
if bq_selected:
fav_bouquet = self.__bouquets.get(bq_selected, None)
for itr in itrs:
if fav_bouquet and model_name == self._FAV_LIST_NAME:
del fav_bouquet[int(model.get_path(itr)[0])]
if model_name == self._BOUQUETS_LIST_NAME:
if len(model.get_path(itr)) < 2:
show_dialog(DialogType.ERROR, self.__main_window, "This item is not allowed to be removed!")
return
else:
self.delete_bouquet(bq_selected)
model.remove(itr)
if model_name == self._FAV_LIST_NAME:
self.update_fav_num_column(model)
self.remove_favs(fav_bouquet, itrs, model)
elif model_name == self._BOUQUETS_LIST_NAME:
self.delete_bouquets(itrs, model, bq_selected)
elif model_name == self._SERVICE_LIST_NAME:
self.delete_services(bq_selected, rows)
self.delete_services(bq_selected, itrs, model, rows)
self.on_view_focus(view, None)
return rows
def delete_services(self, bq_selected, rows):
def remove_favs(self, fav_bouquet, itrs, model):
""" Deleting bouquet services """
if fav_bouquet:
for itr in itrs:
del fav_bouquet[int(model.get_path(itr)[0])]
self.__fav_model.remove(itr)
self.update_fav_num_column(model)
def delete_services(self, bq_selected, itrs, model, rows):
""" Deleting services """
srv_itrs = [self.__services_model_filter.convert_iter_to_child_iter(
model.convert_iter_to_child_iter(itr)) for itr in itrs]
for s_itr in srv_itrs:
self.__services_model.remove(s_itr)
for row in rows:
# There are channels with the same parameters except for the name.
# None because it can have duplicates! Need fix
@@ -271,13 +291,16 @@ class MainAppWindow:
if bq_selected:
self.update_bouquet_channels(self.__fav_model, None, bq_selected)
def delete_bouquet(self, bouquet):
""" Deleting bouquet """
self.__bouquets.pop(bouquet)
self.__fav_model.clear()
profile = Profile(self.__profile)
if profile is Profile.ENIGMA_2:
self.__bouquets_to_del.append(self.get_bouquet_file_name(bouquet))
def delete_bouquets(self, itrs, model, bouquet):
""" Deleting bouquets """
for itr in itrs:
if len(model.get_path(itr)) < 2:
show_dialog(DialogType.ERROR, self.__main_window, "This item is not allowed to be removed!")
return
else:
self.__bouquets.pop(bouquet)
self.__fav_model.clear()
self.__bouquets_model.remove(itr)
def get_bouquet_file_name(self, bouquet):
bouquet_file_name = "{}userbouquet.{}.{}".format(self.__options.get(self.__profile).get("data_dir_path"),
@@ -290,7 +313,8 @@ class MainAppWindow:
if paths:
itr = model.get_iter(paths[0])
bq_type = model.get_value(itr, 1)
bq_type = model.get_value(itr, 3)
bq_name = "bouquet"
count = 0
key = "{}:{}".format(bq_name, bq_type)
@@ -338,14 +362,11 @@ class MainAppWindow:
itr = model.get_iter(paths[0])
bq_name, bq_type = model.get(itr, 0, 3)
response = show_dialog(DialogType.INPUT, self.__main_window, bq_name)
if response == Gtk.ResponseType.CANCEL:
return
model.set_value(itr, 0, response)
self.__bouquets["{}:{}".format(response, bq_type)] = self.__bouquets.pop("{}:{}".format(bq_name, bq_type))
if Profile(self.__profile) is Profile.ENIGMA_2:
self.__bouquets_to_del.append(self.get_bouquet_file_name(bq_selected))
def on_to_fav_move(self, view):
""" Move items from app to fav list """
@@ -357,6 +378,8 @@ class MainAppWindow:
def get_selection(self, view):
""" Creates a string from the iterators of the selected rows """
model, paths = view.get_selection().get_selected_rows()
if model.get_model(): # needs think about it !
model = model.get_model().get_model()
if len(paths) > 0:
itrs = [model.get_iter(path) for path in paths]
@@ -370,7 +393,7 @@ class MainAppWindow:
show_dialog(DialogType.ERROR, self.__main_window, "Error. No bouquet is selected!")
return
model = view.get_model()
model = get_base_model(view.get_model())
dest_index = 0
if drop_info:
@@ -388,8 +411,7 @@ class MainAppWindow:
if source == self._SERVICE_LIST_NAME:
ext_model = self.__services_view.get_model()
ext_itrs = [ext_model.get_iter_from_string(itr) for itr in itrs]
ext_rows = [ext_model.get(ext_itr, *[x for x in range(ext_model.get_n_columns())]) for
ext_itr in ext_itrs]
ext_rows = [ext_model[ext_itr][:] for ext_itr in ext_itrs]
dest_index -= 1
for ext_row in ext_rows:
dest_index += 1
@@ -400,7 +422,7 @@ class MainAppWindow:
fav_bouquet.insert(dest_index, channel.fav_id)
elif source == self._FAV_LIST_NAME:
in_itrs = [model.get_iter_from_string(itr) for itr in itrs]
in_rows = [model.get(in_itr, *[x for x in range(model.get_n_columns())]) for in_itr in in_itrs]
in_rows = [model[in_itr][:] for in_itr in in_itrs]
for row in in_rows:
model.insert(dest_index, row)
fav_bouquet.insert(dest_index, row[4])
@@ -448,7 +470,7 @@ class MainAppWindow:
def on_data_open(self, model):
response = show_dialog(DialogType.CHOOSER, self.__main_window, options=self.__options.get(self.__profile))
if response == Gtk.ResponseType.CANCEL:
if response in (Gtk.ResponseType.CANCEL, Gtk.ResponseType.DELETE_EVENT):
return
self.open_data(response)
@@ -460,8 +482,8 @@ class MainAppWindow:
data_path = self.__options.get(self.__profile).get("data_dir_path") if data_path is None else data_path
try:
self.append_blacklist(data_path)
self.append_services(data_path)
self.append_bouquets(data_path)
self.append_services(data_path)
self.update_services_counts(len(self.__services_model))
except FileNotFoundError as e:
show_dialog(DialogType.ERROR, self.__main_window, getattr(e, "message", str(e)) +
@@ -493,14 +515,18 @@ class MainAppWindow:
self.__bouquets["{}:{}".format(name, bt_type)] = services
def append_services(self, data_path):
services = get_services(data_path, Profile(self.__profile))
if services:
for srv in services:
# adding channels to dict with fav_id as keys
self.__services[srv.fav_id] = srv
self.__services_model.append(srv)
else:
try:
services = get_services(data_path, Profile(self.__profile))
except Exception as e:
print(e)
log("Append services error: " + str(e))
show_dialog(DialogType.ERROR, self.__main_window, "Error opening data!")
else:
if services:
for srv in services:
# adding channels to dict with fav_id as keys
self.__services[srv.fav_id] = srv
self.__services_model.append(srv)
def clear_current_data(self):
""" Clearing current data from lists """
@@ -511,29 +537,32 @@ class MainAppWindow:
self.__services.clear()
self.__rows_buffer.clear()
self.__bouquets.clear()
self.__bouquets_to_del.clear()
def on_data_save(self, *args):
if show_dialog(DialogType.QUESTION, self.__main_window) == Gtk.ResponseType.CANCEL:
return
path = self.__options.get(self.__profile).get("data_dir_path")
# deleting files in data dir(skipping dirs) :)
list(map(os.unlink, (os.path.join(path, f) for f in filter(
lambda f: f != "satellites.xml" and os.path.isfile(os.path.join(path, f)), os.listdir(path)))))
bouquets = []
services_model = self.__services_view.get_model()
def parse_bouquets(model, b_path, itr):
bqs = None
if model.iter_has_child(itr):
num_of_children = model.iter_n_children(itr)
bqs = []
num_of_children = model.iter_n_children(itr)
for num in range(num_of_children):
bq_itr = model.iter_nth_child(itr, num)
bq_name, locked, hidden, bq_type = model.get(bq_itr, 0, 1, 2, 3)
favs = self.__bouquets["{}:{}".format(bq_name, bq_type)]
bq = Bouquet(bq_name, bq_type, [self.__services.get(f_id, None) for f_id in favs], locked, hidden)
bqs.append(bq)
bqs = Bouquets(*model.get(itr, 0, 3), bqs)
bouquets.append(bqs)
if len(b_path) == 1:
bouquets.append(Bouquets(*model.get(itr, 0, 3), bqs if bqs else []))
profile = Profile(self.__profile)
# Getting bouquets
@@ -544,10 +573,6 @@ class MainAppWindow:
write_services(path, services, profile)
# removing bouquet files
if profile is profile.ENIGMA_2:
for bqf in self.__bouquets_to_del:
with suppress(FileNotFoundError):
os.remove(bqf)
self.__bouquets_to_del.clear()
# blacklist
write_blacklist(path, self.__blacklist)
@@ -611,6 +636,7 @@ class MainAppWindow:
for v in [view, *args]:
v.get_selection().unselect_all()
@run_idle
def on_preferences(self, item):
response = show_settings_dialog(self.__main_window, self.__options)
if response != Gtk.ResponseType.CANCEL:
@@ -627,7 +653,8 @@ class MainAppWindow:
key = event.keyval
ctrl = event.state & Gdk.ModifierType.CONTROL_MASK
alt = event.state & Gdk.ModifierType.MOD1_MASK
model_name = view.get_model().get_name()
model = get_base_model(view.get_model())
model_name = model.get_name()
if key == Gdk.KEY_Delete:
self.on_delete(view)
@@ -636,7 +663,7 @@ class MainAppWindow:
elif ctrl and key in (Gdk.KEY_Down, Gdk.KEY_Page_Down, Gdk.KEY_KP_Page_Down):
self.move_items(key)
elif model_name == self._FAV_LIST_NAME and key == Gdk.KEY_Control_L or key == Gdk.KEY_Control_R:
self.update_fav_num_column(view.get_model())
self.update_fav_num_column(model)
self.update_bouquet_list()
elif key == Gdk.KEY_Insert:
# Move items from app to fav list
@@ -661,6 +688,8 @@ class MainAppWindow:
self.on_edit(view)
elif key == Gdk.KEY_space and model_name == self._FAV_LIST_NAME:
pass
elif key == Gdk.KEY_Left or key == Gdk.KEY_Right:
view.do_unselect_all(view)
def on_download(self, item):
show_download_dialog(transient=self.__main_window,
@@ -671,7 +700,7 @@ class MainAppWindow:
@run_idle
def on_view_focus(self, view, focus_event):
profile = Profile(self.__profile)
model = view.get_model()
model = get_base_model(view.get_model())
model_name = model.get_name()
not_empty = len(model) > 0 # if > 0 model has items
@@ -799,6 +828,20 @@ class MainAppWindow:
def on_locate_in_services(self, view):
locate_in_services(view, self.__services_view, self.__main_window)
def on_picons_loader_show(self, item):
dialog = PiconsDialog(self.__main_window, self.__options.get(self.__profile), Profile(self.__profile))
dialog.show()
@run_idle
def on_filter_changed(self, entry):
self.__services_model_filter.refilter()
def services_filter_function(self, model, iter, data):
if self.__services_model_filter is None or self.__services_model_filter == "None":
return True
else:
return self.__filter_entry.get_text() in str(model.get(iter, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14))
def start_app():
MainAppWindow()

View File

@@ -94,6 +94,7 @@ def move_items(key, view):
def edit(view, parent_window, target, fav_view=None, service_view=None, channels=None):
model, paths = view.get_selection().get_selected_rows()
model = get_base_model(model)
if not paths:
return
@@ -157,16 +158,18 @@ def set_flags(flag, services_view, fav_view, channels, blacklist):
if not paths:
return
model = get_base_model(model)
if flag is FLAG.HIDE:
if target is ViewTarget.SERVICES:
set_hide(channels, model, paths)
else:
fav_ids = [model.get_value(model.get_iter(path), 7) for path in paths]
srv_model = services_view.get_model()
srv_model = get_base_model(services_view.get_model())
srv_paths = [row.path for row in srv_model if row[16] in fav_ids]
set_hide(channels, srv_model, srv_paths)
elif flag is FLAG.LOCK:
set_lock(blacklist, channels, model, paths, target, services_model=services_view.get_model())
set_lock(blacklist, channels, model, paths, target, services_model=get_base_model(services_view.get_model()))
return True
@@ -272,5 +275,23 @@ def scroll_to(index, view, paths=None):
selection.select_path(index)
# ***************** Others *********************#
def update_entry_data(entry, dialog, options):
""" Updates value in text entry from chooser dialog """
response = show_dialog(dialog_type=DialogType.CHOOSER, transient=dialog, options=options)
if response not in (Gtk.ResponseType.CANCEL, Gtk.ResponseType.DELETE_EVENT):
entry.set_text(response)
return response
return False
def get_base_model(model):
""" Returns base tree model if has wrappers ("TreeModelSort" and "TreeModelFilter") """
if type(model) is Gtk.TreeModelSort:
return model.get_model().get_model()
return model
if __name__ == "__main__":
pass

View File

@@ -83,7 +83,7 @@
<object class="GtkImage" id="image4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">applications-utilities</property>
<property name="icon_name">edit-select-all</property>
</object>
<object class="GtkImage" id="image5">
<property name="visible">True</property>
@@ -219,6 +219,11 @@
</object>
</child>
</object>
<object class="GtkImage" id="image8">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">insert-image</property>
</object>
<object class="GtkImage" id="send_recive_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
@@ -265,6 +270,12 @@
</columns>
<signal name="row-deleted" handler="on_model_changed" swapped="no"/>
</object>
<object class="GtkTreeModelFilter" id="services_model_filter">
<property name="child_model">services_list_store</property>
</object>
<object class="GtkTreeModelSort" id="services_model_tree_model_sort">
<property name="model">services_model_filter</property>
</object>
<object class="GtkApplicationWindow" id="main_window">
<property name="width_request">640</property>
<property name="can_focus">False</property>
@@ -411,6 +422,17 @@
<signal name="activate" handler="on_satellite_editor_show" swapped="no"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="Picons loader">
<property name="label" translatable="yes">Picons loader</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="image">image8</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_picons_loader_show" swapped="no"/>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="menuitem5">
<property name="visible">True</property>
@@ -531,6 +553,38 @@
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkSeparatorToolItem" id="separatortoolitem8">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">False</property>
</packing>
</child>
<child>
<object class="GtkToolItem" id="filter_tool_item">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkEntry" id="filter_entry">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="tooltip_text" translatable="yes">Services filter</property>
<property name="primary_icon_name">edit-select-all-symbolic</property>
<property name="primary_icon_activatable">False</property>
<property name="primary_icon_tooltip_text" translatable="yes">Services filter</property>
<signal name="changed" handler="on_filter_changed" swapped="no"/>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">False</property>
</packing>
</child>
<child>
<object class="GtkSeparatorToolItem" id="toolbutton4">
<property name="visible">True</property>
@@ -571,6 +625,7 @@
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Up</property>
<property name="label" translatable="yes">Up</property>
<property name="use_underline">True</property>
<property name="stock_id">gtk-go-up</property>
@@ -586,6 +641,7 @@
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Down</property>
<property name="label" translatable="yes">Down</property>
<property name="use_underline">True</property>
<property name="stock_id">gtk-go-down</property>
@@ -724,7 +780,7 @@
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Rename bouquet</property>
<property name="tooltip_text" translatable="yes">Edit</property>
<property name="label" translatable="yes">Edit </property>
<property name="use_underline">True</property>
<property name="stock_id">gtk-edit</property>
@@ -735,43 +791,6 @@
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkSeparatorToolItem" id="separatortoolitem4">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">False</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="import_m3u_tool_button">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Import m3u file</property>
<property name="opacity">0.93999999999999995</property>
<property name="label" translatable="yes">IPTV</property>
<property name="use_underline">True</property>
<property name="icon_name">emblem-downloads</property>
<signal name="clicked" handler="on_import_m3u" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkSeparatorToolItem" id="separatortoolitem7">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">False</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="remove_tool_button">
<property name="visible">True</property>
@@ -788,19 +807,20 @@
</packing>
</child>
<child>
<object class="GtkSeparatorToolItem" id="toolbutton9">
<object class="GtkSeparatorToolItem" id="separatortoolitem4">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
<property name="homogeneous">False</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="preferences_tool_button">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Settings</property>
<property name="label" translatable="yes">Preferences</property>
<property name="use_underline">True</property>
<property name="stock_id">gtk-preferences</property>
@@ -812,13 +832,23 @@
</packing>
</child>
<child>
<object class="GtkToolButton" id="tools_button">
<object class="GtkSeparatorToolItem" id="separatortoolitem7">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">False</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="satellites_editor_tool_button">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Satellites editor</property>
<property name="label" translatable="yes">Tools</property>
<property name="label" translatable="yes">Satellites editor</property>
<property name="use_underline">True</property>
<property name="icon_name">applications-utilities</property>
<property name="icon_name">edit-select-all</property>
<signal name="clicked" handler="on_satellite_editor_show" swapped="no"/>
</object>
<packing>
@@ -826,6 +856,38 @@
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="picons_download_tool_button">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Picons</property>
<property name="label" translatable="yes">Picons loader</property>
<property name="use_underline">True</property>
<property name="icon_name">insert-image</property>
<signal name="clicked" handler="on_picons_loader_show" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="import_m3u_tool_button">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Import m3u file</property>
<property name="opacity">0.93999999999999995</property>
<property name="label" translatable="yes">IPTV</property>
<property name="use_underline">True</property>
<property name="icon_name">emblem-downloads</property>
<signal name="clicked" handler="on_import_m3u" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkSeparatorToolItem" id="toolbutton11">
<property name="visible">True</property>
@@ -869,7 +931,7 @@
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">2</property>
<property name="position">2</property>
<property name="position">3</property>
</packing>
</child>
<child>
@@ -877,8 +939,8 @@
<property name="height_request">250</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="margin_left">2</property>
<property name="margin_right">2</property>
<property name="margin_left">1</property>
<property name="margin_right">1</property>
<property name="wide_handle">True</property>
<child>
<object class="GtkBox" id="box4">
@@ -901,12 +963,13 @@
<object class="GtkScrolledWindow" id="services_scrolled_window">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="margin_bottom">2</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTreeView" id="services_tree_view">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="model">services_list_store</property>
<property name="model">services_model_tree_model_sort</property>
<property name="search_column">3</property>
<property name="rubber_banding">True</property>
<property name="enable_grid_lines">both</property>
@@ -949,6 +1012,7 @@
<object class="GtkTreeViewColumn" id="service_column">
<property name="resizable">True</property>
<property name="spacing">2</property>
<property name="min_width">50</property>
<property name="title" translatable="yes">Service</property>
<property name="expand">True</property>
<property name="reorderable">True</property>
@@ -982,7 +1046,7 @@
<child>
<object class="GtkTreeViewColumn" id="package_column">
<property name="resizable">True</property>
<property name="sizing">autosize</property>
<property name="min_width">50</property>
<property name="title" translatable="yes">Package</property>
<property name="expand">True</property>
<property name="reorderable">True</property>
@@ -998,6 +1062,7 @@
<child>
<object class="GtkTreeViewColumn" id="service_type_column">
<property name="resizable">True</property>
<property name="min_width">25</property>
<property name="title" translatable="yes">Type</property>
<property name="expand">True</property>
<property name="reorderable">True</property>
@@ -1015,6 +1080,7 @@
<child>
<object class="GtkTreeViewColumn" id="ssid_column">
<property name="resizable">True</property>
<property name="min_width">25</property>
<property name="title" translatable="yes">Ssid</property>
<property name="expand">True</property>
<property name="reorderable">True</property>
@@ -1032,6 +1098,7 @@
<child>
<object class="GtkTreeViewColumn" id="freq_column">
<property name="resizable">True</property>
<property name="min_width">25</property>
<property name="title" translatable="yes">Freq</property>
<property name="expand">True</property>
<property name="reorderable">True</property>
@@ -1049,6 +1116,7 @@
<child>
<object class="GtkTreeViewColumn" id="rate_column">
<property name="resizable">True</property>
<property name="min_width">25</property>
<property name="title" translatable="yes">Rate</property>
<property name="expand">True</property>
<property name="reorderable">True</property>
@@ -1066,6 +1134,7 @@
<child>
<object class="GtkTreeViewColumn" id="pol_column">
<property name="resizable">True</property>
<property name="min_width">25</property>
<property name="title" translatable="yes">Pol</property>
<property name="expand">True</property>
<property name="reorderable">True</property>
@@ -1083,6 +1152,7 @@
<child>
<object class="GtkTreeViewColumn" id="fec_column">
<property name="resizable">True</property>
<property name="min_width">25</property>
<property name="title" translatable="yes">FEC</property>
<property name="expand">True</property>
<property name="reorderable">True</property>
@@ -1100,6 +1170,7 @@
<child>
<object class="GtkTreeViewColumn" id="system_column">
<property name="resizable">True</property>
<property name="min_width">25</property>
<property name="title" translatable="yes">System</property>
<property name="expand">True</property>
<property name="reorderable">True</property>
@@ -1117,6 +1188,7 @@
<child>
<object class="GtkTreeViewColumn" id="pos_column">
<property name="resizable">True</property>
<property name="min_width">25</property>
<property name="title" translatable="yes">Pos</property>
<property name="expand">True</property>
<property name="sort_column_id">14</property>
@@ -1177,7 +1249,7 @@
</child>
<child>
<object class="GtkBox" id="services_bar_box">
<property name="height_request">25</property>
<property name="height_request">20</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="resize_mode">queue</property>
@@ -1200,12 +1272,14 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">CAS</property>
<property name="width_chars">10</property>
<property name="width_chars">20</property>
<property name="max_width_chars">20</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">2</property>
<property name="position">1</property>
</packing>
</child>
@@ -1299,6 +1373,19 @@
<property name="position">8</property>
</packing>
</child>
<child>
<object class="GtkSeparator" id="separator2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">5</property>
<property name="position">9</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
@@ -1338,6 +1425,7 @@
<object class="GtkScrolledWindow" id="scrolledwindow2">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="margin_bottom">2</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTreeView" id="fav_tree_view">
@@ -1458,7 +1546,7 @@
</child>
<child>
<object class="GtkBox" id="fav_bar_box">
<property name="height_request">25</property>
<property name="height_request">20</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">2</property>
@@ -1479,7 +1567,8 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">0</property>
<property name="width_chars">10</property>
<property name="width_chars">15</property>
<property name="max_width_chars">15</property>
<property name="xalign">0</property>
</object>
<packing>
@@ -1525,6 +1614,7 @@
<object class="GtkScrolledWindow" id="scrolledwindow3">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="margin_bottom">2</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTreeView" id="bouquets_tree_view">
@@ -1595,7 +1685,7 @@
</child>
<child>
<object class="GtkBox" id="bouquet_bar_box">
<property name="height_request">25</property>
<property name="height_request">20</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">2</property>
@@ -1616,7 +1706,8 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">0</property>
<property name="width_chars">5</property>
<property name="width_chars">10</property>
<property name="max_width_chars">10</property>
<property name="xalign">0</property>
</object>
<packing>
@@ -1652,7 +1743,7 @@
<property name="expand">True</property>
<property name="fill">True</property>
<property name="padding">1</property>
<property name="position">3</property>
<property name="position">4</property>
</packing>
</child>
<child>
@@ -1665,7 +1756,7 @@
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">2</property>
<property name="position">4</property>
<property name="position">5</property>
</packing>
</child>
<child>
@@ -1674,8 +1765,6 @@
<property name="can_focus">False</property>
<property name="margin_start">10</property>
<property name="margin_end">10</property>
<property name="margin_top">6</property>
<property name="margin_bottom">6</property>
<property name="spacing">2</property>
<property name="homogeneous">True</property>
<child>
@@ -1718,7 +1807,7 @@
<object class="GtkLabel" id="ver_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Ver. 0.2.0 Pre-alpha</property>
<property name="label" translatable="yes">Ver. 0.2.2 Pre-alpha</property>
<property name="xalign">0.94999998807907104</property>
</object>
<packing>
@@ -1731,7 +1820,7 @@
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">5</property>
<property name="position">7</property>
</packing>
</child>
</object>

692
app/ui/picons_dialog.glade Normal file
View File

@@ -0,0 +1,692 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.18.3 -->
<interface>
<requires lib="gtk+" version="3.12"/>
<!-- interface-css-provider-path style.css -->
<object class="GtkListStore" id="providers_list_store">
<columns>
<!-- column-name logo -->
<column type="GdkPixbuf"/>
<!-- column-name name -->
<column type="gchararray"/>
<!-- column-name url -->
<column type="gchararray"/>
<!-- column-name on_id -->
<column type="gchararray"/>
<!-- column-name selected -->
<column type="gboolean"/>
</columns>
</object>
<object class="GtkDialog" id="picons_dialog">
<property name="width_request">480</property>
<property name="can_focus">False</property>
<property name="title" translatable="yes">Picons download tool</property>
<property name="resizable">False</property>
<property name="destroy_with_parent">True</property>
<property name="icon_name">emblem-photos</property>
<property name="type_hint">dialog</property>
<child internal-child="vbox">
<object class="GtkBox" id="picons_dialog_vbox">
<property name="width_request">320</property>
<property name="can_focus">False</property>
<property name="margin_left">2</property>
<property name="margin_right">2</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox" id="dialog_action_area">
<property name="can_focus">False</property>
<property name="margin_left">2</property>
<property name="margin_right">2</property>
<property name="homogeneous">True</property>
<property name="layout_style">spread</property>
<child>
<object class="GtkButton" id="cancel_button">
<property name="label">gtk-close</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="on_close" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</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="GtkBox" id="main_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child>
<object class="GtkGrid" id="grid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="column_spacing">2</property>
<property name="column_homogeneous">True</property>
<child>
<object class="GtkEntry" id="ip_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="primary_icon_name">network-transmit-receive-symbolic</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="picons_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="ip_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Receiver IP:</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="res_picons_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Receiver picons path:</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="picons_dir_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Current picons path:</property>
<property name="xalign">0.019999999552965164</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="picons_dir_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="secondary_icon_name">folder-open-symbolic</property>
<property name="primary_icon_activatable">False</property>
<signal name="icon-press" handler="on_picons_dir_open" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkGrid" id="format_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="column_spacing">2</property>
<child>
<object class="GtkBox" id="name_format_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Picons name format:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_right">5</property>
<child>
<object class="GtkRadioButton" id="enigma2_radio_button">
<property name="label" translatable="yes">Enigma2 (default)</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="xalign">0</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">neutrino_mp_radio_button</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="neutrino_mp_radio_button">
<property name="label" translatable="yes">Neutrino-MP</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="xalign">0</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">enigma2_radio_button</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="resize_format_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Resize: </property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="resize_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkRadioButton" id="resize_no_radio_button">
<property name="label" translatable="yes">No(default)</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="xalign">0</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">resize_100_60_radio_button</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="resize_220_132_radio_button">
<property name="label" translatable="yes">220x132</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="xalign">0</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">resize_100_60_radio_button</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="resize_100_60_radio_button">
<property name="label" translatable="yes">100x60</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="xalign">0</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">resize_no_radio_button</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="left_attach">2</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkSeparator" id="separator3">
<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="orientation">vertical</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<style>
<class name="primary-toolbar"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkSeparator" id="separator1">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="url_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Satellite url (www.lyngsat.com):</property>
<property name="xalign">0.019999999552965164</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">5</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="url_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="primary_icon_name">network-workgroup-symbolic</property>
<property name="primary_icon_activatable">False</property>
<property name="placeholder_text" translatable="yes">https://www.lyngsat.com/*satellite*.html</property>
<property name="input_purpose">url</property>
<signal name="changed" handler="on_url_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">6</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="providers_scrolled_window">
<property name="height_request">150</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">out</property>
<child>
<object class="GtkTreeView" id="providers_tree_view">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="has_focus">True</property>
<property name="model">providers_list_store</property>
<child internal-child="selection">
<object class="GtkTreeSelection" id="treeview_selection"/>
</child>
<child>
<object class="GtkTreeViewColumn" id="provider_column">
<property name="spacing">15</property>
<property name="title" translatable="yes">Providers</property>
<property name="expand">True</property>
<property name="alignment">0.5</property>
<child>
<object class="GtkCellRendererPixbuf" id="logo_cellrendererpixbuf"/>
<attributes>
<attribute name="pixbuf">0</attribute>
</attributes>
</child>
<child>
<object class="GtkCellRendererText" id="name_cellrenderertext"/>
<attributes>
<attribute name="text">1</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="url_column">
<property name="visible">False</property>
<property name="title" translatable="yes">Url</property>
<child>
<object class="GtkCellRendererText" id="cellrenderertext1"/>
<attributes>
<attribute name="text">2</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="on_id_column">
<property name="visible">False</property>
<property name="title" translatable="yes">ONID</property>
<child>
<object class="GtkCellRendererText" id="cellrenderertext2"/>
<attributes>
<attribute name="text">3</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="selected_column">
<property name="title" translatable="yes">Selected</property>
<child>
<object class="GtkCellRendererToggle" id="cellrenderer_toggle">
<signal name="toggled" handler="on_selected_toggled" swapped="no"/>
</object>
<attributes>
<attribute name="active">4</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">7</property>
</packing>
</child>
<child>
<object class="GtkSeparator" id="separator">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">2</property>
<property name="position">10</property>
</packing>
</child>
<child>
<object class="GtkToolbar" id="toolbar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="show_arrow">False</property>
<child>
<object class="GtkToolButton" id="cancel_tool_button">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Cancel</property>
<property name="use_underline">True</property>
<property name="stock_id">gtk-cancel</property>
<signal name="clicked" handler="on_cancel" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkSeparatorToolItem" id="separatortoolitem2">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">False</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="receive_tool_button">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Receive picons for providers</property>
<property name="is_important">True</property>
<property name="label" translatable="yes">Receive picons</property>
<property name="use_underline">True</property>
<property name="icon_name">go-bottom</property>
<signal name="clicked" handler="on_receive" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="load_providers_tool_button">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Load satellite providers.</property>
<property name="is_important">True</property>
<property name="label" translatable="yes">Load providers</property>
<property name="use_underline">True</property>
<property name="icon_name">network-server-symbolic</property>
<signal name="clicked" handler="on_load_providers" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkSeparatorToolItem" id="separatortoolitem1">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">False</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="send_tool_button">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Transfer to receiver</property>
<property name="label" translatable="yes">Send</property>
<property name="use_underline">True</property>
<property name="icon_name">go-top</property>
<signal name="clicked" handler="on_send" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="homogeneous">True</property>
</packing>
</child>
<style>
<class name="primary-toolbar"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">11</property>
</packing>
</child>
<child>
<object class="GtkExpander" id="expander">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="resize_toplevel">True</property>
<child>
<object class="GtkScrolledWindow" id="scrolled_window">
<property name="height_request">150</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<property name="min_content_width">240</property>
<child>
<object class="GtkTextView" id="text_view">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="editable">False</property>
<property name="wrap_mode">word-char</property>
<property name="overwrite">True</property>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="expander_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Info</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">12</property>
</packing>
</child>
<child>
<object class="GtkInfoBar" id="info_bar">
<property name="app_paintable">True</property>
<property name="can_focus">False</property>
<property name="show_close_button">True</property>
<signal name="response" handler="on_info_bar_close" swapped="no"/>
<child internal-child="action_area">
<object class="GtkButtonBox" id="infobar-action_area1">
<property name="can_focus">False</property>
<property name="spacing">6</property>
<property name="layout_style">end</property>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</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" id="infobar-content_area1">
<property name="can_focus">False</property>
<property name="spacing">16</property>
<child>
<placeholder/>
</child>
<child>
<object class="GtkLabel" id="info_bar_message_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Info</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">13</property>
</packing>
</child>
<child>
<object class="GtkSeparator" id="separator2">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">14</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</interface>

239
app/ui/picons_dialog.py Normal file
View File

@@ -0,0 +1,239 @@
import re
import subprocess
import tempfile
import time
from gi.repository import GLib, GdkPixbuf
from app.commons import run_idle, run_task
from app.ftp import upload_data, DownloadDataType
from app.picons.picons import PiconsParser, parse_providers, Provider
from app.properties import Profile
from . import Gtk, Gdk, UI_RESOURCES_PATH
from .dialogs import show_dialog, DialogType
from .main_helper import update_entry_data
class PiconsDialog:
def __init__(self, transient, options, profile=Profile.ENIGMA_2):
self._TMP_DIR = tempfile.gettempdir() + "/"
self._BASE_URL = "www.lyngsat.com/packages/"
self._PATTERN = re.compile("^https://www\.lyngsat\.com/[\w-]+\.html$")
self._current_process = None
self._picons_path = options.get("picons_dir_path", "")
self._terminate = False
handlers = {"on_receive": self.on_receive,
"on_load_providers": self.on_load_providers,
"on_cancel": self.on_cancel,
"on_close": self.on_close,
"on_send": self.on_send,
"on_info_bar_close": self.on_info_bar_close,
"on_picons_dir_open": self.on_picons_dir_open,
"on_selected_toggled": self.on_selected_toggled,
"on_url_changed": self.on_url_changed}
builder = Gtk.Builder()
builder.add_objects_from_file(UI_RESOURCES_PATH + "picons_dialog.glade",
("picons_dialog", "receive_image", "providers_list_store"))
builder.connect_signals(handlers)
self._dialog = builder.get_object("picons_dialog")
self._dialog.set_transient_for(transient)
self._providers_tree_view = builder.get_object("providers_tree_view")
self._expander = builder.get_object("expander")
self._text_view = builder.get_object("text_view")
self._info_bar = builder.get_object("info_bar")
self._ip_entry = builder.get_object("ip_entry")
self._picons_entry = builder.get_object("picons_entry")
self._url_entry = builder.get_object("url_entry")
self._picons_dir_entry = builder.get_object("picons_dir_entry")
self._info_bar = builder.get_object("info_bar")
self._info_bar = builder.get_object("info_bar")
self._message_label = builder.get_object("info_bar_message_label")
self._load_providers_tool_button = builder.get_object("load_providers_tool_button")
self._receive_tool_button = builder.get_object("receive_tool_button")
self._enigma2_radio_button = builder.get_object("enigma2_radio_button")
self._neutrino_mp_radio_button = builder.get_object("neutrino_mp_radio_button")
self._resize_no_radio_button = builder.get_object("resize_no_radio_button")
self._resize_220_132_radio_button = builder.get_object("resize_220_132_radio_button")
self._resize_100_60_radio_button = builder.get_object("resize_100_60_radio_button")
# style
self._style_provider = Gtk.CssProvider()
self._style_provider.load_from_path(UI_RESOURCES_PATH + "style.css")
self._url_entry.get_style_context().add_provider_for_screen(Gdk.Screen.get_default(), self._style_provider,
Gtk.STYLE_PROVIDER_PRIORITY_USER)
self._properties = options
self._profile = profile
self._ip_entry.set_text(options.get("host", ""))
self._picons_entry.set_text(options.get("picons_path", ""))
self._picons_path = options.get("picons_dir_path", "")
self._picons_dir_entry.set_text(self._picons_path)
def show(self):
self._dialog.run()
self._dialog.destroy()
@run_idle
def on_load_providers(self, item):
self._expander.set_expanded(True)
url = self._url_entry.get_text()
self._current_process = subprocess.Popen(["wget", "-pkP", self._TMP_DIR, url],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True)
GLib.io_add_watch(self._current_process.stderr, GLib.IO_IN, self.write_to_buffer)
self.append_providers(url)
@run_task
def append_providers(self, url):
model = self._providers_tree_view.get_model()
model.clear()
self._current_process.wait()
providers = parse_providers(self._TMP_DIR + url[url.find("w"):])
if providers:
for p in providers:
logo = self.get_pixbuf(p[0])
model.append((logo, p.name, p.url, p.on_id, p.selected))
self.update_receive_button_state()
def get_pixbuf(self, img_url):
return GdkPixbuf.Pixbuf.new_from_file_at_scale(filename=self._TMP_DIR + "www.lyngsat.com/" + img_url,
width=48, height=48, preserve_aspect_ratio=True)
@run_idle
def on_receive(self, item):
self.start_download()
@run_task
def start_download(self):
if self._current_process.poll() is None:
self.show_dialog("The task is already running!", DialogType.ERROR)
return
self._terminate = False
self._expander.set_expanded(True)
for prv in self.get_selected_providers():
if self._terminate:
break
self.process_provider(Provider(*prv))
def process_provider(self, provider):
url = provider.url
self.show_info_message("Please, wait...", Gtk.MessageType.INFO)
self._current_process = subprocess.Popen(["wget", "-pkP", self._TMP_DIR, url],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True)
GLib.io_add_watch(self._current_process.stderr, GLib.IO_IN, self.write_to_buffer)
self._current_process.wait()
path = self._TMP_DIR + self._BASE_URL + url[url.rfind("/") + 1:]
PiconsParser.parse(path, self._picons_path, self._TMP_DIR, provider.on_id, self.get_picons_format())
self.resize(self._picons_path)
self.show_info_message("Done", Gtk.MessageType.INFO)
def write_to_buffer(self, fd, condition):
if condition == GLib.IO_IN:
char = fd.read(1)
self.append_output(char)
return True
else:
return False
@run_idle
def append_output(self, char):
buf = self._text_view.get_buffer()
buf.insert_at_cursor(char)
self.scroll_to_end(buf)
def scroll_to_end(self, buf):
insert = buf.get_insert()
self._text_view.scroll_to_mark(insert, 0.0, True, 0.0, 1.0)
def resize(self, path):
if self._resize_no_radio_button.get_active():
return
self.show_info_message("Resizing...", Gtk.MessageType.INFO)
command = "mogrify -resize {}! *.png".format(
"320x240" if self._resize_220_132_radio_button.get_active() else "100x60").split()
self._current_process = subprocess.Popen(command, universal_newlines=True, cwd=path)
self._current_process.wait()
@run_task
def on_cancel(self, item):
if self._current_process:
self._terminate = True
self._current_process.terminate()
time.sleep(1)
@run_idle
def on_close(self, item):
self.on_cancel(item)
self._dialog.destroy()
def on_send(self, item):
if show_dialog(DialogType.QUESTION, self._dialog) == Gtk.ResponseType.CANCEL:
return
self.show_info_message("Please, wait...", Gtk.MessageType.INFO)
self.upload_picons()
@run_task
def upload_picons(self):
if self._current_process is not None and self._current_process.poll() is None:
self.show_dialog("The task is already running!", DialogType.ERROR)
return
upload_data(properties=self._properties,
download_type=DownloadDataType.PICONS,
profile=self._profile,
callback=lambda: self.show_info_message("Done!", Gtk.MessageType.INFO))
def on_info_bar_close(self, bar=None, resp=None):
self._info_bar.set_visible(False)
@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)
def on_picons_dir_open(self, entry, icon, event_button):
update_entry_data(entry, self._dialog, options={"data_dir_path": self._picons_path})
@run_idle
def on_selected_toggled(self, toggle, path):
model = self._providers_tree_view.get_model()
model.set_value(model.get_iter(path), 4, not toggle.get_active())
self.update_receive_button_state()
def on_url_changed(self, entry):
suit = self._PATTERN.search(entry.get_text())
entry.set_name("GtkEntry" if suit else "digit-entry")
self._load_providers_tool_button.set_sensitive(suit if suit else False)
@run_idle
def update_receive_button_state(self):
self._receive_tool_button.set_sensitive(len(self.get_selected_providers()) > 0)
def get_selected_providers(self):
""" returns selected providers """
return [r for r in self._providers_tree_view.get_model() if r[4]]
@run_idle
def show_dialog(self, message, dialog_type):
show_dialog(dialog_type, self._dialog, message)
def get_picons_format(self):
picon_format = Profile.ENIGMA_2
if self._neutrino_mp_radio_button.get_active():
picon_format = Profile.NEUTRINO_MP
return picon_format
if __name__ == "__main__":
pass

View File

@@ -1,6 +1,6 @@
from app.properties import write_config, Profile, get_default_settings
from app.ui.dialogs import show_dialog, DialogType
from . import Gtk, UI_RESOURCES_PATH
from .main_helper import update_entry_data
def show_settings_dialog(transient, options):
@@ -10,10 +10,14 @@ def show_settings_dialog(transient, options):
class SettingsDialog:
def __init__(self, transient, options):
handlers = {"on_data_dir_field_icon_press": self.on_data_dir_field_icon_press,
"on_picons_dir_field_icon_press": self.on_picons_dir_field_icon_press,
"on_profile_changed": self.on_profile_changed,
"on_reset": self.on_reset}
"on_reset": self.on_reset,
"apply_settings": self.apply_settings}
builder = Gtk.Builder()
builder.add_objects_from_file(UI_RESOURCES_PATH + "dialogs.glade", ("settings_dialog",))
builder.add_objects_from_file(UI_RESOURCES_PATH + "dialogs.glade",
("settings_dialog", "telnet_timeout_adjustment"))
builder.connect_signals(handlers)
self._dialog = builder.get_object("settings_dialog")
@@ -22,10 +26,16 @@ class SettingsDialog:
self._port_field = builder.get_object("port_field")
self._login_field = builder.get_object("login_field")
self._password_field = builder.get_object("password_field")
self._telnet_login_field = builder.get_object("telnet_login_field")
self._telnet_password_field = builder.get_object("telnet_password_field")
self._telnet_port_field = builder.get_object("telnet_port_field")
self._telnet_timeout_spin_button = builder.get_object("telnet_timeout_spin_button")
self._services_field = builder.get_object("services_field")
self._user_bouquet_field = builder.get_object("user_bouquet_field")
self._satellites_xml_field = builder.get_object("satellites_xml_field")
self._data_dir_field = builder.get_object("data_dir_field")
self._picons_field = builder.get_object("picons_field")
self._picons_dir_field = builder.get_object("picons_dir_field")
self._enigma_radio_button = builder.get_object("enigma_radio_button")
self._neutrino_radio_button = builder.get_object("neutrino_radio_button")
@@ -44,10 +54,10 @@ class SettingsDialog:
return response
def on_data_dir_field_icon_press(self, entry, icon, event_button):
response = show_dialog(dialog_type=DialogType.CHOOSER,
transient=self._dialog, options=self._options.get(self._options.get("profile")))
if response != Gtk.ResponseType.CANCEL:
entry.set_text(response)
update_entry_data(entry, self._dialog, self._options.get(self._options.get("profile")))
def on_picons_dir_field_icon_press(self, entry, icon, event_button):
update_entry_data(entry, self._dialog, self._options.get(self._options.get("profile")))
def on_profile_changed(self, item):
self.set_profile(Profile.ENIGMA_2 if self._enigma_radio_button.get_active() else Profile.NEUTRINO_MP)
@@ -69,16 +79,22 @@ class SettingsDialog:
def set_settings(self):
options = self._options.get(self._active_profile)
self._host_field.set_text(options.get("host"))
self._port_field.set_text(options.get("port"))
self._login_field.set_text(options.get("user"))
self._password_field.set_text(options.get("password"))
self._services_field.set_text(options.get("services_path"))
self._user_bouquet_field.set_text(options.get("user_bouquet_path"))
self._satellites_xml_field.set_text(options.get("satellites_xml_path"))
self._data_dir_field.set_text(options.get("data_dir_path"))
self._host_field.set_text(options.get("host", ""))
self._port_field.set_text(options.get("port", ""))
self._login_field.set_text(options.get("user", ""))
self._password_field.set_text(options.get("password", ""))
self._telnet_login_field.set_text(options.get("telnet_user", ""))
self._telnet_password_field.set_text(options.get("telnet_password", ""))
self._telnet_port_field.set_text(options.get("telnet_port", ""))
self._telnet_timeout_spin_button.set_value(options.get("telnet_timeout", 5))
self._services_field.set_text(options.get("services_path", ""))
self._user_bouquet_field.set_text(options.get("user_bouquet_path", ""))
self._satellites_xml_field.set_text(options.get("satellites_xml_path", ""))
self._picons_field.set_text(options.get("picons_path", ""))
self._data_dir_field.set_text(options.get("data_dir_path", ""))
self._picons_dir_field.set_text(options.get("picons_dir_path", ""))
def apply_settings(self):
def apply_settings(self, item=None):
profile = Profile.ENIGMA_2.value if self._enigma_radio_button.get_active() else Profile.NEUTRINO_MP.value
self._active_profile = profile
self._options["profile"] = profile
@@ -87,10 +103,16 @@ class SettingsDialog:
options["port"] = self._port_field.get_text()
options["user"] = self._login_field.get_text()
options["password"] = self._password_field.get_text()
options["telnet_user"] = self._telnet_login_field.get_text()
options["telnet_password"] = self._telnet_password_field.get_text()
options["telnet_port"] = self._telnet_port_field.get_text()
options["telnet_timeout"] = int(self._telnet_timeout_spin_button.get_value())
options["services_path"] = self._services_field.get_text()
options["user_bouquet_path"] = self._user_bouquet_field.get_text()
options["satellites_xml_path"] = self._satellites_xml_field.get_text()
options["picons_path"] = self._picons_field.get_text()
options["data_dir_path"] = self._data_dir_field.get_text()
options["picons_dir_path"] = self._picons_dir_field.get_text()
if __name__ == "__main__":

2
build-deb.sh Normal file → Executable file
View File

@@ -1,5 +1,5 @@
#!/bin/env bash
VER="0.2.0_Pre-alpha"
VER="0.2.2_Pre-alpha"
B_PATH="dist/DemonEditor"
DEB_PATH="$B_PATH/usr/share/demoneditor"

View File

@@ -1,9 +1,9 @@
Package: DemonEditor
Version: 0.2.0-Pre-alpha
Version: 0.2.2-Pre-alpha
Section: utils
Priority: optional
Architecture: all
Essential: no
Depends: python3 (>= 3.5)
Maintainer: Dmitriy Yefremov <dmitry.v.yefremov@gmail.com>
Description: Enigma2 channels and satellites editor
Description: Enigma2 channels and satellites list editor