Merge branch 'experimental' into testing

This commit is contained in:
Dmitriy Yefremov
2018-03-25 10:47:33 +03:00
19 changed files with 1152 additions and 398 deletions

View File

@@ -1,11 +1,18 @@
""" Module for m3u import """
""" Module for IPTV and streams support """
from enum import Enum
from app.properties import Profile
from app.ui import IPTV_ICON
from .ecommons import BqServiceType, Service
# url, description, urlkey, account, usrname, psw, s_type, iconsrc, iconsrc_b, group
NEUTRINO_FAV_ID_FORMAT = "{}::{}::{}::{}::{}::{}::{}::{}::{}::{}"
ENIGMA2_FAV_ID_FORMAT = " 1:0:1:0:0:0:0:0:0:0:{}:{}\n#DESCRIPTION: {}\n"
ENIGMA2_FAV_ID_FORMAT = " {}:0:{}:{}:{}:{}:{}:0:0:0:{}:{}\n#DESCRIPTION: {}\n"
class StreamType(Enum):
DVB_TS = "1"
NONE_TS = "4097"
def parse_m3u(path, profile):
@@ -22,7 +29,8 @@ def parse_m3u(path, profile):
elif count == 1:
count = 0
if profile is Profile.ENIGMA_2:
fav_id = ENIGMA2_FAV_ID_FORMAT.format(line.strip().replace(":", "%3a"), name, name, None)
fav_id = ENIGMA2_FAV_ID_FORMAT.format(StreamType.DVB_TS.value, 1, 0, 0, 0, 0,
line.strip().replace(":", "%3a"), name, name, None)
elif profile is Profile.NEUTRINO_MP:
fav_id = NEUTRINO_FAV_ID_FORMAT.format(line.strip(), "", 0, None, None, None, None, "", "", 1)
srv = Service(None, None, IPTV_ICON, name, *aggr[0:3], BqServiceType.IPTV.name, *aggr, fav_id, None)

View File

@@ -2,8 +2,11 @@
For more info see __COMMENT
"""
from functools import lru_cache
from xml.dom.minidom import parse, Document
import os
from .ecommons import POLARIZATION, FEC, SYSTEM, MODULATION, PLS_MODE, Transponder, Satellite, get_key_by_value
__COMMENT = (" File was created in DemonEditor\n\n"
@@ -29,7 +32,7 @@ __COMMENT = (" File was created in DemonEditor\n\n"
def get_satellites(path):
return parse_satellites(path)
return parse_satellites(path, os.path.getsize(path))
def write_satellites(satellites, data_path):
@@ -98,7 +101,8 @@ def parse_sat(elem):
parse_transponders(elem))
def parse_satellites(path):
@lru_cache(maxsize=1)
def parse_satellites(path, file_size):
""" Parsing satellites from xml"""
dom = parse(path)
satellites = []

View File

@@ -4,6 +4,8 @@ import shutil
from collections import namedtuple
from html.parser import HTMLParser
import re
from app.commons import log, run_task
from app.properties import Profile
@@ -103,6 +105,8 @@ class PiconsParser(HTMLParser):
class ProviderParser(HTMLParser):
""" Parser for satellite html page. (https://www.lyngsat.com/*sat-name*.html) """
_POSITION_PATTERN = re.compile("at\s\d+\..*(?:E|W)']")
def __init__(self, entities=False, separator=' '):
HTMLParser.__init__(self)
@@ -117,7 +121,6 @@ class ProviderParser(HTMLParser):
self._current_cell = []
self.rows = []
self._ids = set()
self._counter = 0
self._positon = None
def handle_starttag(self, tag, attrs):
@@ -150,11 +153,10 @@ class ProviderParser(HTMLParser):
elif tag == 'tr':
row = self._current_row
# Satellite position
self._counter = self._counter + 1
if self._counter == 12:
pos = str(row)
pos = pos[pos.rfind("at") + 2:]
self._positon = "".join(c for c in pos if c.isalnum() or c == ".")
if not self._positon:
pos = re.findall(self._POSITION_PATTERN, str(row))
if pos:
self._positon = "".join(c for c in str(pos) if c.isdigit() or c in ".EW")
if len(row) == 12:
on_id, sep, tid = str(row[-2]).partition("-")
@@ -170,7 +172,6 @@ class ProviderParser(HTMLParser):
def reset(self):
super().reset()
self._counter = 0
def parse_providers(open_path):

View File

@@ -613,6 +613,480 @@ dmitry.v.yefremov@gmail.com
</object>
</child>
</object>
<object class="GtkListStore" id="stream_type_liststore">
<columns>
<!-- column-name stream_type -->
<column type="gchararray"/>
</columns>
<data>
<row>
<col id="0">DVB/TS</col>
</row>
<row>
<col id="0">non-TS</col>
</row>
</data>
</object>
<object class="GtkDialog" id="iptv_dialog">
<property name="width_request">480</property>
<property name="can_focus">False</property>
<property name="title" translatable="yes">Stream data</property>
<property name="resizable">False</property>
<property name="modal">True</property>
<property name="destroy_with_parent">True</property>
<property name="type_hint">dialog</property>
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<child internal-child="vbox">
<object class="GtkBox" id="iptv_dialog_vbox">
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox" id="iptv_dialog_action_area">
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="iptv_dialog_cancel_button">
<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="use_stock">True</property>
<property name="always_show_image">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="iptv_dialog_add_button">
<property name="label">gtk-add</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_save" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="iptv_dialog_save_button">
<property name="label">gtk-save</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_save" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="iptv_dialog_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="GtkLabel" id="label22">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Service data:</property>
<property name="xalign">0.0099999997764825821</property>
<style>
<class name="primary-toolbar"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkGrid" id="iptv_dialog_main_grid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="row_spacing">2</property>
<property name="column_spacing">2</property>
<child>
<object class="GtkLabel" id="label23">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Name</property>
<property name="width_chars">7</property>
<property name="max_width_chars">7</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="name_entry">
<property name="width_request">-1</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="primary_icon_stock">gtk-edit</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="iptv_description_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Description</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="description_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="primary_icon_stock">gtk-edit</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="iptv_type_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Type</property>
</object>
<packing>
<property name="left_attach">2</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkComboBox" id="stream_type_combobox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="model">stream_type_liststore</property>
<property name="active">0</property>
<property name="id_column">0</property>
<signal name="changed" handler="on_stream_type_changed" swapped="no"/>
<child>
<object class="GtkCellRendererText" id="iptv_sream_type_cellrenderertext"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
<packing>
<property name="left_attach">2</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="iptv_reference_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Reference</property>
</object>
<packing>
<property name="left_attach">3</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="reference_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="editable">False</property>
</object>
<packing>
<property name="left_attach">3</property>
<property name="top_attach">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkGrid" id="iptv_url_grid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="column_homogeneous">True</property>
<child>
<object class="GtkLabel" id="url_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Url:</property>
<property name="width_chars">7</property>
<property name="max_width_chars">7</property>
<property name="xalign">0.0099999997764825821</property>
<style>
<class name="primary-toolbar"/>
</style>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</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_stock">gtk-edit</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkBox" id="iptv_data_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="GtkSeparator" id="separator6">
<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">1</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="ts_data_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">DVB/TS data:</property>
<property name="xalign">0.0099999997764825821</property>
<style>
<class name="primary-toolbar"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkGrid" id="ts_data_grid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="row_spacing">2</property>
<property name="column_spacing">2</property>
<property name="column_homogeneous">True</property>
<child>
<object class="GtkLabel" id="label28">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Type</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label29">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">SID</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label30">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Tr. ID</property>
</object>
<packing>
<property name="left_attach">2</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label31">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Net. ID</property>
</object>
<packing>
<property name="left_attach">3</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label32">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Namespace</property>
</object>
<packing>
<property name="left_attach">4</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="srv_type_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="width_chars">5</property>
<property name="max_width_chars">5</property>
<property name="text">1</property>
<property name="primary_icon_stock">gtk-edit</property>
<signal name="changed" handler="on_entry_changed" swapped="no"/>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="sid_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="width_chars">5</property>
<property name="max_width_chars">5</property>
<property name="text">0</property>
<property name="primary_icon_stock">gtk-edit</property>
<signal name="changed" handler="on_entry_changed" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="tr_id_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="width_chars">5</property>
<property name="max_width_chars">5</property>
<property name="text">0</property>
<property name="primary_icon_stock">gtk-edit</property>
<signal name="changed" handler="on_entry_changed" swapped="no"/>
</object>
<packing>
<property name="left_attach">2</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="net_id_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="width_chars">5</property>
<property name="max_width_chars">5</property>
<property name="text">0</property>
<property name="primary_icon_stock">gtk-edit</property>
<signal name="changed" handler="on_entry_changed" swapped="no"/>
</object>
<packing>
<property name="left_attach">3</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="namespace_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="width_chars">5</property>
<property name="max_width_chars">5</property>
<property name="text">0</property>
<property name="primary_icon_stock">gtk-edit</property>
<signal name="changed" handler="on_entry_changed" swapped="no"/>
</object>
<packing>
<property name="left_attach">4</property>
<property name="top_attach">1</property>
</packing>
</child>
</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">3</property>
</packing>
</child>
<child>
<object class="GtkSeparator" id="separator7">
<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">7</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
<action-widgets>
<action-widget response="-6">iptv_dialog_cancel_button</action-widget>
</action-widgets>
</object>
<object class="GtkAdjustment" id="telnet_timeout_adjustment">
<property name="lower">1</property>
<property name="upper">11</property>

View File

@@ -6,6 +6,11 @@ from app.commons import run_idle
from . import Gtk, UI_RESOURCES_PATH, TEXT_DOMAIN
class Action(Enum):
EDIT = 0
ADD = 1
class DialogType(Enum):
INPUT = "input_dialog"
CHOOSER = "path_chooser_dialog"
@@ -74,9 +79,10 @@ def show_dialog(dialog_type: DialogType, transient, text=None, options=None, act
def get_dialog_from_xml(dialog_type, transient):
builder = Gtk.Builder()
builder.set_translation_domain(TEXT_DOMAIN)
builder.add_from_file(UI_RESOURCES_PATH + "dialogs.glade")
builder.add_objects_from_file(UI_RESOURCES_PATH + "dialogs.glade", (dialog_type.value,))
dialog = builder.get_object(dialog_type.value)
dialog.set_transient_for(transient)
return builder, dialog
@@ -84,6 +90,7 @@ def get_chooser_dialog(transient, options, pattern, name):
file_filter = Gtk.FileFilter()
file_filter.add_pattern(pattern)
file_filter.set_name(name)
return show_dialog(dialog_type=DialogType.CHOOSER,
transient=transient,
options=options,

167
app/ui/iptv.py Normal file
View File

@@ -0,0 +1,167 @@
import re
from app.eparser.ecommons import BqServiceType, Service
from app.eparser.iptv import NEUTRINO_FAV_ID_FORMAT, StreamType, ENIGMA2_FAV_ID_FORMAT
from app.properties import Profile
from . import Gtk, Gdk, TEXT_DOMAIN, UI_RESOURCES_PATH, IPTV_ICON
from .dialogs import Action, show_dialog, DialogType
from .main_helper import get_base_model
class IptvDialog:
def __init__(self, transient, view, services, bouquet, profile=Profile.ENIGMA_2, action=Action.ADD):
handlers = {"on_entry_changed": self.on_entry_changed,
"on_save": self.on_save,
"on_stream_type_changed": self.on_stream_type_changed}
builder = Gtk.Builder()
builder.set_translation_domain(TEXT_DOMAIN)
builder.add_objects_from_file(UI_RESOURCES_PATH + "dialogs.glade", ("iptv_dialog", "stream_type_liststore"))
builder.connect_signals(handlers)
self._dialog = builder.get_object("iptv_dialog")
self._dialog.set_transient_for(transient)
self._name_entry = builder.get_object("name_entry")
self._description_entry = builder.get_object("description_entry")
self._url_entry = builder.get_object("url_entry")
self._reference_entry = builder.get_object("reference_entry")
self._srv_type_entry = builder.get_object("srv_type_entry")
self._sid_entry = builder.get_object("sid_entry")
self._tr_id_entry = builder.get_object("tr_id_entry")
self._net_id_entry = builder.get_object("net_id_entry")
self._namespace_entry = builder.get_object("namespace_entry")
self._stream_type_combobox = builder.get_object("stream_type_combobox")
self._add_button = builder.get_object("iptv_dialog_add_button")
self._save_button = builder.get_object("iptv_dialog_save_button")
self._stream_type_combobox = builder.get_object("stream_type_combobox")
self._action = action
self._profile = profile
self._bouquet = bouquet
self._services = services
self._model, self._paths = view.get_selection().get_selected_rows()
self._PATTERN = re.compile("(?:^[\s]*$|\D)")
# style
self._style_provider = Gtk.CssProvider()
self._style_provider.load_from_path(UI_RESOURCES_PATH + "style.css")
for el in (self._srv_type_entry, self._sid_entry, self._tr_id_entry, self._net_id_entry, self._namespace_entry):
el.get_style_context().add_provider_for_screen(Gdk.Screen.get_default(), self._style_provider,
Gtk.STYLE_PROVIDER_PRIORITY_USER)
if profile is Profile.NEUTRINO_MP:
builder.get_object("iptv_data_box").set_visible(False)
builder.get_object("iptv_type_label").set_visible(False)
builder.get_object("reference_entry").set_visible(False)
builder.get_object("iptv_reference_label").set_visible(False)
self._stream_type_combobox.set_visible(False)
else:
self._description_entry.set_visible(False)
builder.get_object("iptv_description_label").set_visible(False)
if self._action is Action.ADD:
self._save_button.set_visible(False)
self._add_button.set_visible(True)
if self._profile is Profile.ENIGMA_2:
self._update_reference_entry()
elif self._action is Action.EDIT:
self._current_srv = get_base_model(self._model)[self._paths][:]
self.init_data(self._current_srv)
def show(self):
self._dialog.run()
self._dialog.destroy()
def on_save(self, item):
if show_dialog(DialogType.QUESTION, self._dialog) == Gtk.ResponseType.CANCEL:
return
self.save_enigma2_data() if self._profile is Profile.ENIGMA_2 else self.save_neutrino_data()
self._dialog.destroy()
def init_data(self, srv):
name, fav_id = srv[2], srv[7]
self._name_entry.set_text(name)
self.init_enigma2_data(fav_id) if self._profile is Profile.ENIGMA_2 else self.init_neutrino_data(fav_id)
def init_enigma2_data(self, fav_id):
data, sep, desc = fav_id.partition("#DESCRIPTION:")
self._description_entry.set_text(desc.strip())
data = data.split(":")
if len(data) < 12:
return
self._stream_type_combobox.set_active(0 if StreamType(data[0].strip()) is StreamType.DVB_TS else 1)
self._srv_type_entry.set_text(data[2])
self._sid_entry.set_text(data[3])
self._tr_id_entry.set_text(data[4])
self._net_id_entry.set_text(data[5])
self._namespace_entry.set_text(data[6])
self._url_entry.set_text(data[10].replace("%3a", ":"))
self._update_reference_entry()
def init_neutrino_data(self, fav_id):
data = fav_id.split("::")
self._url_entry.set_text(data[0])
self._description_entry.set_text(data[1])
def _update_reference_entry(self):
if self._profile is Profile.ENIGMA_2:
self._reference_entry.set_text("{}:0:{}:{}:{}:{}:{}:0:0:0".format(self.get_type(),
self._srv_type_entry.get_text(),
self._sid_entry.get_text(),
self._tr_id_entry.get_text(),
self._net_id_entry.get_text(),
self._namespace_entry.get_text()))
def get_type(self):
return 1 if self._stream_type_combobox.get_active() == 0 else 4097
def on_entry_changed(self, entry):
if self._PATTERN.search(entry.get_text()):
entry.set_name("digit-entry")
else:
entry.set_name("GtkEntry")
self._update_reference_entry()
def on_stream_type_changed(self, item):
self._update_reference_entry()
def save_enigma2_data(self):
name = self._name_entry.get_text().strip()
fav_id = ENIGMA2_FAV_ID_FORMAT.format(self.get_type(),
self._srv_type_entry.get_text(),
self._sid_entry.get_text(),
self._tr_id_entry.get_text(),
self._net_id_entry.get_text(),
self._namespace_entry.get_text(),
self._url_entry.get_text().replace(":", "%3a"),
name, name)
self.update_bouquet_data(name, fav_id)
def save_neutrino_data(self):
if self._action is Action.EDIT:
id_data = self._current_srv[7].split("::")
else:
id_data = ["", "", "0", None, None, None, None, "", "", "1"]
id_data[0] = self._url_entry.get_text()
id_data[1] = self._description_entry.get_text()
self.update_bouquet_data(self._name_entry.get_text(), NEUTRINO_FAV_ID_FORMAT.format(*id_data))
self._dialog.destroy()
def update_bouquet_data(self, name, fav_id):
if self._action is Action.EDIT:
old_srv = self._services.pop(self._current_srv[7])
self._services[fav_id] = old_srv._replace(service=name, fav_id=fav_id)
self._bouquet[self._paths[0][0]] = fav_id
self._model.set(self._model.get_iter(self._paths), {2: name, 7: fav_id})
else:
aggr = [None] * 10
s_type = BqServiceType.IPTV.name
srv = (None, None, name, None, None, s_type, None, fav_id, None)
itr = self._model.insert_after(self._model.get_iter(self._paths[0]),
srv) if self._paths else self._model.insert(0, srv)
self._model.set_value(itr, 1, IPTV_ICON)
self._bouquet.insert(self._model.get_path(itr)[0], fav_id)
self._services[fav_id] = Service(None, None, IPTV_ICON, name, *aggr[0:3], s_type, *aggr, fav_id, None)
if __name__ == "__main__":
pass

View File

@@ -11,6 +11,7 @@ from app.eparser.ecommons import CAS, Flag
from app.eparser.enigma.bouquets import BqServiceType
from app.eparser.neutrino.bouquets import BqType
from app.properties import get_config, write_config, Profile
from .iptv import IptvDialog
from .search import SearchProvider
from . import Gtk, Gdk, UI_RESOURCES_PATH, LOCKED_ICON, HIDE_ICON, IPTV_ICON
from .dialogs import show_dialog, DialogType, get_chooser_dialog, WaitDialog, get_message
@@ -21,7 +22,7 @@ from .main_helper import edit_marker, insert_marker, move_items, rename, ViewTar
from .picons_dialog import PiconsDialog
from .satellites_dialog import show_satellites_dialog
from .settings_dialog import show_settings_dialog
from .service_details_dialog import ServiceDetailsDialog
from .service_details_dialog import ServiceDetailsDialog, Action
class MainAppWindow:
@@ -46,11 +47,11 @@ class MainAppWindow:
_FAV_ELEMENTS = ("cut_tool_button", "paste_tool_button", "cut_menu_item",
"paste_menu_item", "fav_cut_popup_item", "fav_paste_popup_item", "import_m3u_tool_button",
"fav_import_m3u_popup_item", "fav_insert_marker_popup_item", "fav_edit_popup_item",
"fav_locate_popup_item", "fav_picon_popup_item")
"fav_locate_popup_item", "fav_picon_popup_item", "fav_add_iptv_popup_item")
_FAV_ENIGMA_ELEMENTS = ("fav_insert_marker_popup_item", "fav_edit_marker_popup_item")
_FAV_M3U_ELEMENTS = ("import_m3u_tool_button", "fav_import_m3u_popup_item")
_FAV_M3U_ELEMENTS = ("import_m3u_tool_button", "fav_import_m3u_popup_item", "fav_add_iptv_popup_item")
_LOCK_HIDE_ELEMENTS = ("locked_tool_button", "hide_tool_button")
@@ -63,7 +64,8 @@ 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_picon_popup_item", "fav_picon_popup_item")
"services_copy_popup_item", "services_picon_popup_item", "fav_picon_popup_item",
"services_add_new_popup_item", "fav_add_iptv_popup_item")
def __init__(self):
handlers = {"on_close_main_window": self.on_quit,
@@ -112,7 +114,9 @@ class MainAppWindow:
"on_search_down": self.on_search_down,
"on_search_up": self.on_search_up,
"on_search": self.on_search,
"on_service_edit": self.on_service_edit}
"on_service_edit": self.on_service_edit,
"on_services_add_new": self.on_services_add_new,
"on_iptv": self.on_iptv}
self.__options = get_config()
self.__profile = self.__options.get("profile")
@@ -171,7 +175,9 @@ class MainAppWindow:
# Search
self.__search_info_bar = builder.get_object("search_info_bar")
self.__search_provider = SearchProvider(self.__services_view, self.__fav_view, self.__bouquets_view,
self.__services, self.__bouquets)
self.__services, self.__bouquets,
builder.get_object("search_down_button"),
builder.get_object("search_up_button"))
self.__main_window.show()
def init_drag_and_drop(self):
@@ -785,6 +791,8 @@ class MainAppWindow:
for elem in self._COMMONS_ELEMENTS:
self.__tool_elements[elem].set_sensitive(not_empty)
self.__tool_elements["services_add_new_popup_item"].set_sensitive(len(self.__bouquets_model))
def on_hide(self, item):
self.set_service_flags(Flag.HIDE)
@@ -857,6 +865,16 @@ class MainAppWindow:
bq_services.append(ch.fav_id)
self.update_bouquet_channels(self.__fav_model, None, bq_selected)
def on_iptv(self, item):
response = IptvDialog(self.__main_window,
self.__fav_view,
self.__services,
self.__bouquets.get(self.is_bouquet_selected(), None),
Profile(self.__profile),
Action.ADD).show()
if response != Gtk.ResponseType.CANCEL:
self.update_fav_num_column(self.__fav_model)
def on_insert_marker(self, view):
""" Inserts marker into bouquet services list. """
insert_marker(view, self.__bouquets, self.is_bouquet_selected(), self.__services, self.__main_window)
@@ -920,9 +938,15 @@ class MainAppWindow:
model_name = get_base_model(model).get_name()
if model_name == self._FAV_LIST_NAME:
srv_type = model.get_value(model.get_iter(paths), 5)
if srv_type == BqServiceType.IPTV.name or srv_type == BqServiceType.MARKER.name:
self.on_rename(view)
return
if srv_type == BqServiceType.MARKER.name:
return self.on_rename(view)
elif srv_type == BqServiceType.IPTV.name:
return IptvDialog(self.__main_window,
self.__fav_view,
self.__services,
self.__bouquets.get(self.is_bouquet_selected(), None),
Profile(self.__profile),
Action.EDIT).show()
self.on_locate_in_services(view)
dialog = ServiceDetailsDialog(self.__main_window,
@@ -932,6 +956,15 @@ class MainAppWindow:
self.__bouquets)
dialog.show()
def on_services_add_new(self, item):
dialog = ServiceDetailsDialog(self.__main_window,
self.__options,
self.__services_view,
self.__services,
self.__bouquets,
action=Action.ADD)
dialog.show()
@run_idle
def update_picons(self):
update_picons(self.__options.get(self.__profile).get("picons_dir_path"), self.__picons, self.__services_model)

View File

@@ -59,7 +59,7 @@ def edit_marker(view, bouquets, selected_bouquet, channels, parent_window):
old_ch = channels.pop(fav_id, None)
new_fav_id = "{}::{}\n#DESCRIPTION {}\n".format(fav_id.split("::")[0], response, response)
model.set(itr, {2: response, 7: new_fav_id})
channels[new_fav_id] = Service(*old_ch[0:3], response, *old_ch[4:17], old_ch.data_id, new_fav_id, None)
channels[new_fav_id] = old_ch._replace(service=response, fav_id=new_fav_id)
bq_services.pop(index)
bq_services.insert(index, new_fav_id)
@@ -143,7 +143,7 @@ def rename(view, parent_window, target, fav_view=None, service_view=None, channe
old_ch = channels.get(f_id, None)
if old_ch:
channels[f_id] = Service(*old_ch[0:3], channel_name, *old_ch[4:])
channels[f_id] = old_ch._replace(service=channel_name)
# ***************** Flags *******************#
@@ -196,7 +196,7 @@ def set_lock(blacklist, channels, model, paths, target, services_model):
continue
blacklist.discard(bq_id) if locked else blacklist.add(bq_id)
model.set_value(itr, col_num, None if locked else LOCKED_ICON)
channels[fav_id] = Service(*channel[:4], None if locked else LOCKED_ICON, *channel[5:])
channels[fav_id] = channel._replace(locked=None if locked else LOCKED_ICON)
ids.append(fav_id)
if target is ViewTarget.FAV and ids:
@@ -244,7 +244,7 @@ def set_hide(channels, model, paths):
fav_id = model.get_value(itr, 18)
channel = channels.get(fav_id, None)
if channel:
channels[fav_id] = Service(*channel[:5], None if hide else HIDE_ICON, *channel[6:])
channels[fav_id] = channel._replace(hide=None if hide else HIDE_ICON)
def has_locked_hide(model, paths, col_num):

View File

@@ -117,6 +117,11 @@
<property name="can_focus">False</property>
<property name="stock">gtk-copy</property>
</object>
<object class="GtkImage" id="image17">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">network-transmit-receive</property>
</object>
<object class="GtkImage" id="image4">
<property name="visible">True</property>
<property name="can_focus">False</property>
@@ -238,6 +243,17 @@
<signal name="activate" handler="on_import_m3u" swapped="no"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="fav_add_iptv_popup_item">
<property name="label" translatable="yes">Add IPTV or stream</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="image">image17</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_iptv" swapped="no"/>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="fav_pupup_separator_3">
<property name="visible">True</property>
@@ -355,6 +371,12 @@
<signal name="activate" handler="on_copy" object="services_tree_view" swapped="no"/>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="separatormenuitem7">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="services_edit_popup_item">
<property name="label">gtk-edit</property>
@@ -367,6 +389,15 @@
<signal name="activate" handler="on_service_edit" object="services_tree_view" swapped="no"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="services_add_new_popup_item">
<property name="label">gtk-new</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_services_add_new" swapped="no"/>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="separatormenuitem2">
<property name="visible">True</property>
@@ -1215,6 +1246,7 @@
<child>
<object class="GtkButton" id="search_down_button">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="on_search_down" swapped="no"/>
@@ -1235,6 +1267,7 @@
<child>
<object class="GtkButton" id="search_up_button">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="on_search_up" swapped="no"/>

View File

@@ -768,22 +768,16 @@
<object class="GtkInfoBar" id="info_bar">
<property name="app_paintable">True</property>
<property name="can_focus">False</property>
<property name="spacing">2</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>
@@ -794,25 +788,22 @@
<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>
<property name="label">Info</property>
<property name="justify">center</property>
<property name="wrap">True</property>
<property name="wrap_mode">word-char</property>
<property name="lines">2</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
@@ -820,9 +811,6 @@
<property name="position">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>

View File

@@ -79,6 +79,10 @@ class PiconsDialog:
self._enigma2_picons_path = self._picons_path
if profile is Profile.NEUTRINO_MP:
self._enigma2_picons_path = options.get(Profile.ENIGMA_2.value).get("picons_dir_path", "")
if not len(self._picon_ids) and self._profile is Profile.ENIGMA_2:
message = get_message("To automatically set the identifiers for picons,\n"
"first load the required services list into the main application window.")
self.show_info_message(message, Gtk.MessageType.WARNING)
def show(self):
self._dialog.run()
@@ -93,12 +97,13 @@ class PiconsDialog:
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.update_receive_button_state()
self.append_providers(url, model)
@run_task
def append_providers(self, url, model):
self._current_process.wait()
providers = parse_providers(self._TMP_DIR + url[url.find("w"):])
if providers:
@@ -123,7 +128,14 @@ class PiconsDialog:
self._terminate = False
self._expander.set_expanded(True)
for prv in self.get_selected_providers():
providers = self.get_selected_providers()
for prv in providers:
if not prv[2] and prv[2][:-2].isdigit():
self.show_info_message(
get_message("Specify the correct position value for the provider!"), Gtk.MessageType.ERROR)
return
for prv in providers:
if self._terminate:
break
self.process_provider(Provider(*prv))
@@ -142,7 +154,7 @@ class PiconsDialog:
PiconsParser.parse(path, self._picons_path, self._TMP_DIR, prv.on_id, pos,
self._picon_ids, self.get_picons_format())
self.resize(self._picons_path)
self.show_info_message("Done", Gtk.MessageType.INFO)
self.show_info_message(get_message("Done!"), Gtk.MessageType.INFO)
def write_to_buffer(self, fd, condition):
if condition == GLib.IO_IN:

View File

@@ -1,9 +1,8 @@
""" This is helper module for search features """
from app.ui.main_helper import get_base_model
class SearchProvider:
def __init__(self, srv_view, fav_view, bqs_view, services, bouquets):
def __init__(self, srv_view, fav_view, bqs_view, services, bouquets, down_button, up_button):
self._paths = []
self._current_index = -1
self._max_indexes = 0
@@ -12,12 +11,14 @@ class SearchProvider:
self._bqs_view = bqs_view
self._services = services
self._bouquets = bouquets
self._up_button = up_button
self._down_button = down_button
def search(self, text, ):
self._current_index = -1
self._paths.clear()
for view in self._srv_view, self._fav_view:
model = get_base_model(view.get_model())
model = view.get_model()
selection = view.get_selection()
selection.unselect_all()
if not text:
@@ -37,6 +38,7 @@ class SearchProvider:
def scroll_to(self, index):
view, path = self._paths[index]
view.scroll_to_cell(path, None)
self.update_navigation_buttons()
def on_search_down(self):
if self._current_index < self._max_indexes:
@@ -48,6 +50,10 @@ class SearchProvider:
self._current_index -= 1
self.scroll_to(self._current_index)
def update_navigation_buttons(self):
self._up_button.set_sensitive(self._current_index > 0)
self._down_button.set_sensitive(self._current_index < self._max_indexes)
if __name__ == "__main__":
pass

View File

@@ -154,6 +154,12 @@
</row>
</data>
</object>
<object class="GtkAdjustment" id="sat_pos_adjustment">
<property name="lower">-180</property>
<property name="upper">180</property>
<property name="step_increment">0.10000000000000001</property>
<property name="page_increment">10</property>
</object>
<object class="GtkListStore" id="sat_pos_list_store">
<columns>
<!-- column-name sat_pos -->
@@ -261,9 +267,8 @@
</packing>
</child>
<child>
<object class="GtkButton" id="save_as_button">
<object class="GtkButton" id="create_button">
<property name="label">gtk-new</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Create and save as new service</property>
@@ -373,7 +378,7 @@
<property name="width_chars">10</property>
<property name="max_width_chars">10</property>
<property name="primary_icon_stock">gtk-edit</property>
<signal name="changed" handler="on_digit_entry_changed" swapped="no"/>
<signal name="changed" handler="on_non_empty_entry_changed" swapped="no"/>
</object>
<packing>
<property name="left_attach">2</property>
@@ -391,30 +396,6 @@
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label5">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">CA ID's</property>
</object>
<packing>
<property name="left_attach">4</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="cas_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="width_chars">15</property>
<property name="max_width_chars">22</property>
<property name="primary_icon_stock">gtk-edit</property>
</object>
<packing>
<property name="left_attach">4</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkComboBox" id="service_type_combo_box">
<property name="visible">True</property>
@@ -448,6 +429,31 @@
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="reference_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Reference</property>
</object>
<packing>
<property name="left_attach">4</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="reference_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="editable">False</property>
<property name="width_chars">8</property>
<property name="max_width_chars">10</property>
</object>
<packing>
<property name="left_attach">4</property>
<property name="top_attach">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
@@ -456,7 +462,7 @@
</packing>
</child>
<child>
<object class="GtkSeparator" id="separator4">
<object class="GtkSeparator" id="srv_separator">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
@@ -638,10 +644,11 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">25</property>
<property name="hexpand">True</property>
<property name="label" translatable="yes">Delays (ms):</property>
<property name="width_chars">10</property>
<property name="max_width_chars">10</property>
<property name="xalign">0</property>
<property name="xalign">1</property>
</object>
<packing>
<property name="left_attach">9</property>
@@ -758,7 +765,7 @@
</packing>
</child>
<child>
<object class="GtkBox" id="box1">
<object class="GtkBox" id="flags_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
@@ -842,16 +849,17 @@
</packing>
</child>
<child>
<object class="GtkGrid" id="ref_grid">
<object class="GtkGrid" id="caids_grid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="column_spacing">2</property>
<child>
<object class="GtkEntry" id="reference_entry">
<object class="GtkEntry" id="cas_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="editable">False</property>
<property name="width_chars">24</property>
<property name="width_chars">15</property>
<property name="max_width_chars">26</property>
<property name="primary_icon_stock">gtk-edit</property>
</object>
<packing>
<property name="left_attach">1</property>
@@ -859,10 +867,10 @@
</packing>
</child>
<child>
<object class="GtkLabel" id="reference_label">
<object class="GtkLabel" id="caid_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Reference: </property>
<property name="label" translatable="yes">CAID's:</property>
</object>
<packing>
<property name="left_attach">0</property>
@@ -917,8 +925,9 @@
<object class="GtkLabel" id="transponder_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">5</property>
<property name="label" translatable="yes">Transponder data:</property>
<property name="xalign">0.0099999997764825821</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="expand">False</property>
@@ -972,7 +981,7 @@
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Pos</property>
<property name="label" translatable="yes">Position</property>
</object>
<packing>
<property name="left_attach">0</property>
@@ -998,7 +1007,7 @@
<property name="width_chars">12</property>
<property name="max_width_chars">12</property>
<property name="primary_icon_stock">gtk-edit</property>
<signal name="changed" handler="on_digit_entry_changed" swapped="no"/>
<signal name="changed" handler="on_non_empty_entry_changed" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
@@ -1024,7 +1033,7 @@
<property name="width_chars">12</property>
<property name="max_width_chars">12</property>
<property name="primary_icon_stock">gtk-edit</property>
<signal name="changed" handler="on_digit_entry_changed" swapped="no"/>
<signal name="changed" handler="on_non_empty_entry_changed" swapped="no"/>
</object>
<packing>
<property name="left_attach">2</property>
@@ -1091,77 +1100,15 @@
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label21">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">System</property>
</object>
<packing>
<property name="left_attach">5</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkComboBox" id="sys_combo_box">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="model">sys_list_store</property>
<property name="id_column">0</property>
<signal name="changed" handler="on_system_changed" swapped="no"/>
<child>
<object class="GtkCellRendererText" id="sys_cellrenderertext"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
<packing>
<property name="left_attach">5</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label22">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Mod</property>
</object>
<packing>
<property name="left_attach">6</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkComboBox" id="mod_combo_box">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="opacity">0.98999999999999999</property>
<property name="model">mod_list_store</property>
<property name="id_column">0</property>
<child>
<object class="GtkCellRendererText" id="mod_cellrenderertext"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
<packing>
<property name="left_attach">6</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="namespace_entry">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="width_chars">17</property>
<property name="max_width_chars">17</property>
<property name="width_chars">12</property>
<property name="max_width_chars">12</property>
<property name="primary_icon_stock">gtk-edit</property>
<signal name="changed" handler="on_digit_entry_changed" swapped="no"/>
<signal name="changed" handler="on_non_empty_entry_changed" swapped="no"/>
</object>
<packing>
<property name="left_attach">7</property>
@@ -1180,24 +1127,72 @@
</packing>
</child>
<child>
<object class="GtkComboBox" id="sat_pos_combo_box">
<object class="GtkSpinButton" id="sat_pos_button">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="model">sat_pos_list_store</property>
<property name="id_column">0</property>
<child>
<object class="GtkCellRendererText" id="sat_pos_cellrenderertext"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
<property name="can_focus">True</property>
<property name="input_purpose">number</property>
<property name="adjustment">sat_pos_adjustment</property>
<property name="digits">1</property>
<property name="numeric">True</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">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">TID</property>
</object>
<packing>
<property name="left_attach">5</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="transponder_id_entry">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="width_chars">8</property>
<property name="max_width_chars">10</property>
<property name="primary_icon_stock">gtk-edit</property>
<signal name="changed" handler="on_non_empty_entry_changed" swapped="no"/>
</object>
<packing>
<property name="left_attach">5</property>
<property name="top_attach">1</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">NID</property>
</object>
<packing>
<property name="left_attach">6</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="network_id_entry">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="width_chars">8</property>
<property name="max_width_chars">10</property>
<property name="primary_icon_stock">gtk-edit</property>
<signal name="changed" handler="on_non_empty_entry_changed" swapped="no"/>
</object>
<packing>
<property name="left_attach">6</property>
<property name="top_attach">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
@@ -1214,58 +1209,6 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="column_spacing">2</property>
<child>
<object class="GtkLabel" id="label4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Tr. ID</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="transponder_id_entry">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="width_chars">8</property>
<property name="max_width_chars">10</property>
<property name="primary_icon_stock">gtk-edit</property>
<signal name="changed" handler="on_digit_entry_changed" swapped="no"/>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</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">Net. ID</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="network_id_entry">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="width_chars">8</property>
<property name="max_width_chars">10</property>
<property name="primary_icon_stock">gtk-edit</property>
<signal name="changed" handler="on_digit_entry_changed" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label25">
<property name="visible">True</property>
@@ -1403,8 +1346,8 @@
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="width_chars">5</property>
<property name="max_width_chars">5</property>
<property name="width_chars">8</property>
<property name="max_width_chars">10</property>
<property name="primary_icon_stock">gtk-edit</property>
<signal name="changed" handler="on_digit_entry_changed" swapped="no"/>
</object>
@@ -1465,6 +1408,69 @@
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label21">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">System</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkComboBox" id="sys_combo_box">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="model">sys_list_store</property>
<property name="id_column">0</property>
<signal name="changed" handler="on_system_changed" swapped="no"/>
<child>
<object class="GtkCellRendererText" id="sys_cellrenderertext"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label22">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Mod</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkComboBox" id="mod_combo_box">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="model">mod_list_store</property>
<property name="id_column">0</property>
<child>
<object class="GtkCellRendererText" id="mod_cellrenderertext"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
</object>
</child>
<child type="label">

View File

@@ -1,62 +1,79 @@
import re
from functools import lru_cache
from app.commons import run_idle
from app.eparser import Service, get_satellites
from app.eparser.ecommons import MODULATION, Inversion, ROLL_OFF, Pilot, Flag, Pids, POLARIZATION, \
get_key_by_value, get_value_by_name, FEC_DEFAULT, PLS_MODE
from app.properties import Profile
from app.ui.dialogs import show_dialog, DialogType
from app.ui.main_helper import get_base_model
from . import Gtk, Gdk, UI_RESOURCES_PATH, HIDE_ICON, TEXT_DOMAIN
from .dialogs import show_dialog, DialogType, Action
from .main_helper import get_base_model
class ServiceDetailsDialog:
_DATA_ID = "{:04x}:{:08x}:{:04x}:{:04x}:{}:{}"
_ENIGMA2_DATA_ID = "{:04x}:{:08x}:{:04x}:{:04x}:{}:{}"
_FAV_ID = "{:X}:{:X}:{:X}:{:X}"
_ENIGMA2_FAV_ID = "{:X}:{:X}:{:X}:{:X}"
_TRANSPONDER_DATA = "{} {}:{}:{}:{}:{}:{}:{}"
_ENIGMA2_TRANSPONDER_DATA = "{} {}:{}:{}:{}:{}:{}:{}"
_DIGIT_ENTRY_ELEMENTS = ("sid_entry", "bitstream_entry", "pcm_entry", "video_pid_entry", "pcr_pid_entry",
"audio_pid_entry", "ac3_pid_entry", "ac3plus_pid_entry", "acc_pid_entry", "freq_entry",
"he_acc_pid_entry", "teletext_pid_entry", "transponder_id_entry", "network_id_entry",
"rate_entry", "pls_code_entry", "stream_id_entry", "tr_flag_entry", "namespace_entry",
"srv_type_entry")
_NEUTRINO_FAV_ID = "{:x}:{:x}:{:x}"
def __init__(self, transient, options, view, services, bouquets):
_NEUTRINO_TRANSPONDER_DATA = "{:04x}:{:04x}:{}:{}:{}:{}:{}:{}:{}"
_DIGIT_ENTRY_ELEMENTS = ("bitstream_entry", "pcm_entry", "video_pid_entry", "pcr_pid_entry", "srv_type_entry",
"ac3_pid_entry", "ac3plus_pid_entry", "acc_pid_entry", "he_acc_pid_entry",
"teletext_pid_entry", "pls_code_entry", "stream_id_entry", "tr_flag_entry",
"audio_pid_entry")
_NOT_EMPTY_DIGIT_ELEMENTS = ("sid_entry", "freq_entry", "rate_entry", "transponder_id_entry", "network_id_entry",
"namespace_entry")
_DIGIT_ENTRY_NAME = "digit-entry"
def __init__(self, transient, options, view, services, bouquets, action=Action.EDIT):
handlers = {"on_system_changed": self.on_system_changed,
"on_save": self.on_save,
"on_create_new": self.on_create_new,
"on_digit_entry_changed": self.on_digit_entry_changed,
"on_tr_edit_toggled": self.on_tr_edit_toggled}
"on_tr_edit_toggled": self.on_tr_edit_toggled,
"on_non_empty_entry_changed": self.on_non_empty_entry_changed}
builder = Gtk.Builder()
builder.set_translation_domain(TEXT_DOMAIN)
builder.add_from_file(UI_RESOURCES_PATH + "service_details_dialog.glade")
builder.connect_signals(handlers)
self._builder = builder
self._dialog = builder.get_object("service_details_dialog")
self._dialog.set_transient_for(transient)
self._profile = Profile(options["profile"])
self._satellites_xml_path = options.get(self._profile.value)["data_dir_path"] + "satellites.xml"
self._services_view = view
self._action = action
self._old_service = None
self._services = services
self._bouquets = bouquets
self._transponder_services_iters = None
self._current_model = None
self._current_itr = None
self._pattern = re.compile("\D")
self._DIGIT_PATTERN = re.compile("\D")
self._NON_EMPTY_PATTERN = re.compile("(?:^[\s]*$|\D)")
self._apply_button = builder.get_object("apply_button")
self._create_button = builder.get_object("create_button")
# style
self._style_provider = Gtk.CssProvider()
self._style_provider.load_from_path(UI_RESOURCES_PATH + "style.css")
# initialize only digit elements
# initialization only digit elements
self._digit_elements = {k: builder.get_object(k) for k in self._DIGIT_ENTRY_ELEMENTS}
for elem in self._digit_elements.values():
elem.get_style_context().add_provider_for_screen(Gdk.Screen.get_default(), self._style_provider,
Gtk.STYLE_PROVIDER_PRIORITY_USER)
self._sid_entry = self._digit_elements.get("sid_entry")
# initialization of non empty elements
self._non_empty_elements = {k: builder.get_object(k) for k in self._NOT_EMPTY_DIGIT_ELEMENTS}
for elem in self._non_empty_elements.values():
elem.get_style_context().add_provider_for_screen(Gdk.Screen.get_default(), self._style_provider,
Gtk.STYLE_PROVIDER_PRIORITY_USER)
self._sid_entry = self._non_empty_elements.get("sid_entry")
self._bitstream_entry = self._digit_elements.get("bitstream_entry")
self._pcm_entry = self._digit_elements.get("pcm_entry")
self._video_pid_entry = self._digit_elements.get("video_pid_entry")
@@ -67,14 +84,14 @@ class ServiceDetailsDialog:
self._acc_pid_entry = self._digit_elements.get("acc_pid_entry")
self._he_acc_pid_entry = self._digit_elements.get("he_acc_pid_entry")
self._teletext_pid_entry = self._digit_elements.get("teletext_pid_entry")
self._transponder_id_entry = self._digit_elements.get("transponder_id_entry")
self._network_id_entry = self._digit_elements.get("network_id_entry")
self._freq_entry = self._digit_elements.get("freq_entry")
self._rate_entry = self._digit_elements.get("rate_entry")
self._transponder_id_entry = self._non_empty_elements.get("transponder_id_entry")
self._network_id_entry = self._non_empty_elements.get("network_id_entry")
self._freq_entry = self._non_empty_elements.get("freq_entry")
self._rate_entry = self._non_empty_elements.get("rate_entry")
self._pls_code_entry = self._digit_elements.get("pls_code_entry")
self._stream_id_entry = self._digit_elements.get("stream_id_entry")
self._tr_flag_entry = self._digit_elements.get("tr_flag_entry")
self._namespace_entry = self._digit_elements.get("namespace_entry")
self._namespace_entry = self._non_empty_elements.get("namespace_entry")
# Service elements
self._name_entry = builder.get_object("name_entry")
self._package_entry = builder.get_object("package_entry")
@@ -88,7 +105,7 @@ class ServiceDetailsDialog:
self._new_check_button = builder.get_object("new_check_button")
self._pids_grid = builder.get_object("pids_grid")
# Transponder elements
self._sat_pos_combo_box = builder.get_object("sat_pos_combo_box")
self._sat_pos_button = builder.get_object("sat_pos_button")
self._pol_combo_box = builder.get_object("pol_combo_box")
self._fec_combo_box = builder.get_object("fec_combo_box")
self._sys_combo_box = builder.get_object("sys_combo_box")
@@ -98,15 +115,19 @@ class ServiceDetailsDialog:
self._pilot_combo_box = builder.get_object("pilot_combo_box")
self._pls_mode_combo_box = builder.get_object("pls_mode_combo_box")
self._tr_edit_switch = builder.get_object("tr_edit_switch")
self._tr_extra_expander = builder.get_object("tr_extra_expander")
self._DVB_S2_ELEMENTS = (self._mod_combo_box, self._rolloff_combo_box, self._pilot_combo_box,
self._pls_mode_combo_box, self._pls_code_entry, self._stream_id_entry)
self._TRANSPONDER_ELEMENTS = (self._sat_pos_combo_box, self._pol_combo_box, self._invertion_combo_box,
self._TRANSPONDER_ELEMENTS = (self._sat_pos_button, self._pol_combo_box, self._invertion_combo_box,
self._sys_combo_box, self._freq_entry, self._transponder_id_entry,
self._network_id_entry, self._namespace_entry, self._fec_combo_box,
self._rate_entry)
self.update_data_elements()
if self._action is Action.EDIT:
self.update_data_elements()
elif self._action is Action.ADD:
self.init_default_data_elements()
def show(self):
response = self._dialog.run()
@@ -117,6 +138,22 @@ class ServiceDetailsDialog:
return response
@run_idle
def init_default_data_elements(self):
self._apply_button.set_visible(False)
self._create_button.set_visible(True)
self._tr_edit_switch.set_sensitive(False)
self.on_tr_edit_toggled(self._tr_edit_switch.set_active(True), True)
for elem in self._non_empty_elements.values():
elem.set_text(" ")
elem.set_text("")
self._new_check_button.set_active(True)
self._tr_extra_expander.activate()
self._service_type_combo_box.set_active(0)
self._pol_combo_box.set_active(0)
self._fec_combo_box.set_active(0)
self._sys_combo_box.set_active(0)
self._invertion_combo_box.set_active(2)
def update_data_elements(self):
model, paths = self._services_view.get_selection().get_selected_rows()
itr = model.get_iter(paths)
@@ -145,7 +182,7 @@ class ServiceDetailsDialog:
self.init_enigma2_transponder_data(srv)
elif self._profile is Profile.NEUTRINO_MP:
self.init_neutrino_data(srv)
self.init_enigma_ui_elements()
self.init_neutrino_ui_elements()
# ***************** Init Enigma2 data *********************#
@@ -230,27 +267,21 @@ class ServiceDetailsDialog:
self._reference_entry.set_text(srv.picon_id.rstrip(".png"))
self._transponder_id_entry.set_text(str(int(tr_data[0], 16)))
self._network_id_entry.set_text(str(int(tr_data[1], 16)))
self.select_active_text(self._invertion_combo_box, Inversion(tr_data[3]).name)
def init_enigma_ui_elements(self):
self._pids_grid.set_sensitive(False)
self._cas_entry.set_sensitive(False)
self._keep_check_button.set_sensitive(False)
self._hide_check_button.set_sensitive(False)
self._use_pids_check_button.set_sensitive(False)
self._new_check_button.set_sensitive(False)
def init_neutrino_ui_elements(self):
self._builder.get_object("flags_box").set_visible(False)
self._builder.get_object("pids_grid").set_visible(False)
self._builder.get_object("tr_grid").remove_column(7)
self._builder.get_object("tr_extra_expander").set_visible(False)
self._builder.get_object("srv_separator").set_visible(False)
# ***************** Init Sat positions *********************#
@run_idle
def set_sat_positions(self, sat_pos):
""" Sat positions initialisation """
model = self._sat_pos_combo_box.get_model()
positions = self.get_sat_positions(self._satellites_xml_path)
for pos in positions:
model.append((pos,))
self.select_active_text(self._sat_pos_combo_box, sat_pos)
self._sat_pos_button.set_value(float(sat_pos))
@lru_cache(maxsize=1)
def get_sat_positions(self, path):
try:
return ["{:.1f}".format(float(x.position) / 10) for x in get_satellites(path)]
@@ -272,56 +303,31 @@ class ServiceDetailsDialog:
# ***************** Save data *********************#
def on_save(self, item):
self.save_data()
def on_create_new(self, item):
self.save_data()
def save_data(self):
if not self.is_data_correct():
show_dialog(DialogType.ERROR, self._dialog, "Error. Verify the data!")
return
if show_dialog(DialogType.QUESTION, self._dialog) == Gtk.ResponseType.CANCEL:
return
self.on_edit() if self._action is Action.EDIT else self.on_new()
self._dialog.destroy()
def on_edit(self):
fav_id, data_id = self.get_srv_data()
# transponder
transponder = self._old_service.transponder
freq = self._freq_entry.get_text()
rate = self._rate_entry.get_text()
pol = self._pol_combo_box.get_active_id()
fec = self._fec_combo_box.get_active_id()
system = self._sys_combo_box.get_active_id()
pos = self._sat_pos_combo_box.get_active_id()
if self._tr_edit_switch.get_active():
transponder = self.get_transponder_data()
if self._transponder_services_iters:
for itr in self._transponder_services_iters:
srv = self._current_model[itr][:]
srv[-9] = freq
srv[-8] = rate
srv[-7] = pol
srv[-6] = fec
srv[-5] = system
srv[-4] = pos
srv[-1] = transponder
srv = Service(*srv)
self._services[srv.fav_id] = srv
self._current_model.set(itr, {i: v for i, v in enumerate(srv)})
service = Service(flags_cas=self.get_flags(),
transponder_type="s",
coded=self._old_service.coded,
service=self._name_entry.get_text(),
locked=self._old_service.locked,
hide=HIDE_ICON if self._hide_check_button.get_active() else None,
package=self._package_entry.get_text(),
service_type=self._service_type_combo_box.get_active_id(),
picon=self._old_service.picon,
picon_id=self._old_service.picon_id,
ssid="{:x}".format(int(self._sid_entry.get_text())),
freq=freq,
rate=rate,
pol=pol,
fec=fec,
system=system,
pos=pos,
data_id=data_id,
fav_id=fav_id,
transponder=transponder)
self.update_transponder_services(transponder)
service = self.get_service(fav_id, data_id, transponder)
old_fav_id = self._old_service.fav_id
if old_fav_id != fav_id:
self._services.pop(old_fav_id, None)
@@ -332,17 +338,38 @@ class ServiceDetailsDialog:
indexes.append(i)
for i in indexes:
bq[i] = fav_id
self._services[fav_id] = service
self._current_model.set(self._current_itr, {i: v for i, v in enumerate(service)})
self._old_service = service
def on_create_new(self, item):
if show_dialog(DialogType.QUESTION, self._dialog) == Gtk.ResponseType.CANCEL:
return
def on_new(self):
service = self.get_service(*self.get_srv_data(), self.get_transponder_data())
print(service)
show_dialog(DialogType.ERROR, transient=self._dialog, text="Not implemented yet!")
def get_service(self, fav_id, data_id, transponder):
freq, rate, pol, fec, system, pos = self.get_transponder_values()
return Service(flags_cas=self.get_flags(),
transponder_type="s",
coded=self._old_service.coded,
service=self._name_entry.get_text(),
locked=self._old_service.locked,
hide=HIDE_ICON if self._hide_check_button.get_active() else None,
package=self._package_entry.get_text(),
service_type=self._service_type_combo_box.get_active_id(),
picon=self._old_service.picon,
picon_id=self._old_service.picon_id,
ssid="{:x}".format(int(self._sid_entry.get_text())),
freq=freq,
rate=rate,
pol=pol,
fec=fec,
system=system,
pos=pos,
data_id=data_id,
fav_id=fav_id,
transponder=transponder)
def get_flags(self):
if self._profile is Profile.ENIGMA_2:
return self.get_enigma2_flags()
@@ -389,23 +416,26 @@ class ServiceDetailsDialog:
def get_srv_data(self):
ssid = int(self._sid_entry.get_text())
namespace = int(self._namespace_entry.get_text())
transponder_id = int(self._transponder_id_entry.get_text())
network_id = int(self._network_id_entry.get_text())
net_id, tr_id = int(self._network_id_entry.get_text()), int(self._transponder_id_entry.get_text())
service_type = self._srv_type_entry.get_text()
if self._profile is Profile.ENIGMA_2:
data_id = self._DATA_ID.format(ssid, namespace, transponder_id, network_id, service_type, 0)
fav_id = self._FAV_ID.format(ssid, transponder_id, network_id, namespace)
namespace = int(self._namespace_entry.get_text())
data_id = self._ENIGMA2_DATA_ID.format(ssid, namespace, tr_id, net_id, service_type, 0)
fav_id = self._ENIGMA2_FAV_ID.format(ssid, tr_id, net_id, namespace)
return fav_id, data_id
elif self._profile is Profile.NEUTRINO_MP:
return self._old_service.fav_id, self._old_service.data_id
fav_id = self._NEUTRINO_FAV_ID.format(tr_id, net_id, ssid)
return fav_id, self._old_service.data_id
def get_fav_id(self):
if self._profile is Profile.ENIGMA_2:
return self._old_service.fav_id
elif self._profile is Profile.NEUTRINO_MP:
return self._old_service.fav_id
def get_transponder_values(self):
freq = self._freq_entry.get_text()
rate = self._rate_entry.get_text()
pol = self._pol_combo_box.get_active_id()
fec = self._fec_combo_box.get_active_id()
system = self._sys_combo_box.get_active_id()
pos = str(round(self._sat_pos_button.get_value(), 1))
return freq, rate, pol, fec, system, pos
def get_transponder_data(self):
sys = self._sys_combo_box.get_active_id()
@@ -413,12 +443,12 @@ class ServiceDetailsDialog:
rate = self._rate_entry.get_text()
pol = self.get_value_from_combobox_id(self._pol_combo_box, POLARIZATION)
fec = self.get_value_from_combobox_id(self._fec_combo_box, FEC_DEFAULT)
sat_pos = self._sat_pos_combo_box.get_active_id().replace(".", "")
sat_pos = str(round(self._sat_pos_button.get_value(), 1)).replace(".", "")
inv = get_value_by_name(Inversion, self._invertion_combo_box.get_active_id())
srv_sys = "0" # !!!
if self._profile is Profile.ENIGMA_2:
dvb_s_tr = self._TRANSPONDER_DATA.format("s", freq, rate, pol, fec, sat_pos, inv, srv_sys)
dvb_s_tr = self._ENIGMA2_TRANSPONDER_DATA.format("s", freq, rate, pol, fec, sat_pos, inv, srv_sys)
if sys == "DVB-S":
return dvb_s_tr
if sys == "DVB-S2":
@@ -432,7 +462,19 @@ class ServiceDetailsDialog:
pls = ":{}:{}:{}".format(st_id, pls_code, pls_mode) if pls_mode and pls_code and st_id else ""
return "{}:{}:{}:{}:{}{}".format(dvb_s_tr, flag, mod, roll_off, pilot, pls)
elif self._profile is Profile.NEUTRINO_MP:
return self._old_service.transponder
on_id, tr_id = int(self._network_id_entry.get_text()), int(self._transponder_id_entry.get_text())
mod = self.get_value_from_combobox_id(self._mod_combo_box, MODULATION) if sys == "DVB-S2" else None
srv_sys = None
return self._NEUTRINO_TRANSPONDER_DATA.format(tr_id, on_id, freq, inv, rate, fec, pol, mod, srv_sys)
def update_transponder_services(self, transponder):
for itr in self._transponder_services_iters:
srv = self._current_model[itr][:]
srv[-9], srv[-8], srv[-7], srv[-6], srv[-5], srv[-4] = self.get_transponder_values()
srv[-1] = transponder
srv = Service(*srv)
self._services[srv.fav_id] = self._services.pop(srv.fav_id)._replace(transponder=transponder)
self._current_model.set(itr, {i: v for i, v in enumerate(srv)})
# ***************** Others *********************#
@@ -444,7 +486,10 @@ class ServiceDetailsDialog:
break
def on_digit_entry_changed(self, entry):
entry.set_name("digit-entry" if self._pattern.search(entry.get_text()) else "GtkEntry")
entry.set_name(self._DIGIT_ENTRY_NAME if self._DIGIT_PATTERN.search(entry.get_text()) else "GtkEntry")
def on_non_empty_entry_changed(self, entry):
entry.set_name(self._DIGIT_ENTRY_NAME if self._NON_EMPTY_PATTERN.search(entry.get_text()) else "GtkEntry")
def get_value_from_combobox_id(self, box: Gtk.ComboBox, dc: dict):
cb_id = box.get_active_id()
@@ -453,7 +498,7 @@ class ServiceDetailsDialog:
@run_idle
def on_tr_edit_toggled(self, switch: Gtk.Switch, active):
if active:
if active and self._action is Action.EDIT:
self._transponder_services_iters = []
response = TransponderServicesDialog(self._dialog,
self._current_model,
@@ -469,6 +514,15 @@ class ServiceDetailsDialog:
for elem in self._TRANSPONDER_ELEMENTS:
elem.set_sensitive(active)
def is_data_correct(self):
for elem in self._digit_elements.values():
if elem.get_name() == self._DIGIT_ENTRY_NAME:
return False
for elem in self._non_empty_elements.values():
if elem.get_name() == self._DIGIT_ENTRY_NAME:
return False
return True
class TransponderServicesDialog:
def __init__(self, transient, model, transponder, tr_iters):

View File

@@ -5,7 +5,7 @@ DEB_PATH="$B_PATH/usr/share/demoneditor"
mkdir -p $B_PATH
cp -TRv deb $B_PATH
cp -Rv app $DEB_PATH
rsync --exclude=app/ui/lang -arv app $DEB_PATH
cp -Rv start.py $DEB_PATH
cd dist

Binary file not shown.

View File

@@ -43,294 +43,222 @@ msgstr "№"
msgid "Current IP:"
msgstr "Текущий IP:"
#: main_window.glade:261
msgid "Assign"
msgstr "Привязать"
#: main_window.glade:1826
msgid "Bouquet details"
msgstr "Сервисы букета"
#: main_window.glade:2021
msgid "Bouquets"
msgstr "Букеты"
#: main_window.glade:916
msgid "Copy"
msgstr "Копировать"
#: main_window.glade:287 main_window.glade:416
msgid "Copy reference"
msgstr "Копировать ссылку"
#: main_window.glade:1777
msgid "Data"
msgstr ""
#: main_window.glade:744
msgid "Download"
msgstr "Загрузить"
#: main_window.glade:1014
msgid "Edit"
msgstr "Изменить"
#: main_window.glade:1015
msgid "Edit "
msgstr "Изменить"
#: main_window.glade:213
msgid "Edit mаrker text"
msgstr "Изменить текст маркера"
#: main_window.glade:543 main_window.glade:743
msgid "FTP-transfer"
msgstr "Передача установок по FTP"
#: main_window.glade:808
msgid "Global search"
msgstr "Глобальный поиск"
#: main_window.glade:973
msgid "Hide"
msgstr "Пропустить"
#: main_window.glade:972
msgid "Hide/Skip On/Off Ctrl + H"
msgstr "Скрыть/Пропустить Вкл/Выкл Ctrl + H"
#: main_window.glade:1113
msgid "IPTV"
msgstr ""
#: main_window.glade:231
msgid "Import m3u"
msgstr "Импортировать m3u"
#: main_window.glade:1111
msgid "Import m3u file"
msgstr "Импортировать файл m3u"
#: main_window.glade:201
msgid "Insert marker"
msgstr "Вставить маркер"
#: main_window.glade:184
msgid "Locate in services"
msgstr "Найти в списке сервисов"
#: main_window.glade:957
msgid "Locked"
msgstr "Заблокирован"
#: main_window.glade:834
msgid "Move"
msgstr "Переместить"
#: main_window.glade:999
msgid "New"
msgstr "Новый"
#: main_window.glade:998
msgid "New bouquet"
msgstr "Новый букет"
#: main_window.glade:718 main_window.glade:719
msgid "Open"
msgstr "Открыть"
#: main_window.glade:956
msgid "Parent lock On/Off Ctrl + L"
msgstr "Родительский замок Вкл/Выкл Ctrl + L"
#: main_window.glade:931
msgid "Paste"
msgstr ""
#: main_window.glade:1095
msgid "Picons"
msgstr "Пиконы"
#: main_window.glade:650 main_window.glade:1096
msgid "Picons loader"
msgstr "Загрузчик пиконов"
#: main_window.glade:1055
msgid "Preferences"
msgstr "Настройки"
#: main_window.glade:2195
msgid "Profile:"
msgstr "Профиль:"
#: main_window.glade:1751
msgid "Radio"
msgstr ""
#: main_window.glade:271 main_window.glade:1030
msgid "Remove"
msgstr "Удалить"
#: main_window.glade:640 main_window.glade:1079 main_window.glade:1080
msgid "Satellites editor"
msgstr "Редактор спутников"
#: main_window.glade:768 main_window.glade:769
msgid "Save"
msgstr "Сохранить"
#: main_window.glade:809
msgid "Search"
msgstr "Поиск"
#: main_window.glade:1269
msgid "Services"
msgstr "Сервисы"
#: main_window.glade:793 main_window.glade:794
msgid "Services filter"
msgstr "Фильтр сервисов"
#: main_window.glade:1054
msgid "Settings"
msgstr "Настройки"
#: main_window.glade:1725
msgid "TV"
msgstr ""
#: main_window.glade:859 main_window.glade:860
msgid "Up"
msgstr "Переместить вверх"
msgid "Down"
msgstr "Переместить вниз"
#: dialogs.glade:1101
msgid "Active profile:"
msgstr "Активный профиль:"
#: dialogs.glade:175
msgid "All"
msgstr "Все"
#: dialogs.glade:595
msgid "Are you sure?"
msgstr "Вы уверены?"
#: dialogs.glade:127
msgid "Current data path:"
msgstr "Текущий путь к данным:"
#: dialogs.glade:1192
msgid "Data dir:"
msgstr "Путь к данным:"
#: dialogs.glade:164
msgid "Data:"
msgstr "Данные:"
#: dialogs.glade:16
msgid "Enigma2 channel and satellites list editor for GNU/Linux"
msgstr "Редактор списка каналов и спутников Enigma2\n для GNU/Linux"
#: dialogs.glade:814
msgid "FTP"
msgstr ""
#: dialogs.glade:712
msgid "Host:"
msgstr "Адрес ресивера:"
#: dialogs.glade:1328
msgid "Loading data..."
msgstr "Загрузка данных..."
#: dialogs.glade:735 dialogs.glade:863
msgid "Login:"
msgstr "Логин:"
#: dialogs.glade:625
msgid "Options"
msgstr "Настройки"
#: dialogs.glade:746 dialogs.glade:874
msgid "Password:"
msgstr "Пароль:"
#: dialogs.glade:1235
msgid "Picons dir:"
msgstr "Директория пиконов:"
#: dialogs.glade:1050
msgid "Picons:"
msgstr "Пиконы:"
#: dialogs.glade:769 dialogs.glade:830
msgid "Port:"
msgstr "Порт:"
#: dialogs.glade:94 dialogs.glade:256
msgid "Receive"
msgstr "Получить"
#: dialogs.glade:254
msgid "Receive files from receiver"
msgstr "Получить файлы из ресивера"
#: dialogs.glade:100
msgid "Receiver IP:"
msgstr "IP адрес ресивера:"
#: dialogs.glade:297
msgid "Remove unused bouquets"
msgstr "Удалить не испрльзуемые букеты"
#: dialogs.glade:1148
msgid "Reset profile"
msgstr "Сброс профиля"
#: dialogs.glade:208
msgid "Satellites"
msgstr "Спутники"
#: dialogs.glade:1026
msgid "Satellites.xml file:"
msgstr "Файл satellites.xml:"
#: dialogs.glade:1215 dialogs.glade:1216
msgid "Select"
msgstr ""
#: dialogs.glade:271
msgid "Send"
msgstr "Отправить"
#: dialogs.glade:269
msgid "Send files to receiver"
msgstr "Отправить вайлы в ресивер"
msgstr "Отправить файлы в ресивер"
#: dialogs.glade:978
msgid "Services and Bouquets files:"
msgstr "Файлы сервисов и букетов:"
#: dialogs.glade:932
msgid "Telnet"
msgstr ""
#: dialogs.glade:908
msgid "Timeout between commands in seconds"
msgstr "Пауза между коммандами в сек."
#: dialogs.glade:897
msgid "Timeout:"
msgstr "Тайм-аут:"
#: dialogs.glade:1002
msgid "User bouquet files:"
msgstr "Файлы букетов:"
#: dialogs.glade:224
msgid "WebTV"
msgstr ""
@@ -377,6 +305,21 @@ msgstr "Путь для сохранения:"
msgid "Path to Enigma2 picons:"
msgstr "Путь к пиконам формата Enigma2:"
msgid "Specify the correct position value for the provider!"
msgstr "Укажите правильное значение позиции для провайдера!"
msgid "Converter between name formats"
msgstr "Конвертер формата имен"
msgid "Receive picons for providers"
msgstr "Получение пиконов для провайдеров"
msgid "Load satellite providers."
msgstr "Загрузка провайдеров"
msgid "To automatically set the identifiers for picons,\nfirst load the required services list into the main application window."
msgstr "Для автоматического именования пиконов,\nзагрузите список необходимых сервисов в главное окно программы."
# Satellites editor
msgid "Satellites edit tool"
msgstr "Редактор спутников"
@@ -418,6 +361,24 @@ msgstr "Данные транспондера"
msgid "Changes will be applied to all services of this transponder!\nContinue?"
msgstr "Изменения будут применены ко всем сервисам данного транспондера!\nПродолжить?"
msgid "Reference"
msgstr "Ссылка"
msgid "Namespace"
msgstr "Пр. имен"
msgid "Flags:"
msgstr "Флаги:"
msgid "Delays (ms):"
msgstr "Задержки (mc)"
msgid "Bitstream"
msgstr "Поток"
msgid "Description"
msgstr "Описание"
# Dialogs messages
msgid "Error. No bouquet is selected!"
msgstr "Ошибка. Не выбран букет!"