mirror of
https://github.com/DYefremov/DemonEditor.git
synced 2026-03-21 20:11:37 +01:00
Merge branch 'experimental' into testing
This commit is contained in:
10
README.md
10
README.md
@@ -5,13 +5,13 @@ 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.
|
||||
Insert - copies the selected channels from the main list to the bouquet or inserts (creates) a new bouquet.
|
||||
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.
|
||||
Ctrl + R - rename.
|
||||
Ctrl + S, T, E in Satellites edit tool for create and edit satellite or transponder.
|
||||
Ctrl + E - edit.
|
||||
Ctrl + R, F2 - rename.
|
||||
Ctrl + S, T in Satellites edit tool for create satellite or transponder.
|
||||
Ctrl + L - parental lock.
|
||||
Ctrl + H - hide/skip.
|
||||
Left/Right - remove selection.
|
||||
|
||||
@@ -35,7 +35,13 @@ class Type(Enum):
|
||||
|
||||
|
||||
class Flag(Enum):
|
||||
""" Service flags """
|
||||
""" Service flags
|
||||
|
||||
K - last bit (1)
|
||||
H - second from end (10)
|
||||
P - third (100)
|
||||
N - sixth (100000)
|
||||
"""
|
||||
KEEP = 1 # Do not automatically update the services parameters.
|
||||
HIDE = 2
|
||||
PIDS = 4 # Always use the cached instead of current pids.
|
||||
@@ -43,8 +49,33 @@ class Flag(Enum):
|
||||
NEW = 40 # Marked as new at the last scan
|
||||
|
||||
@staticmethod
|
||||
def hide_values():
|
||||
return 2, 3, 6, 7, 10, 42, 43, 46, 47
|
||||
def is_hide(value: int):
|
||||
return value & 1 << 1
|
||||
|
||||
@staticmethod
|
||||
def is_keep(value: int):
|
||||
return value & 1 << 0
|
||||
|
||||
@staticmethod
|
||||
def is_pids(value: int):
|
||||
return value & 1 << 2
|
||||
|
||||
@staticmethod
|
||||
def is_new(value: int):
|
||||
return value & 1 << 5
|
||||
|
||||
|
||||
class Pids(Enum):
|
||||
VIDEO = "c:00"
|
||||
AUDIO = "c:01"
|
||||
TELETEXT = "c:02"
|
||||
PCR = "c:03"
|
||||
AC3 = "c:04"
|
||||
VIDEO_TYPE = "c:05"
|
||||
AUDIO_CHANNEL = "c:06"
|
||||
BIT_STREAM_DELAY = "c:07" # in ms
|
||||
PCM_DELAY = "c:08" # in ms
|
||||
SUBTITLE = "c:09"
|
||||
|
||||
|
||||
class Inversion(Enum):
|
||||
@@ -70,13 +101,15 @@ FEC = {"0": "Auto", "1": "1/2", "2": "2/3", "3": "3/4", "4": "5/6", "5": "7/8",
|
||||
"17": "4/5", "18": "9/10", "19": "1/2", "20": "2/3", "21": "3/4", "22": "5/6", "23": "7/8", "24": "8/9",
|
||||
"25": "3/5", "26": "4/5", "27": "9/10", "28": "Auto"}
|
||||
|
||||
FEC_DEFAULT = {"0": "Auto", "1": "1/2", "2": "2/3", "3": "3/4", "4": "5/6", "5": "7/8", "6": "8/9", "7": "3/5",
|
||||
"8": "4/5", "9": "9/10"}
|
||||
|
||||
SYSTEM = {"0": "DVB-S", "1": "DVB-S2"}
|
||||
|
||||
MODULATION = {"0": "Auto", "1": "QPSK", "2": "8PSK", "3": "16APSK", "5": "32APSK"}
|
||||
|
||||
SERVICE_TYPE = {"-2": "Unknown", "1": "TV", "2": "Radio", "3": "Data",
|
||||
"10": "Radio", "12": "Data", "22": "TV", "25": "TV (HD)", "31": "TV (UHD)",
|
||||
"136": "Data", "139": "Data"}
|
||||
SERVICE_TYPE = {"-2": "Data", "1": "TV", "2": "Radio", "3": "Data", "10": "Radio", "22": "TV (H264)",
|
||||
"25": "TV (HD)", "31": "TV (UHD)"}
|
||||
|
||||
CAS = {"C:2600": "BISS", "C:0b00": "Conax", "C:0b01": "Conax", "C:0b02": "Conax", "C:0baa": "Conax", "C:0602": "Irdeto",
|
||||
"C:0604": "Irdeto", "C:0606": "Irdeto", "C:0608": "Irdeto", "C:0622": "Irdeto", "C:0626": "Irdeto",
|
||||
@@ -85,3 +118,19 @@ CAS = {"C:2600": "BISS", "C:0b00": "Conax", "C:0b01": "Conax", "C:0b02": "Conax"
|
||||
|
||||
# 'on' attribute 0070(hex) = 112(int) = ONID(ONID-TID on www.lyngsat.com)
|
||||
PROVIDER = {112: "HTB+", 253: "Tricolor TV"}
|
||||
|
||||
|
||||
# ************* subsidiary functions ****************
|
||||
|
||||
def get_key_by_value(dc: dict, value):
|
||||
""" Returns key from dict by value """
|
||||
for k, v in dc.items():
|
||||
if v == value:
|
||||
return k
|
||||
|
||||
|
||||
def get_value_by_name(en, name):
|
||||
""" Returns value by name from enums """
|
||||
for n in en:
|
||||
if n.name == name:
|
||||
return n.value
|
||||
|
||||
@@ -52,7 +52,7 @@ def to_bouquet_id(ch):
|
||||
|
||||
def get_bouquet(path, name, bq_type):
|
||||
""" Parsing services ids from bouquet file """
|
||||
with open(path + "userbouquet.{}.{}".format(name, bq_type), encoding="utf-8") as file:
|
||||
with open(path + "userbouquet.{}.{}".format(name, bq_type), encoding="utf-8", errors="replace") as file:
|
||||
chs_list = file.read()
|
||||
services = []
|
||||
srvs = list(filter(None, chs_list.split("\n#SERVICE"))) # filtering ['']
|
||||
@@ -70,7 +70,7 @@ def get_bouquet(path, name, bq_type):
|
||||
|
||||
|
||||
def parse_bouquets(path, bq_name, bq_type):
|
||||
with open(path + bq_name) as file:
|
||||
with open(path + bq_name, encoding="utf-8", errors="replace") as file:
|
||||
lines = file.readlines()
|
||||
bouquets = None
|
||||
nm_sep = "#NAME"
|
||||
|
||||
@@ -101,7 +101,7 @@ def parse_services(services, transponders, path):
|
||||
all_flags = ch[2].split(",")
|
||||
coded = CODED_ICON if list(filter(lambda x: x.startswith("C:"), all_flags)) else None
|
||||
flags = list(filter(lambda x: x.startswith("f:"), all_flags))
|
||||
hide = HIDE_ICON if flags and int(flags[0][2:]) in Flag.hide_values() else None
|
||||
hide = HIDE_ICON if flags and Flag.is_hide(int(flags[0][2:])) else None
|
||||
locked = LOCKED_ICON if fav_id in blacklist else None
|
||||
|
||||
package = list(filter(lambda x: x.startswith("p:"), all_flags))
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"""
|
||||
from xml.dom.minidom import parse, Document
|
||||
|
||||
from .ecommons import POLARIZATION, FEC, SYSTEM, MODULATION, PLS_MODE, Transponder, Satellite
|
||||
from .ecommons import POLARIZATION, FEC, SYSTEM, MODULATION, PLS_MODE, Transponder, Satellite, get_key_by_value
|
||||
|
||||
__COMMENT = (" File was created in DemonEditor\n\n"
|
||||
"usable flags are\n"
|
||||
@@ -110,11 +110,5 @@ def parse_satellites(path):
|
||||
return satellites
|
||||
|
||||
|
||||
def get_key_by_value(dictionary, value):
|
||||
for k, v in dictionary.items():
|
||||
if v == value:
|
||||
return k
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pass
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import glob
|
||||
import os
|
||||
import shutil
|
||||
from collections import namedtuple
|
||||
from html.parser import HTMLParser
|
||||
|
||||
from app.commons import log
|
||||
from app.commons import log, run_task
|
||||
from app.properties import Profile
|
||||
|
||||
_ENIGMA2_PICON_KEY = "{:X}:{:X}:{:X}0000"
|
||||
@@ -184,5 +185,23 @@ def parse_providers(open_path):
|
||||
return [Provider(logo=r[2], name=r[5], pos=r[0], url=r[6], on_id=r[-2], selected=True) for r in rows]
|
||||
|
||||
|
||||
@run_task
|
||||
def convert_to(src_path, dest_path, profile, callback, done_callback):
|
||||
""" Converts names format of picons.
|
||||
|
||||
Copies resulting files from src to dest and writes state to callback.
|
||||
"""
|
||||
pattern = "/*_0_0_0.png" if profile is Profile.ENIGMA_2 else "/*.png"
|
||||
for file in glob.glob(src_path + pattern):
|
||||
base_name = os.path.basename(file)
|
||||
pic_data = base_name.rstrip(".png").split("_")
|
||||
dest_file = _NEUTRINO_PICON_KEY.format(int(pic_data[4], 16), int(pic_data[5], 16), int(pic_data[3], 16))
|
||||
dest = "{}/{}".format(dest_path, dest_file)
|
||||
callback('Converting "{}" to "{}"\n'.format(base_name, dest_file))
|
||||
shutil.copyfile(file, dest)
|
||||
|
||||
done_callback()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pass
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import locale
|
||||
|
||||
import gi
|
||||
import os
|
||||
|
||||
@@ -7,6 +9,12 @@ from gi.repository import Gtk, Gdk
|
||||
# path to *.glade files
|
||||
UI_RESOURCES_PATH = "app/ui/" if os.path.exists("app/ui/") else "/usr/share/demoneditor/app/ui/"
|
||||
|
||||
# translation
|
||||
TEXT_DOMAIN = "demon-editor"
|
||||
if UI_RESOURCES_PATH == "app/ui/":
|
||||
LANG_DIR = UI_RESOURCES_PATH + "lang"
|
||||
locale.bindtextdomain(TEXT_DOMAIN, UI_RESOURCES_PATH + "lang")
|
||||
|
||||
theme = Gtk.IconTheme.get_default()
|
||||
_IMAGE_MISSING = theme.load_icon("image-missing", 16, 0) if theme.lookup_icon("image-missing", 16, 0) else None
|
||||
CODED_ICON = theme.load_icon("emblem-readonly", 16, 0) if theme.lookup_icon(
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
<property name="icon_name">system-help</property>
|
||||
<property name="type_hint">normal</property>
|
||||
<property name="program_name">DemonEditor</property>
|
||||
<property name="version">0.2.4 Pre-alpha</property>
|
||||
<property name="copyright" translatable="yes">2018 Dmitriy Yefremov
|
||||
<property name="version">0.3.0 Pre-alpha</property>
|
||||
<property name="copyright">2018 Dmitriy Yefremov
|
||||
dmitry.v.yefremov@gmail.com
|
||||
</property>
|
||||
<property name="comments" translatable="yes">Enigma2 channel and satellites list editor for GNU/Linux</property>
|
||||
@@ -111,7 +111,7 @@ dmitry.v.yefremov@gmail.com
|
||||
<property name="can_focus">True</property>
|
||||
<property name="editable">False</property>
|
||||
<property name="max_width_chars">10</property>
|
||||
<property name="text" translatable="yes">127.0.0.1</property>
|
||||
<property name="text">127.0.0.1</property>
|
||||
<property name="caps_lock_warning">False</property>
|
||||
<property name="primary_icon_name">network-transmit-receive-symbolic</property>
|
||||
</object>
|
||||
@@ -137,7 +137,7 @@ dmitry.v.yefremov@gmail.com
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="editable">False</property>
|
||||
<property name="text" translatable="yes">data/</property>
|
||||
<property name="text">data/</property>
|
||||
<property name="caps_lock_warning">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
@@ -720,7 +720,7 @@ dmitry.v.yefremov@gmail.com
|
||||
<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="text">127.0.0.1</property>
|
||||
<property name="primary_icon_name">network-transmit-receive-symbolic</property>
|
||||
</object>
|
||||
<packing>
|
||||
@@ -754,7 +754,7 @@ dmitry.v.yefremov@gmail.com
|
||||
<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="text">21</property>
|
||||
<property name="primary_icon_name">network-workgroup-symbolic</property>
|
||||
</object>
|
||||
<packing>
|
||||
@@ -777,7 +777,7 @@ dmitry.v.yefremov@gmail.com
|
||||
<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="text">root</property>
|
||||
<property name="primary_icon_name">avatar-default-symbolic</property>
|
||||
<property name="primary_icon_activatable">False</property>
|
||||
</object>
|
||||
@@ -792,7 +792,7 @@ dmitry.v.yefremov@gmail.com
|
||||
<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="text">root</property>
|
||||
<property name="primary_icon_name">emblem-readonly</property>
|
||||
<property name="primary_icon_activatable">False</property>
|
||||
<property name="input_purpose">password</property>
|
||||
@@ -802,6 +802,9 @@ dmitry.v.yefremov@gmail.com
|
||||
<property name="top_attach">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<style>
|
||||
<class name="primary-toolbar"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
<child type="tab">
|
||||
@@ -857,7 +860,7 @@ dmitry.v.yefremov@gmail.com
|
||||
<object class="GtkLabel" id="label16">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Loggin:</property>
|
||||
<property name="label" translatable="yes">Login:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
@@ -914,6 +917,9 @@ dmitry.v.yefremov@gmail.com
|
||||
<property name="top_attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<style>
|
||||
<class name="primary-toolbar"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
@@ -981,7 +987,8 @@ dmitry.v.yefremov@gmail.com
|
||||
<object class="GtkEntry" id="services_field">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="text" translatable="yes">/etc/enigma2/</property>
|
||||
<property name="text">/etc/enigma2/</property>
|
||||
<property name="primary_icon_stock">gtk-edit</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
@@ -1004,7 +1011,8 @@ dmitry.v.yefremov@gmail.com
|
||||
<object class="GtkEntry" id="user_bouquet_field">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="text" translatable="yes">/etc/enigma2/</property>
|
||||
<property name="text">/etc/enigma2/</property>
|
||||
<property name="primary_icon_stock">gtk-edit</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
@@ -1027,7 +1035,8 @@ dmitry.v.yefremov@gmail.com
|
||||
<object class="GtkEntry" id="satellites_xml_field">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="text" translatable="yes">/etc/tuxbox/</property>
|
||||
<property name="text">/etc/tuxbox/</property>
|
||||
<property name="primary_icon_stock">gtk-edit</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
@@ -1050,7 +1059,8 @@ dmitry.v.yefremov@gmail.com
|
||||
<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>
|
||||
<property name="text">/usr/share/enigma2/picon</property>
|
||||
<property name="primary_icon_stock">gtk-edit</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
@@ -1089,7 +1099,7 @@ dmitry.v.yefremov@gmail.com
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Active profile:</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="xalign">0.20000000298023224</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
@@ -1099,7 +1109,7 @@ dmitry.v.yefremov@gmail.com
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkRadioButton" id="enigma_radio_button">
|
||||
<property name="label" translatable="yes">Enigma2 </property>
|
||||
<property name="label">Enigma2 </property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
@@ -1117,7 +1127,7 @@ dmitry.v.yefremov@gmail.com
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkRadioButton" id="neutrino_radio_button">
|
||||
<property name="label" translatable="yes">Neutrino-MP
|
||||
<property name="label">Neutrino-MP
|
||||
(experimental)</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
@@ -1198,7 +1208,8 @@ dmitry.v.yefremov@gmail.com
|
||||
<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="text">/data</property>
|
||||
<property name="primary_icon_stock">gtk-edit</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>
|
||||
@@ -1217,18 +1228,6 @@ dmitry.v.yefremov@gmail.com
|
||||
<property name="position">5</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparator" id="separator3">
|
||||
<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">6</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label18">
|
||||
<property name="visible">True</property>
|
||||
@@ -1239,20 +1238,33 @@ dmitry.v.yefremov@gmail.com
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">8</property>
|
||||
<property name="position">7</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="text">/data/picons</property>
|
||||
<property name="primary_icon_stock">gtk-edit</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">8</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparator" id="separator3">
|
||||
<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">9</property>
|
||||
</packing>
|
||||
</child>
|
||||
@@ -1263,4 +1275,75 @@ dmitry.v.yefremov@gmail.com
|
||||
<action-widget response="-5">ok_button</action-widget>
|
||||
</action-widgets>
|
||||
</object>
|
||||
<object class="GtkDialog" id="wait_dialog">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="resizable">False</property>
|
||||
<property name="modal">True</property>
|
||||
<property name="window_position">center-on-parent</property>
|
||||
<property name="destroy_with_parent">True</property>
|
||||
<property name="type_hint">splashscreen</property>
|
||||
<property name="skip_taskbar_hint">True</property>
|
||||
<property name="skip_pager_hint">True</property>
|
||||
<property name="decorated">False</property>
|
||||
<child internal-child="vbox">
|
||||
<object class="GtkBox" id="dialog-vbox4">
|
||||
<property name="width_request">118</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child internal-child="action_area">
|
||||
<object class="GtkButtonBox" id="dialog-action_area4">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="opacity">0</property>
|
||||
<property name="layout_style">end</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="box4">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkSpinner" id="spinner">
|
||||
<property name="width_request">150</property>
|
||||
<property name="height_request">45</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="active">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label21">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Loading data...</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">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<style>
|
||||
<class name="primary-toolbar"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
|
||||
@@ -1,24 +1,37 @@
|
||||
""" Common module for showing dialogs """
|
||||
import locale
|
||||
from enum import Enum
|
||||
|
||||
from . import Gtk, UI_RESOURCES_PATH
|
||||
from app.commons import run_idle
|
||||
from . import Gtk, UI_RESOURCES_PATH, TEXT_DOMAIN
|
||||
|
||||
|
||||
class DialogType(Enum):
|
||||
INPUT = "input_dialog"
|
||||
MESSAGE = ""
|
||||
CHOOSER = "path_chooser_dialog"
|
||||
ERROR = "error_dialog"
|
||||
QUESTION = "question_dialog"
|
||||
ABOUT = "about_dialog"
|
||||
WAIT = "wait_dialog"
|
||||
|
||||
|
||||
class WaitDialog:
|
||||
def __init__(self, transient):
|
||||
builder, dialog = get_dialog_from_xml(DialogType.WAIT, transient)
|
||||
self._dialog = dialog
|
||||
self._dialog.set_transient_for(transient)
|
||||
|
||||
def show(self):
|
||||
self._dialog.show()
|
||||
|
||||
@run_idle
|
||||
def hide(self):
|
||||
self._dialog.hide()
|
||||
|
||||
|
||||
def show_dialog(dialog_type: DialogType, transient, text=None, options=None, action_type=None, file_filter=None):
|
||||
""" Shows dialogs by name """
|
||||
builder = Gtk.Builder()
|
||||
builder.add_from_file(UI_RESOURCES_PATH + "dialogs.glade")
|
||||
dialog = builder.get_object(dialog_type.value)
|
||||
dialog.set_transient_for(transient)
|
||||
builder, dialog = get_dialog_from_xml(dialog_type, transient)
|
||||
|
||||
if dialog_type is DialogType.CHOOSER and options:
|
||||
if action_type is not None:
|
||||
@@ -51,13 +64,22 @@ def show_dialog(dialog_type: DialogType, transient, text=None, options=None, act
|
||||
return txt if response == Gtk.ResponseType.OK else Gtk.ResponseType.CANCEL
|
||||
|
||||
if text:
|
||||
dialog.set_markup(text)
|
||||
dialog.set_markup(get_message(text))
|
||||
response = dialog.run()
|
||||
dialog.destroy()
|
||||
|
||||
return response
|
||||
|
||||
|
||||
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")
|
||||
dialog = builder.get_object(dialog_type.value)
|
||||
dialog.set_transient_for(transient)
|
||||
return builder, dialog
|
||||
|
||||
|
||||
def get_chooser_dialog(transient, options, pattern, name):
|
||||
file_filter = Gtk.FileFilter()
|
||||
file_filter.add_pattern(pattern)
|
||||
@@ -69,5 +91,10 @@ def get_chooser_dialog(transient, options, pattern, name):
|
||||
file_filter=file_filter)
|
||||
|
||||
|
||||
def get_message(message):
|
||||
""" returns translated message """
|
||||
return locale.dgettext(TEXT_DOMAIN, message)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pass
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from app.commons import run_idle, run_task
|
||||
from app.ftp import download_data, DownloadDataType, upload_data
|
||||
from app.properties import Profile
|
||||
from . import Gtk, UI_RESOURCES_PATH
|
||||
from . import Gtk, UI_RESOURCES_PATH, TEXT_DOMAIN
|
||||
from .dialogs import show_dialog, DialogType
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ class DownloadDialog:
|
||||
"on_info_bar_close": self.on_info_bar_close}
|
||||
|
||||
builder = Gtk.Builder()
|
||||
builder.set_translation_domain(TEXT_DOMAIN)
|
||||
builder.add_objects_from_file(UI_RESOURCES_PATH + "dialogs.glade", ("download_dialog",))
|
||||
builder.connect_signals(handlers)
|
||||
|
||||
|
||||
BIN
app/ui/lang/ru/LC_MESSAGES/demon-editor.mo
Normal file
BIN
app/ui/lang/ru/LC_MESSAGES/demon-editor.mo
Normal file
Binary file not shown.
@@ -11,11 +11,13 @@ 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 .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
|
||||
from .dialogs import show_dialog, DialogType, get_chooser_dialog, WaitDialog, get_message
|
||||
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, get_base_model, update_picons, copy_picon_reference, assign_picon, remove_picon, search
|
||||
from .main_helper import edit_marker, insert_marker, move_items, rename, ViewTarget, set_flags, locate_in_services, \
|
||||
scroll_to, get_base_model, update_picons, copy_picon_reference, assign_picon, remove_picon, \
|
||||
is_only_one_item_selected
|
||||
from .picons_dialog import PiconsDialog
|
||||
from .satellites_dialog import show_satellites_dialog
|
||||
from .settings_dialog import show_settings_dialog
|
||||
@@ -23,9 +25,14 @@ from .service_details_dialog import ServiceDetailsDialog
|
||||
|
||||
|
||||
class MainAppWindow:
|
||||
_TV_TYPES = ("TV", "TV (HD)", "TV (UHD)", "TV (H264)")
|
||||
|
||||
_SERVICE_LIST_NAME = "services_list_store"
|
||||
|
||||
_FAV_LIST_NAME = "fav_list_store"
|
||||
|
||||
_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_picon_popup_item")
|
||||
@@ -76,7 +83,7 @@ class MainAppWindow:
|
||||
"on_cut": self.on_cut,
|
||||
"on_copy": self.on_copy,
|
||||
"on_paste": self.on_paste,
|
||||
"on_edit": self.on_edit,
|
||||
"on_edit": self.on_rename,
|
||||
"on_delete": self.on_delete,
|
||||
"on_new_bouquet": self.on_new_bouquet,
|
||||
"on_bouquets_edit": self.on_bouquets_edit,
|
||||
@@ -102,8 +109,10 @@ class MainAppWindow:
|
||||
"on_reference_picon": self.on_reference_picon,
|
||||
"on_filter_toggled": self.on_filter_toggled,
|
||||
"on_search_toggled": self.on_search_toggled,
|
||||
"on_search_down": self.on_search_down,
|
||||
"on_search_up": self.on_search_up,
|
||||
"on_search": self.on_search,
|
||||
"on_services_data_edit": self.on_services_data_edit}
|
||||
"on_service_edit": self.on_service_edit}
|
||||
|
||||
self.__options = get_config()
|
||||
self.__profile = self.__options.get("profile")
|
||||
@@ -117,6 +126,7 @@ class MainAppWindow:
|
||||
self.__blacklist = set()
|
||||
|
||||
builder = Gtk.Builder()
|
||||
builder.set_translation_domain("demon-editor")
|
||||
builder.add_from_file(UI_RESOURCES_PATH + "main_window.glade")
|
||||
builder.connect_signals(handlers)
|
||||
self.__main_window = builder.get_object("main_window")
|
||||
@@ -132,7 +142,8 @@ class MainAppWindow:
|
||||
self.__bouquets_model = builder.get_object("bouquets_tree_store")
|
||||
self.__status_bar = builder.get_object("status_bar")
|
||||
self.__profile_label = builder.get_object("profile_label")
|
||||
self.__status_bar.push(0, "Current IP: " + self.__options.get(self.__profile).get("host"))
|
||||
self.__ip_label = builder.get_object("ip_label")
|
||||
self.__ip_label.set_text(self.__options.get(self.__profile).get("host"))
|
||||
self.__profile_label.set_text("Enigma2 v.4" if Profile(self.__profile) is Profile.ENIGMA_2 else "Neutrino-MP")
|
||||
# dynamically active elements depending on the selected view
|
||||
self.__tool_elements = {k: builder.get_object(k) for k in self.__DYNAMIC_ELEMENTS}
|
||||
@@ -144,18 +155,23 @@ 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")
|
||||
self.__search_info_bar = builder.get_object("search_info_bar")
|
||||
# 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.__filter_info_bar = builder.get_object("filter_info_bar")
|
||||
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)
|
||||
# Clipboard
|
||||
self.__clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
|
||||
# Wait dialog
|
||||
self.__wait_dialog = WaitDialog(self.__main_window)
|
||||
# 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.__filter_info_bar = builder.get_object("filter_info_bar")
|
||||
# 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.__main_window.show()
|
||||
|
||||
def init_drag_and_drop(self):
|
||||
@@ -239,16 +255,17 @@ class MainAppWindow:
|
||||
self.__rows_buffer.clear()
|
||||
self.on_view_focus(view, None)
|
||||
|
||||
def on_edit(self, view):
|
||||
def on_rename(self, view):
|
||||
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)
|
||||
elif name == self._FAV_LIST_NAME:
|
||||
edit(view, self.__main_window, ViewTarget.FAV, service_view=self.__services_view, channels=self.__services)
|
||||
rename(view, self.__main_window, ViewTarget.FAV, service_view=self.__services_view,
|
||||
channels=self.__services)
|
||||
elif name == self._SERVICE_LIST_NAME:
|
||||
edit(view, self.__main_window, ViewTarget.SERVICES, fav_view=self.__fav_view, channels=self.__services)
|
||||
rename(view, self.__main_window, ViewTarget.SERVICES, fav_view=self.__fav_view, channels=self.__services)
|
||||
|
||||
def on_delete(self, item):
|
||||
""" Delete selected items from views
|
||||
@@ -361,11 +378,11 @@ class MainAppWindow:
|
||||
def on_tool_edit(self, item):
|
||||
""" Edit tool bar button """
|
||||
if self.__services_view.is_focus():
|
||||
self.on_edit(self.__services_view)
|
||||
self.on_service_edit(self.__services_view)
|
||||
elif self.__fav_view.is_focus():
|
||||
self.on_edit(self.__fav_view)
|
||||
self.on_service_edit(self.__fav_view)
|
||||
elif self.__bouquets_view.is_focus():
|
||||
self.on_edit(self.__bouquets_view)
|
||||
self.on_rename(self.__bouquets_view)
|
||||
|
||||
def on_bouquets_edit(self, view):
|
||||
""" Rename bouquets """
|
||||
@@ -494,6 +511,7 @@ class MainAppWindow:
|
||||
@run_idle
|
||||
def open_data(self, data_path=None):
|
||||
""" Opening data and fill views. """
|
||||
self.__wait_dialog.show()
|
||||
self.clear_current_data()
|
||||
|
||||
data_path = self.__options.get(self.__profile).get("data_dir_path") if data_path is None else data_path
|
||||
@@ -503,12 +521,13 @@ class MainAppWindow:
|
||||
self.append_services(data_path)
|
||||
self.update_services_counts(len(self.__services_model))
|
||||
self.update_picons()
|
||||
self.__picons_download_tool_button.set_sensitive(len(self.__services_model))
|
||||
except FileNotFoundError as e:
|
||||
show_dialog(DialogType.ERROR, self.__main_window, getattr(e, "message", str(e)) +
|
||||
"\n\nPlease, download files from receiver or setup your path for read data!")
|
||||
show_dialog(DialogType.ERROR, self.__main_window, getattr(e, "message", str(e)) + "\n\n" +
|
||||
get_message("Please, download files from receiver or setup your path for read data!"))
|
||||
except SyntaxError as e:
|
||||
show_dialog(DialogType.ERROR, self.__main_window, str(e))
|
||||
finally:
|
||||
self.__wait_dialog.hide()
|
||||
|
||||
def append_blacklist(self, data_path):
|
||||
black_list = get_blacklist(data_path)
|
||||
@@ -540,7 +559,7 @@ class MainAppWindow:
|
||||
except Exception as e:
|
||||
print(e)
|
||||
log("Append services error: " + str(e))
|
||||
show_dialog(DialogType.ERROR, self.__main_window, "Error opening data!")
|
||||
show_dialog(DialogType.ERROR, self.__main_window, "Reading data error!")
|
||||
else:
|
||||
if services:
|
||||
for srv in services:
|
||||
@@ -664,13 +683,12 @@ class MainAppWindow:
|
||||
response = show_settings_dialog(self.__main_window, self.__options)
|
||||
if response != Gtk.ResponseType.CANCEL:
|
||||
profile = self.__options.get("profile")
|
||||
self.__status_bar.push(0, "Current IP: " + self.__options.get(profile).get("host"))
|
||||
self.__ip_label.set_text(self.__options.get(profile).get("host"))
|
||||
if profile != self.__profile:
|
||||
self.__profile_label.set_text("Enigma 2 v.4" if Profile(profile) is Profile.ENIGMA_2 else "Neutrino-MP")
|
||||
self.__profile = profile
|
||||
self.clear_current_data()
|
||||
self.update_services_counts()
|
||||
self.__picons_download_tool_button.set_sensitive(len(self.__services_model))
|
||||
|
||||
def on_tree_view_key_release(self, view, event):
|
||||
""" Handling keystrokes """
|
||||
@@ -708,15 +726,13 @@ class MainAppWindow:
|
||||
self.on_locked(None)
|
||||
elif ctrl and key == Gdk.KEY_h or key == Gdk.KEY_H:
|
||||
self.on_hide(None)
|
||||
elif ctrl and key == Gdk.KEY_R or key == Gdk.KEY_r:
|
||||
self.on_edit(view)
|
||||
elif ctrl and key == Gdk.KEY_E or key == Gdk.KEY_e or key == Gdk.KEY_F2:
|
||||
elif ctrl and key == Gdk.KEY_R or key == Gdk.KEY_r or key == Gdk.KEY_F2:
|
||||
self.on_rename(view)
|
||||
elif ctrl and key == Gdk.KEY_E or key == Gdk.KEY_e:
|
||||
if model_name == self._BOUQUETS_LIST_NAME:
|
||||
self.on_edit(view)
|
||||
self.on_rename(view)
|
||||
return
|
||||
elif model_name == self._FAV_LIST_NAME:
|
||||
self.on_locate_in_services(view)
|
||||
self.on_services_data_edit(view)
|
||||
self.on_service_edit(view)
|
||||
elif key == Gdk.KEY_Left or key == Gdk.KEY_Right:
|
||||
view.do_unselect_all(view)
|
||||
|
||||
@@ -810,7 +826,7 @@ class MainAppWindow:
|
||||
|
||||
for ch in self.__services.values():
|
||||
ch_type = ch.service_type
|
||||
if ch_type in ("TV", "TV (HD)"):
|
||||
if ch_type in self._TV_TYPES:
|
||||
tv_count += 1
|
||||
elif ch_type == "Radio":
|
||||
radio_count += 1
|
||||
@@ -866,7 +882,7 @@ class MainAppWindow:
|
||||
data = r[9].split("_")
|
||||
ids["{}:{}:{}".format(data[3], data[5], data[6])] = r[9]
|
||||
|
||||
dialog = PiconsDialog(self.__main_window, self.__options.get(self.__profile), ids, Profile(self.__profile))
|
||||
dialog = PiconsDialog(self.__main_window, self.__options, ids, Profile(self.__profile))
|
||||
dialog.show()
|
||||
self.update_picons()
|
||||
|
||||
@@ -887,19 +903,34 @@ class MainAppWindow:
|
||||
def on_search_toggled(self, toggle_button: Gtk.ToggleToolButton):
|
||||
self.__search_info_bar.set_visible(toggle_button.get_active())
|
||||
|
||||
@run_idle
|
||||
def on_search(self, entry, event):
|
||||
search(entry.get_text(),
|
||||
self.__services_view,
|
||||
self.__fav_view,
|
||||
self.__bouquets_view,
|
||||
self.__services,
|
||||
self.__bouquets)
|
||||
def on_search_down(self, item):
|
||||
self.__search_provider.on_search_down()
|
||||
|
||||
def on_search_up(self, item):
|
||||
self.__search_provider.on_search_up()
|
||||
|
||||
@run_idle
|
||||
def on_services_data_edit(self, item):
|
||||
dialog = ServiceDetailsDialog(self.__main_window, self.__options, self.__services_view)
|
||||
dialog.show()
|
||||
def on_search(self, entry):
|
||||
self.__search_provider.search(entry.get_text())
|
||||
|
||||
@run_idle
|
||||
def on_service_edit(self, view):
|
||||
model, paths = view.get_selection().get_selected_rows()
|
||||
if is_only_one_item_selected(paths, self.__main_window):
|
||||
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
|
||||
self.on_locate_in_services(view)
|
||||
|
||||
dialog = ServiceDetailsDialog(self.__main_window,
|
||||
self.__options,
|
||||
self.__services_view,
|
||||
self.__services,
|
||||
self.__bouquets)
|
||||
dialog.show()
|
||||
|
||||
@run_idle
|
||||
def update_picons(self):
|
||||
|
||||
@@ -96,9 +96,9 @@ def move_items(key, view):
|
||||
model.move_after(itr, down_itr)
|
||||
|
||||
|
||||
# ***************** Edit *******************#
|
||||
# ***************** Rename *******************#
|
||||
|
||||
def edit(view, parent_window, target, fav_view=None, service_view=None, channels=None):
|
||||
def rename(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)
|
||||
|
||||
@@ -223,18 +223,18 @@ def set_hide(channels, model, paths):
|
||||
value = int(flag[2:]) if flag else 0
|
||||
|
||||
if not hide:
|
||||
if value in Flag.hide_values():
|
||||
if Flag.is_hide(value):
|
||||
continue # skip if already hidden
|
||||
value += Flag.HIDE.value
|
||||
else:
|
||||
if value not in Flag.hide_values():
|
||||
if not Flag.is_hide(value):
|
||||
continue # skip if already allowed to show
|
||||
value -= Flag.HIDE.value
|
||||
|
||||
if value == 0 and index is not None:
|
||||
del flags[index]
|
||||
else:
|
||||
value = "f:{}".format(value) if value > 10 else "f:0{}".format(value)
|
||||
value = "f:{:02d}".format(value)
|
||||
if index is not None:
|
||||
flags[index] = value
|
||||
else:
|
||||
@@ -411,30 +411,8 @@ def get_picon_pixbuf(path):
|
||||
return GdkPixbuf.Pixbuf.new_from_file_at_scale(filename=path, width=32, height=32, preserve_aspect_ratio=True)
|
||||
|
||||
|
||||
# ***************** Search *********************#
|
||||
|
||||
def search(text, srv_view, fav_view, bqs_view, services, bouquets):
|
||||
for view in srv_view, fav_view:
|
||||
model = get_base_model(view.get_model())
|
||||
selection = view.get_selection()
|
||||
selection.unselect_all()
|
||||
if not text:
|
||||
continue
|
||||
paths = []
|
||||
text = text.upper()
|
||||
for r in model:
|
||||
if text in str(r[:]).upper():
|
||||
path = r.path
|
||||
selection.select_path(r.path)
|
||||
paths.append(path)
|
||||
|
||||
if paths:
|
||||
view.scroll_to_cell(paths[0], None)
|
||||
|
||||
|
||||
# ***************** 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)
|
||||
|
||||
@@ -117,11 +117,6 @@
|
||||
<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="stock">gtk-properties</property>
|
||||
</object>
|
||||
<object class="GtkImage" id="image4">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
@@ -175,7 +170,7 @@
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="activate" handler="on_edit" object="fav_tree_view" swapped="no"/>
|
||||
<signal name="activate" handler="on_service_edit" object="fav_tree_view" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
@@ -369,23 +364,7 @@
|
||||
<property name="resize_mode">immediate</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="activate" handler="on_edit" 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_data_edit_popup_item">
|
||||
<property name="label" translatable="yes">Show details/edit</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="image">image17</property>
|
||||
<property name="use_stock">False</property>
|
||||
<signal name="activate" handler="on_services_data_edit" object="services_tree_view" swapped="no"/>
|
||||
<signal name="activate" handler="on_service_edit" object="services_tree_view" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
@@ -408,7 +387,7 @@
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="services_assign_picon_popup_item">
|
||||
<property name="label">Assign</property>
|
||||
<property name="label" translatable="yes">Assign</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="image">image11</property>
|
||||
@@ -418,7 +397,7 @@
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="services_remove_picon_popup_item">
|
||||
<property name="label">Remove</property>
|
||||
<property name="label" translatable="yes">Remove</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="image">image12</property>
|
||||
@@ -558,7 +537,7 @@
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="download_menu_item">
|
||||
<property name="label">Download</property>
|
||||
<property name="label" translatable="yes">Download</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="tooltip_text" translatable="yes">FTP-transfer</property>
|
||||
@@ -1111,7 +1090,6 @@
|
||||
<child>
|
||||
<object class="GtkToolButton" id="picons_download_tool_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="tooltip_text" translatable="yes">Picons</property>
|
||||
<property name="label" translatable="yes">Picons loader</property>
|
||||
@@ -1215,14 +1193,65 @@
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSearchEntry" id="search_entry">
|
||||
<property name="width_request">200</property>
|
||||
<object class="GtkBox" id="search_bar_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="primary_icon_name">edit-find-symbolic</property>
|
||||
<property name="primary_icon_activatable">False</property>
|
||||
<property name="primary_icon_sensitive">False</property>
|
||||
<signal name="key-release-event" handler="on_search" swapped="no"/>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkSearchEntry" id="search_entry">
|
||||
<property name="width_request">200</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="primary_icon_name">edit-find-symbolic</property>
|
||||
<property name="primary_icon_activatable">False</property>
|
||||
<property name="primary_icon_sensitive">False</property>
|
||||
<signal name="search-changed" handler="on_search" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="search_down_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<signal name="clicked" handler="on_search_down" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkArrow" id="arrow1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="arrow_type">down</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="search_up_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<signal name="clicked" handler="on_search_up" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkArrow" id="arrow2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="arrow_type">up</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
@@ -1288,6 +1317,9 @@
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Services</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
@@ -1323,7 +1355,7 @@
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="cas_column">
|
||||
<property name="visible">False</property>
|
||||
<property name="title" translatable="yes">CAS</property>
|
||||
<property name="title">CAS</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="cas_cellrenderertext1"/>
|
||||
<attributes>
|
||||
@@ -1335,7 +1367,7 @@
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="type_column">
|
||||
<property name="visible">False</property>
|
||||
<property name="title" translatable="yes">Type</property>
|
||||
<property name="title">Type</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="type_cellrenderertext2"/>
|
||||
<attributes>
|
||||
@@ -1430,7 +1462,7 @@
|
||||
<object class="GtkTreeViewColumn" id="picon_id_column">
|
||||
<property name="visible">False</property>
|
||||
<property name="sizing">fixed</property>
|
||||
<property name="title" translatable="yes">Picon ID</property>
|
||||
<property name="title">Picon ID</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="picon_id_cellrenderertext"/>
|
||||
<attributes>
|
||||
@@ -1443,7 +1475,7 @@
|
||||
<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="title">SID</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="reorderable">True</property>
|
||||
<property name="sort_column_id">10</property>
|
||||
@@ -1515,7 +1547,7 @@
|
||||
<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="title">FEC</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="reorderable">True</property>
|
||||
<property name="sort_column_id">14</property>
|
||||
@@ -1567,7 +1599,7 @@
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="data_id_column">
|
||||
<property name="visible">False</property>
|
||||
<property name="title" translatable="yes">data_id</property>
|
||||
<property name="title">data_id</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="data_id_cellrenderertext"/>
|
||||
<attributes>
|
||||
@@ -1579,7 +1611,7 @@
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="service_fav_id_column">
|
||||
<property name="visible">False</property>
|
||||
<property name="title" translatable="yes">fav_id</property>
|
||||
<property name="title">fav_id</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="fav_id_cellrenderertext"/>
|
||||
<attributes>
|
||||
@@ -1591,7 +1623,7 @@
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="transponder_column">
|
||||
<property name="visible">False</property>
|
||||
<property name="title" translatable="yes">transponder</property>
|
||||
<property name="title">transponder</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="transponder_cellrenderertext"/>
|
||||
<attributes>
|
||||
@@ -1845,6 +1877,9 @@
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Bouquet details</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
@@ -1963,7 +1998,7 @@
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="fav_id_column">
|
||||
<property name="visible">False</property>
|
||||
<property name="title" translatable="yes">fav_id</property>
|
||||
<property name="title">fav_id</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="fav_id_cellrenderertext4"/>
|
||||
<attributes>
|
||||
@@ -2040,6 +2075,9 @@
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Bouquets</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
@@ -2102,7 +2140,7 @@
|
||||
<property name="visible">False</property>
|
||||
<property name="resizable">True</property>
|
||||
<property name="sizing">autosize</property>
|
||||
<property name="title" translatable="yes">Type</property>
|
||||
<property name="title">Type</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="bouquet_type_cellrenderertext"/>
|
||||
<attributes>
|
||||
@@ -2184,7 +2222,7 @@
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparator" id="separator4">
|
||||
<object class="GtkSeparator" id="bottom_separator">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_bottom">2</property>
|
||||
@@ -2192,25 +2230,59 @@
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="padding">2</property>
|
||||
<property name="position">5</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStatusbar" id="status_bar">
|
||||
<object class="GtkBox" id="status_bar_box">
|
||||
<property name="height_request">24</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_start">10</property>
|
||||
<property name="margin_end">10</property>
|
||||
<property name="spacing">2</property>
|
||||
<property name="homogeneous">True</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="box1">
|
||||
<object class="GtkBox" id="ip_status_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">2</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label1">
|
||||
<object class="GtkLabel" id="label2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Current IP:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="ip_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">127.0.0.1</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="padding">5</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="prifile_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">2</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label3">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Profile:</property>
|
||||
@@ -2225,7 +2297,7 @@
|
||||
<object class="GtkLabel" id="profile_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Enigma 2 v.4</property>
|
||||
<property name="label">Enigma 2 v.4</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
@@ -2244,20 +2316,24 @@
|
||||
<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.4 Pre-alpha</property>
|
||||
<property name="label">Ver. 0.3.0 Pre-alpha</property>
|
||||
<property name="xalign">0.94999998807907104</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<style>
|
||||
<class name="primary-toolbar"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">7</property>
|
||||
<property name="position">6</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,10 +7,10 @@ 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.picons.picons import PiconsParser, parse_providers, Provider, convert_to
|
||||
from app.properties import Profile
|
||||
from . import Gtk, Gdk, UI_RESOURCES_PATH
|
||||
from .dialogs import show_dialog, DialogType
|
||||
from . import Gtk, Gdk, UI_RESOURCES_PATH, TEXT_DOMAIN
|
||||
from .dialogs import show_dialog, DialogType, get_message
|
||||
from .main_helper import update_entry_data
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ class PiconsDialog:
|
||||
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,
|
||||
@@ -33,9 +32,12 @@ class PiconsDialog:
|
||||
"on_picons_dir_open": self.on_picons_dir_open,
|
||||
"on_selected_toggled": self.on_selected_toggled,
|
||||
"on_url_changed": self.on_url_changed,
|
||||
"on_position_edited": self.on_position_edited}
|
||||
"on_position_edited": self.on_position_edited,
|
||||
"on_notebook_switch_page": self.on_notebook_switch_page,
|
||||
"on_convert": self.on_convert}
|
||||
|
||||
builder = Gtk.Builder()
|
||||
builder.set_translation_domain(TEXT_DOMAIN)
|
||||
builder.add_objects_from_file(UI_RESOURCES_PATH + "picons_dialog.glade",
|
||||
("picons_dialog", "receive_image", "providers_list_store"))
|
||||
builder.connect_signals(handlers)
|
||||
@@ -54,6 +56,10 @@ class PiconsDialog:
|
||||
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._convert_tool_button = builder.get_object("convert_tool_button")
|
||||
self._enigma2_path_button = builder.get_object("enigma2_path_button")
|
||||
self._save_to_button = builder.get_object("save_to_button")
|
||||
self._send_tool_button = builder.get_object("send_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")
|
||||
@@ -64,13 +70,15 @@ class PiconsDialog:
|
||||
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._properties = options.get(profile.value)
|
||||
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._ip_entry.set_text(self._properties.get("host", ""))
|
||||
self._picons_entry.set_text(self._properties.get("picons_path", ""))
|
||||
self._picons_path = self._properties.get("picons_dir_path", "")
|
||||
self._picons_dir_entry.set_text(self._picons_path)
|
||||
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", "")
|
||||
|
||||
def show(self):
|
||||
self._dialog.run()
|
||||
@@ -122,7 +130,7 @@ class PiconsDialog:
|
||||
|
||||
def process_provider(self, prv):
|
||||
url = prv.url
|
||||
self.show_info_message("Please, wait...", Gtk.MessageType.INFO)
|
||||
self.show_info_message(get_message("Please, wait..."), Gtk.MessageType.INFO)
|
||||
self._current_process = subprocess.Popen(["wget", "-pkP", self._TMP_DIR, url],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
@@ -158,7 +166,7 @@ class PiconsDialog:
|
||||
if self._resize_no_radio_button.get_active():
|
||||
return
|
||||
|
||||
self.show_info_message("Resizing...", Gtk.MessageType.INFO)
|
||||
self.show_info_message(get_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)
|
||||
@@ -180,7 +188,7 @@ class PiconsDialog:
|
||||
if show_dialog(DialogType.QUESTION, self._dialog) == Gtk.ResponseType.CANCEL:
|
||||
return
|
||||
|
||||
self.show_info_message("Please, wait...", Gtk.MessageType.INFO)
|
||||
self.show_info_message(get_message("Please, wait..."), Gtk.MessageType.INFO)
|
||||
self.upload_picons()
|
||||
|
||||
@run_task
|
||||
@@ -192,7 +200,7 @@ class PiconsDialog:
|
||||
upload_data(properties=self._properties,
|
||||
download_type=DownloadDataType.PICONS,
|
||||
profile=self._profile,
|
||||
callback=lambda: self.show_info_message("Done!", Gtk.MessageType.INFO))
|
||||
callback=lambda: self.show_info_message(get_message("Done!"), Gtk.MessageType.INFO))
|
||||
|
||||
def on_info_bar_close(self, bar=None, resp=None):
|
||||
self._info_bar.set_visible(False)
|
||||
@@ -221,6 +229,34 @@ class PiconsDialog:
|
||||
model = self._providers_tree_view.get_model()
|
||||
model.set_value(model.get_iter(path), 2, value)
|
||||
|
||||
@run_idle
|
||||
def on_notebook_switch_page(self, nb, box, tab_num):
|
||||
self._load_providers_tool_button.set_visible(not tab_num)
|
||||
self._receive_tool_button.set_visible(not tab_num)
|
||||
self._convert_tool_button.set_visible(tab_num)
|
||||
self._send_tool_button.set_sensitive(not tab_num)
|
||||
|
||||
if self._enigma2_path_button.get_filename() is None:
|
||||
self._enigma2_path_button.set_current_folder(self._enigma2_picons_path)
|
||||
|
||||
@run_idle
|
||||
def on_convert(self, item):
|
||||
if show_dialog(DialogType.QUESTION, self._dialog) == Gtk.ResponseType.CANCEL:
|
||||
return
|
||||
|
||||
picons_path = self._enigma2_path_button.get_filename()
|
||||
save_path = self._save_to_button.get_filename()
|
||||
if not picons_path or not save_path:
|
||||
show_dialog(DialogType.ERROR, transient=self._dialog, text="Select paths!")
|
||||
return
|
||||
|
||||
self._expander.set_expanded(True)
|
||||
convert_to(src_path=picons_path,
|
||||
dest_path=save_path,
|
||||
profile=Profile.ENIGMA_2,
|
||||
callback=self.append_output,
|
||||
done_callback=lambda: self.show_info_message(get_message("Done!"), Gtk.MessageType.INFO))
|
||||
|
||||
@run_idle
|
||||
def update_receive_button_state(self):
|
||||
self._receive_tool_button.set_sensitive(len(self.get_selected_providers()) > 0)
|
||||
|
||||
@@ -66,6 +66,9 @@
|
||||
<row>
|
||||
<col id="0" translatable="yes">9/10</col>
|
||||
</row>
|
||||
<row>
|
||||
<col id="0" translatable="yes">Auto</col>
|
||||
</row>
|
||||
</data>
|
||||
</object>
|
||||
<object class="GtkListStore" id="mod_store">
|
||||
@@ -587,7 +590,7 @@
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="freq_column">
|
||||
<property name="resizable">True</property>
|
||||
<property name="title" translatable="yes">Freq.</property>
|
||||
<property name="title" translatable="yes">Freq</property>
|
||||
<property name="expand">True</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="frequency_cellrenderertext"/>
|
||||
@@ -613,7 +616,7 @@
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="pol_column">
|
||||
<property name="resizable">True</property>
|
||||
<property name="title" translatable="yes">Pol.</property>
|
||||
<property name="title" translatable="yes">Pol</property>
|
||||
<property name="expand">True</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="sat_pol_cellrenderertext"/>
|
||||
@@ -626,7 +629,7 @@
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="fec_column">
|
||||
<property name="resizable">True</property>
|
||||
<property name="title" translatable="yes">Fec.</property>
|
||||
<property name="title" translatable="yes">FEC</property>
|
||||
<property name="expand">True</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="set_fec_cellrenderertext"/>
|
||||
@@ -652,7 +655,7 @@
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="mod_column">
|
||||
<property name="resizable">True</property>
|
||||
<property name="title" translatable="yes">Mod.</property>
|
||||
<property name="title" translatable="yes">Mod</property>
|
||||
<property name="expand">True</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="mod_cellrenderertext"/>
|
||||
@@ -1073,7 +1076,7 @@
|
||||
<object class="GtkLabel" id="label1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Freq.</property>
|
||||
<property name="label" translatable="yes">Freq</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
@@ -1095,7 +1098,7 @@
|
||||
<object class="GtkLabel" id="label3">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Pol.</property>
|
||||
<property name="label" translatable="yes">Pol</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">2</property>
|
||||
@@ -1106,7 +1109,7 @@
|
||||
<object class="GtkLabel" id="label4">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Fec.</property>
|
||||
<property name="label" translatable="yes">FEC</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">3</property>
|
||||
@@ -1117,7 +1120,7 @@
|
||||
<object class="GtkLabel" id="label5">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Sys.</property>
|
||||
<property name="label" translatable="yes">System</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">4</property>
|
||||
@@ -1128,7 +1131,7 @@
|
||||
<object class="GtkLabel" id="label6">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Mod.</property>
|
||||
<property name="label" translatable="yes">Mod</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">5</property>
|
||||
@@ -1361,7 +1364,7 @@
|
||||
<object class="GtkLabel" id="expander_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Extra</property>
|
||||
<property name="label" translatable="yes">Extra:</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
||||
@@ -3,8 +3,8 @@ from math import fabs
|
||||
|
||||
from app.commons import run_idle
|
||||
from app.eparser import get_satellites, write_satellites, Satellite, Transponder
|
||||
from . import Gtk, Gdk, UI_RESOURCES_PATH
|
||||
from .dialogs import show_dialog, DialogType
|
||||
from . import Gtk, Gdk, UI_RESOURCES_PATH, TEXT_DOMAIN
|
||||
from .dialogs import show_dialog, DialogType, WaitDialog
|
||||
from .main_helper import move_items, scroll_to
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ def show_satellites_dialog(transient, options):
|
||||
|
||||
|
||||
class SatellitesDialog:
|
||||
__slots__ = ["_dialog", "_data_path", "_stores", "_options", "_sat_view"]
|
||||
__slots__ = ["_dialog", "_data_path", "_stores", "_options", "_sat_view", "_wait_dialog"]
|
||||
|
||||
_aggr = [None for x in range(9)] # aggregate
|
||||
|
||||
@@ -38,6 +38,7 @@ class SatellitesDialog:
|
||||
"on_quit": self.on_quit}
|
||||
|
||||
builder = Gtk.Builder()
|
||||
builder.set_translation_domain(TEXT_DOMAIN)
|
||||
builder.add_objects_from_file(UI_RESOURCES_PATH + "satellites_dialog.glade",
|
||||
("satellites_editor_dialog", "satellites_tree_store",
|
||||
"popup_menu", "add_popup_menu", "add_menu_icon"))
|
||||
@@ -50,6 +51,7 @@ class SatellitesDialog:
|
||||
self._dialog.set_transient_for(transient)
|
||||
self._dialog.get_content_area().set_border_width(0) # The width of the border around the app dialog area!
|
||||
self._sat_view = builder.get_object("satellites_editor_tree_view")
|
||||
self._wait_dialog = WaitDialog(self._dialog)
|
||||
# Setting the last size of the dialog window if it was saved
|
||||
window_size = self._options.get("sat_editor_window_size", None)
|
||||
if window_size:
|
||||
@@ -132,6 +134,7 @@ class SatellitesDialog:
|
||||
def on_satellites_list_load(self, model):
|
||||
""" Load satellites data into model """
|
||||
try:
|
||||
self._wait_dialog.show()
|
||||
satellites = get_satellites(self._data_path)
|
||||
except FileNotFoundError as e:
|
||||
show_dialog(DialogType.ERROR, self._dialog, getattr(e, "message", str(e)) +
|
||||
@@ -139,6 +142,8 @@ class SatellitesDialog:
|
||||
else:
|
||||
model.clear()
|
||||
self.append_data(model, satellites)
|
||||
finally:
|
||||
self._wait_dialog.hide()
|
||||
|
||||
@run_idle
|
||||
def append_data(self, model, satellites):
|
||||
@@ -304,6 +309,7 @@ class TransponderDialog:
|
||||
handlers = {"on_entry_changed": self.on_entry_changed}
|
||||
|
||||
builder = Gtk.Builder()
|
||||
builder.set_translation_domain(TEXT_DOMAIN)
|
||||
builder.add_objects_from_file(UI_RESOURCES_PATH + "satellites_dialog.glade",
|
||||
("transponder_dialog",
|
||||
"pol_store", "fec_store",
|
||||
@@ -387,6 +393,7 @@ class SatelliteDialog:
|
||||
|
||||
def __init__(self, transient, satellite: Satellite = None):
|
||||
builder = Gtk.Builder()
|
||||
builder.set_translation_domain(TEXT_DOMAIN)
|
||||
builder.add_objects_from_file(UI_RESOURCES_PATH + "satellites_dialog.glade",
|
||||
("satellite_dialog", "side_store", "pos_adjustment"))
|
||||
|
||||
|
||||
53
app/ui/search.py
Normal file
53
app/ui/search.py
Normal file
@@ -0,0 +1,53 @@
|
||||
""" 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):
|
||||
self._paths = []
|
||||
self._current_index = -1
|
||||
self._max_indexes = 0
|
||||
self._srv_view = srv_view
|
||||
self._fav_view = fav_view
|
||||
self._bqs_view = bqs_view
|
||||
self._services = services
|
||||
self._bouquets = bouquets
|
||||
|
||||
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())
|
||||
selection = view.get_selection()
|
||||
selection.unselect_all()
|
||||
if not text:
|
||||
continue
|
||||
|
||||
text = text.upper()
|
||||
for r in model:
|
||||
if text in str(r[:]).upper():
|
||||
path = r.path
|
||||
selection.select_path(r.path)
|
||||
self._paths.append((view, path))
|
||||
|
||||
self._max_indexes = len(self._paths) - 1
|
||||
if self._max_indexes > 0:
|
||||
self.on_search_down()
|
||||
|
||||
def scroll_to(self, index):
|
||||
view, path = self._paths[index]
|
||||
view.scroll_to_cell(path, None)
|
||||
|
||||
def on_search_down(self):
|
||||
if self._current_index < self._max_indexes:
|
||||
self._current_index += 1
|
||||
self.scroll_to(self._current_index)
|
||||
|
||||
def on_search_up(self):
|
||||
if self._current_index > -1:
|
||||
self._current_index -= 1
|
||||
self.scroll_to(self._current_index)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pass
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,37 +1,38 @@
|
||||
from enum import Enum
|
||||
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
|
||||
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 . import Gtk, UI_RESOURCES_PATH
|
||||
from .main_helper import is_only_one_item_selected
|
||||
|
||||
|
||||
class Pids(Enum):
|
||||
VIDEO = "c:00"
|
||||
AUDIO = "c:01"
|
||||
TELETEXT = "c:02"
|
||||
PCR = "c:03"
|
||||
AC3 = "c:04"
|
||||
VIDEO_TYPE = "c:05"
|
||||
AUDIO_CHANNEL = "c:06"
|
||||
BIT_STREAM_DELAY = "c:07" # in ms
|
||||
PCM_DELAY = "c:08" # in ms
|
||||
SUBTITLE = "c:09"
|
||||
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def get_sat_positions(path):
|
||||
return ["{:.1f}".format(float(x.position) / 10) for x in get_satellites(path)]
|
||||
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
|
||||
|
||||
|
||||
class ServiceDetailsDialog:
|
||||
def __init__(self, transient, options, view):
|
||||
handlers = {"on_system_changed": self.on_system_changed}
|
||||
_DATA_ID = "{:04x}:{:08x}:{:04x}:{:04x}:{}:{}"
|
||||
|
||||
_FAV_ID = "{:X}:{:X}:{:X}:{:X}"
|
||||
|
||||
_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")
|
||||
|
||||
def __init__(self, transient, options, view, services, bouquets):
|
||||
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}
|
||||
|
||||
builder = Gtk.Builder()
|
||||
builder.set_translation_domain(TEXT_DOMAIN)
|
||||
builder.add_from_file(UI_RESOURCES_PATH + "service_details_dialog.glade")
|
||||
builder.connect_signals(handlers)
|
||||
|
||||
@@ -40,33 +41,54 @@ class ServiceDetailsDialog:
|
||||
self._profile = Profile(options["profile"])
|
||||
self._satellites_xml_path = options.get(self._profile.value)["data_dir_path"] + "satellites.xml"
|
||||
self._services_view = view
|
||||
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")
|
||||
# style
|
||||
self._style_provider = Gtk.CssProvider()
|
||||
self._style_provider.load_from_path(UI_RESOURCES_PATH + "style.css")
|
||||
# initialize 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")
|
||||
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")
|
||||
self._pcr_pid_entry = self._digit_elements.get("pcr_pid_entry")
|
||||
self._audio_pid_entry = self._digit_elements.get("audio_pid_entry")
|
||||
self._ac3_pid_entry = self._digit_elements.get("ac3_pid_entry")
|
||||
self._ac3plus_pid_entry = self._digit_elements.get("ac3plus_pid_entry")
|
||||
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._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")
|
||||
# Service elements
|
||||
self._name_entry = builder.get_object("name_entry")
|
||||
self._package_entry = builder.get_object("package_entry")
|
||||
self._id_entry = builder.get_object("id_entry")
|
||||
self._srv_type_entry = builder.get_object("srv_type_entry")
|
||||
self._service_type_combo_box = builder.get_object("service_type_combo_box")
|
||||
self._cas_entry = builder.get_object("cas_entry")
|
||||
self._bitstream_entry = builder.get_object("bitstream_entry")
|
||||
self._pcm_entry = builder.get_object("pcm_entry")
|
||||
self._reference_entry = builder.get_object("reference_entry")
|
||||
self._video_pid_entry = builder.get_object("video_pid_entry")
|
||||
self._pcr_pid_entry = builder.get_object("pcr_pid_entry")
|
||||
self._audio_pid_entry = builder.get_object("audio_pid_entry")
|
||||
self._ac3_pid_entry = builder.get_object("ac3_pid_entry")
|
||||
self._ac3plus_pid_entry = builder.get_object("ac3plus_pid_entry")
|
||||
self._acc_pid_entry = builder.get_object("acc_pid_entry")
|
||||
self._he_acc_pid_entry = builder.get_object("he_acc_pid_entry")
|
||||
self._teletext_pid_entry = builder.get_object("teletext_pid_entry")
|
||||
self._keep_check_button = builder.get_object("keep_check_button")
|
||||
self._hide_check_button = builder.get_object("hide_check_button")
|
||||
self._use_pids_check_button = builder.get_object("use_pids_check_button")
|
||||
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._transponder_id_entry = builder.get_object("transponder_id_entry")
|
||||
self._network_id_entry = builder.get_object("network_id_entry")
|
||||
self._freq_entry = builder.get_object("freq_entry")
|
||||
self._rate_entry = builder.get_object("rate_entry")
|
||||
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")
|
||||
@@ -75,45 +97,85 @@ class ServiceDetailsDialog:
|
||||
self._rolloff_combo_box = builder.get_object("rolloff_combo_box")
|
||||
self._pilot_combo_box = builder.get_object("pilot_combo_box")
|
||||
self._pls_mode_combo_box = builder.get_object("pls_mode_combo_box")
|
||||
self._pls_code_entry = builder.get_object("pls_code_entry")
|
||||
self._stream_id_entry = builder.get_object("stream_id_entry")
|
||||
self._flags_entry = builder.get_object("flags_entry")
|
||||
self._namespace_entry = builder.get_object("namespace_entry")
|
||||
self._tr_edit_switch = builder.get_object("tr_edit_switch")
|
||||
|
||||
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._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()
|
||||
|
||||
def show(self):
|
||||
response = self._dialog.run()
|
||||
if response == Gtk.ResponseType.OK:
|
||||
pass
|
||||
self._dialog.destroy()
|
||||
|
||||
return response
|
||||
|
||||
@run_idle
|
||||
def update_data_elements(self):
|
||||
model, paths = self._services_view.get_selection().get_selected_rows()
|
||||
if is_only_one_item_selected(paths, self._dialog):
|
||||
srv = Service(*model[paths][:])
|
||||
# Service
|
||||
self._name_entry.set_text(srv.service)
|
||||
self._package_entry.set_text(srv.package)
|
||||
self.select_active_text(self._service_type_combo_box, srv.service_type)
|
||||
self._id_entry.set_text(str(int(srv.ssid, 16)))
|
||||
# Transponder
|
||||
self._freq_entry.set_text(srv.freq)
|
||||
self._rate_entry.set_text(srv.rate)
|
||||
self.select_active_text(self._pol_combo_box, srv.pol)
|
||||
self.select_active_text(self._fec_combo_box, srv.fec)
|
||||
self.select_active_text(self._sys_combo_box, srv.system)
|
||||
self.set_sat_positions(srv.pos)
|
||||
itr = model.get_iter(paths)
|
||||
# Unpacking to search for an iterator for the base model
|
||||
filter_model = model.get_model()
|
||||
itr = filter_model.convert_iter_to_child_iter(model.convert_iter_to_child_iter(itr))
|
||||
self._current_model = get_base_model(model)
|
||||
srv = Service(*self._current_model[itr][:])
|
||||
self._old_service = srv
|
||||
self._current_itr = itr
|
||||
# Service
|
||||
self._name_entry.set_text(srv.service)
|
||||
self._package_entry.set_text(srv.package)
|
||||
self.select_active_text(self._service_type_combo_box, srv.service_type)
|
||||
self._sid_entry.set_text(str(int(srv.ssid, 16)))
|
||||
# Transponder
|
||||
self._freq_entry.set_text(srv.freq)
|
||||
self._rate_entry.set_text(srv.rate)
|
||||
self.select_active_text(self._pol_combo_box, srv.pol)
|
||||
self.select_active_text(self._fec_combo_box, srv.fec)
|
||||
self.select_active_text(self._sys_combo_box, srv.system)
|
||||
self.set_sat_positions(srv.pos)
|
||||
|
||||
if self._profile is Profile.ENIGMA_2:
|
||||
self.init_enigma2_service_data(srv)
|
||||
self.init_enigma2_transponder_data(srv)
|
||||
if self._profile is Profile.ENIGMA_2:
|
||||
self.init_enigma2_service_data(srv)
|
||||
self.init_enigma2_transponder_data(srv)
|
||||
elif self._profile is Profile.NEUTRINO_MP:
|
||||
self.init_neutrino_data(srv)
|
||||
self.init_enigma_ui_elements()
|
||||
|
||||
# ***************** Init Enigma2 data *********************#
|
||||
|
||||
@run_idle
|
||||
def init_enigma2_service_data(self, srv):
|
||||
""" Service data initialisation """
|
||||
flags = srv.flags_cas.split(",")
|
||||
flags = srv.flags_cas
|
||||
if flags:
|
||||
flags = flags.split(",")
|
||||
self.init_enigma2_flags(flags)
|
||||
self.init_enigma2_pids(flags)
|
||||
self.init_enigma2_cas(flags)
|
||||
|
||||
self._reference_entry.set_text(srv.picon_id.replace("_", ":").rstrip(".png"))
|
||||
|
||||
def init_enigma2_flags(self, flags):
|
||||
f_flags = list(filter(lambda x: x.startswith("f:"), flags))
|
||||
if f_flags:
|
||||
value = int(f_flags[0][2:])
|
||||
self._keep_check_button.set_active(Flag.is_keep(value))
|
||||
self._hide_check_button.set_active(Flag.is_hide(value))
|
||||
self._use_pids_check_button.set_active(Flag.is_pids(value))
|
||||
self._new_check_button.set_active(Flag.is_new(value))
|
||||
|
||||
def init_enigma2_cas(self, flags):
|
||||
cas = list(filter(lambda x: x.startswith("C:"), flags))
|
||||
if cas:
|
||||
self._cas_entry.set_text(",".join(cas))
|
||||
|
||||
def init_enigma2_pids(self, flags):
|
||||
pids = list(filter(lambda x: x.startswith("c:"), flags))
|
||||
if pids:
|
||||
for pid in pids:
|
||||
@@ -138,8 +200,6 @@ class ServiceDetailsDialog:
|
||||
elif pid.startswith(Pids.SUBTITLE.value):
|
||||
pass
|
||||
|
||||
self._reference_entry.set_text(srv.picon_id.replace("_", ":").rstrip(".png"))
|
||||
|
||||
@run_idle
|
||||
def init_enigma2_transponder_data(self, srv):
|
||||
""" Transponder data initialisation """
|
||||
@@ -150,12 +210,231 @@ class ServiceDetailsDialog:
|
||||
self.select_active_text(self._mod_combo_box, MODULATION.get(tr_data[8]))
|
||||
self.select_active_text(self._rolloff_combo_box, ROLL_OFF.get(tr_data[9]))
|
||||
self.select_active_text(self._pilot_combo_box, Pilot(tr_data[10]).name)
|
||||
self._tr_flag_entry.set_text(tr_data[7])
|
||||
if len(tr_data) > 12:
|
||||
self._stream_id_entry.set_text(tr_data[11])
|
||||
self._pls_code_entry.set_text(tr_data[12])
|
||||
self.select_active_text(self._pls_mode_combo_box, PLS_MODE.get(tr_data[13]))
|
||||
|
||||
self._srv_type_entry.set_text(data[4])
|
||||
self._namespace_entry.set_text(str(int(data[1], 16)))
|
||||
self._transponder_id_entry.set_text(str(int(data[2], 16)))
|
||||
self._network_id_entry.set_text(str(int(data[3], 16)))
|
||||
self.select_active_text(self._invertion_combo_box, Inversion(tr_data[5]).name)
|
||||
self._flags_entry.set_text(tr_data[6])
|
||||
|
||||
# ***************** Init Neutrino data *********************#
|
||||
|
||||
def init_neutrino_data(self, srv):
|
||||
srv_data = srv.data_id.split(":")
|
||||
tr_data = srv.transponder.split(":")
|
||||
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)))
|
||||
|
||||
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)
|
||||
|
||||
# ***************** 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)
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def get_sat_positions(self, path):
|
||||
try:
|
||||
return ["{:.1f}".format(float(x.position) / 10) for x in get_satellites(path)]
|
||||
except FileNotFoundError:
|
||||
return {r[-4] for r in self._current_model}
|
||||
|
||||
def on_system_changed(self, box):
|
||||
if not self._tr_edit_switch.get_active():
|
||||
return
|
||||
active = box.get_active()
|
||||
self.update_dvb_s2_elements(active)
|
||||
|
||||
def update_dvb_s2_elements(self, active):
|
||||
for elem in self._DVB_S2_ELEMENTS:
|
||||
elem.set_sensitive(active)
|
||||
self._pls_code_entry.set_name("GtkEntry")
|
||||
self._stream_id_entry.set_name("GtkEntry")
|
||||
|
||||
# ***************** Save data *********************#
|
||||
|
||||
def on_save(self, item):
|
||||
if show_dialog(DialogType.QUESTION, self._dialog) == Gtk.ResponseType.CANCEL:
|
||||
return
|
||||
|
||||
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)
|
||||
|
||||
old_fav_id = self._old_service.fav_id
|
||||
if old_fav_id != fav_id:
|
||||
self._services.pop(old_fav_id, None)
|
||||
for bq in self._bouquets.values():
|
||||
indexes = []
|
||||
for i, f_id in enumerate(bq):
|
||||
if old_fav_id == f_id:
|
||||
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
|
||||
|
||||
show_dialog(DialogType.ERROR, transient=self._dialog, text="Not implemented yet!")
|
||||
|
||||
def get_flags(self):
|
||||
if self._profile is Profile.ENIGMA_2:
|
||||
return self.get_enigma2_flags()
|
||||
elif self._profile is Profile.NEUTRINO_MP:
|
||||
return self._old_service.flags_cas
|
||||
|
||||
def get_enigma2_flags(self):
|
||||
flags = ["p:{}".format(self._package_entry.get_text())]
|
||||
# cas
|
||||
cas = self._cas_entry.get_text()
|
||||
if cas:
|
||||
flags.append(cas)
|
||||
# pids
|
||||
video_pid = self._video_pid_entry.get_text()
|
||||
if video_pid:
|
||||
flags.append("{}{:04x}".format(Pids.VIDEO.value, int(video_pid)))
|
||||
audio_pid = self._audio_pid_entry.get_text()
|
||||
if audio_pid:
|
||||
flags.append("{}{:04x}".format(Pids.AUDIO.value, int(audio_pid)))
|
||||
teletext_pid = self._teletext_pid_entry.get_text()
|
||||
if teletext_pid:
|
||||
flags.append("{}{:04x}".format(Pids.TELETEXT.value, int(teletext_pid)))
|
||||
pcr_pid = self._pcr_pid_entry.get_text()
|
||||
if pcr_pid:
|
||||
flags.append("{}{:04x}".format(Pids.PCR.value, int(pcr_pid)))
|
||||
ac3_pid = self._ac3_pid_entry.get_text()
|
||||
if ac3_pid:
|
||||
flags.append("{}{:04x}".format(Pids.AC3.value, int(ac3_pid)))
|
||||
bitstream_pid = self._bitstream_entry.get_text()
|
||||
if bitstream_pid:
|
||||
flags.append("{}{:04x}".format(Pids.BIT_STREAM_DELAY.value, int(bitstream_pid)))
|
||||
pcm_pid = self._pcm_entry.get_text()
|
||||
if pcm_pid:
|
||||
flags.append("{}{:04x}".format(Pids.PCM_DELAY.value, int(pcm_pid)))
|
||||
# flags
|
||||
f_flags = Flag.KEEP.value if self._keep_check_button.get_active() else 0
|
||||
f_flags = f_flags + Flag.HIDE.value if self._hide_check_button.get_active() else f_flags
|
||||
f_flags = f_flags + Flag.PIDS.value if self._use_pids_check_button.get_active() else f_flags
|
||||
f_flags = f_flags + Flag.NEW.value if self._new_check_button.get_active() else f_flags
|
||||
if f_flags:
|
||||
flags.append("f:{:02d}".format(f_flags))
|
||||
|
||||
return ",".join(flags)
|
||||
|
||||
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())
|
||||
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)
|
||||
return fav_id, data_id
|
||||
elif self._profile is Profile.NEUTRINO_MP:
|
||||
return self._old_service.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_data(self):
|
||||
sys = self._sys_combo_box.get_active_id()
|
||||
freq = self._freq_entry.get_text()
|
||||
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(".", "")
|
||||
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)
|
||||
if sys == "DVB-S":
|
||||
return dvb_s_tr
|
||||
if sys == "DVB-S2":
|
||||
flag = self._tr_flag_entry.get_text()
|
||||
mod = self.get_value_from_combobox_id(self._mod_combo_box, MODULATION)
|
||||
roll_off = self.get_value_from_combobox_id(self._rolloff_combo_box, ROLL_OFF)
|
||||
pilot = get_value_by_name(Pilot, self._pilot_combo_box.get_active_id())
|
||||
pls_mode = self.get_value_from_combobox_id(self._pls_mode_combo_box, PLS_MODE)
|
||||
pls_code = self._pls_code_entry.get_text()
|
||||
st_id = self._stream_id_entry.get_text()
|
||||
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
|
||||
|
||||
# ***************** Others *********************#
|
||||
|
||||
def select_active_text(self, box: Gtk.ComboBox, text):
|
||||
model = box.get_model()
|
||||
@@ -164,27 +443,55 @@ class ServiceDetailsDialog:
|
||||
box.set_active(index)
|
||||
break
|
||||
|
||||
@run_idle
|
||||
def set_sat_positions(self, sat_pos):
|
||||
model = self._sat_pos_combo_box.get_model()
|
||||
positions = 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)
|
||||
def on_digit_entry_changed(self, entry):
|
||||
entry.set_name("digit-entry" if self._pattern.search(entry.get_text()) else "GtkEntry")
|
||||
|
||||
def on_system_changed(self, box):
|
||||
for elem in self._DVB_S2_ELEMENTS:
|
||||
elem.set_sensitive(box.get_active())
|
||||
def get_value_from_combobox_id(self, box: Gtk.ComboBox, dc: dict):
|
||||
cb_id = box.get_active_id()
|
||||
return get_key_by_value(dc, cb_id)
|
||||
|
||||
@run_idle
|
||||
def on_tr_edit_toggled(self, switch: Gtk.Switch, active):
|
||||
|
||||
if active:
|
||||
self._transponder_services_iters = []
|
||||
response = TransponderServicesDialog(self._dialog,
|
||||
self._current_model,
|
||||
self._old_service.transponder,
|
||||
self._transponder_services_iters).show()
|
||||
if response == Gtk.ResponseType.CANCEL or response == -4:
|
||||
switch.set_active(False)
|
||||
self._transponder_services_iters = None
|
||||
return
|
||||
|
||||
self.update_dvb_s2_elements(active and self._sys_combo_box.get_active_id() == "DVB-S2")
|
||||
|
||||
for elem in self._TRANSPONDER_ELEMENTS:
|
||||
elem.set_sensitive(active)
|
||||
|
||||
|
||||
class TransponderServicesDialog:
|
||||
def __init__(self, transient, model, transponder, tr_iters):
|
||||
builder = Gtk.Builder()
|
||||
builder.set_translation_domain(TEXT_DOMAIN)
|
||||
builder.add_objects_from_file(UI_RESOURCES_PATH + "service_details_dialog.glade",
|
||||
("tr_services_dialog", "transponder_services_liststore"))
|
||||
self._dialog = builder.get_object("tr_services_dialog")
|
||||
self._dialog.set_transient_for(transient)
|
||||
self._srv_model = builder.get_object("transponder_services_liststore")
|
||||
self.append_services(model, transponder, tr_iters)
|
||||
|
||||
def append_services(self, model, transponder, tr_iters):
|
||||
for row in model:
|
||||
if row[-1] == transponder:
|
||||
self._srv_model.append((row[3], row[6], row[7], row[10], row[11], row[16]))
|
||||
tr_iters.append(model.get_iter(row.path))
|
||||
|
||||
def show(self):
|
||||
response = self._dialog.run()
|
||||
if response == Gtk.ResponseType.OK:
|
||||
pass
|
||||
self._dialog.destroy()
|
||||
|
||||
return response
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
dialog = ServiceDetailsDialog()
|
||||
dialog.show()
|
||||
pass
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from app.properties import write_config, Profile, get_default_settings
|
||||
from . import Gtk, UI_RESOURCES_PATH
|
||||
from . import Gtk, UI_RESOURCES_PATH, TEXT_DOMAIN
|
||||
from .main_helper import update_entry_data
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ class SettingsDialog:
|
||||
"apply_settings": self.apply_settings}
|
||||
|
||||
builder = Gtk.Builder()
|
||||
builder.set_translation_domain(TEXT_DOMAIN)
|
||||
builder.add_objects_from_file(UI_RESOURCES_PATH + "dialogs.glade",
|
||||
("settings_dialog", "telnet_timeout_adjustment"))
|
||||
builder.connect_signals(handlers)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/bin/env bash
|
||||
VER="0.2.4_Pre-alpha"
|
||||
#!/bin/bash
|
||||
VER="0.3.0_Pre-alpha"
|
||||
B_PATH="dist/DemonEditor"
|
||||
DEB_PATH="$B_PATH/usr/share/demoneditor"
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Package: DemonEditor
|
||||
Version: 0.2.4-Pre-alpha
|
||||
Version: 0.3.0-Pre-alpha
|
||||
Section: utils
|
||||
Priority: optional
|
||||
Architecture: all
|
||||
|
||||
@@ -1,25 +1,33 @@
|
||||
# DemonEditor
|
||||
|
||||
Enigma2 channel and satellites list editor for GNU/Linux.
|
||||
## Enigma2 channel and satellites list editor for GNU/Linux.
|
||||
Experimental support of Neutrino-MP or others on the same basis (BPanther, etc).
|
||||
Focused on the convenience of working in lists from the keyboard. The mouse is also fully supported (Drag and Drop etc)
|
||||
Focused on the convenience of working in lists from the keyboard. The mouse is also fully supported (Drag and Drop etc)
|
||||
|
||||
Keyboard shortcuts:
|
||||
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.
|
||||
### Keyboard shortcuts:
|
||||
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 + H - hide/skip.
|
||||
Clipboard is "rubber". There is an accumulation before the insertion!
|
||||
Ctrl + E - edit.
|
||||
Ctrl + R, F2 - rename.
|
||||
Ctrl + S, T in Satellites edit tool for create satellite or transponder.
|
||||
Ctrl + L - parental lock.
|
||||
Ctrl + H - hide/skip.
|
||||
Left/Right - remove selection.
|
||||
|
||||
Ability to import IPTV into bouquet from m3u files!
|
||||
### Extra:
|
||||
Multiple selections in lists only with Space key (as in file managers).
|
||||
Ability to import IPTV into bouquet (Neutrino WEBTV) from m3u files.
|
||||
Tool for downloading picons from lyngsat.com.
|
||||
### Minimum requirements:
|
||||
Python >= 3.5.2 and GTK+ 3 with PyGObject bindings.
|
||||
#### Note.
|
||||
To create a simple debian package, you can use the build-deb.sh
|
||||
|
||||
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)!
|
||||
|
||||
Minimum requirements: Python >= 3.5.2 and GTK+ 3 with PyGObject bindings.
|
||||
#### Terrestrial and cable channels at the moment are not supported!
|
||||
|
||||
Terrestrial and cable channels at the moment are not supported!
|
||||
|
||||
|
||||
BIN
deb/usr/share/locale/ru/LC_MESSAGES/demon-editor.mo
Normal file
BIN
deb/usr/share/locale/ru/LC_MESSAGES/demon-editor.mo
Normal file
Binary file not shown.
3
po/build.sh
Normal file
3
po/build.sh
Normal file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
#xgettext --keyword=translatable --sort-output -L Glade -o po/demon-editor.po app/ui/main_window.glade
|
||||
#msgfmt demon-editor.po -o demon-editor.mo
|
||||
BIN
po/ru/demon-editor.mo
Normal file
BIN
po/ru/demon-editor.mo
Normal file
Binary file not shown.
496
po/ru/demon-editor.po
Normal file
496
po/ru/demon-editor.po
Normal file
@@ -0,0 +1,496 @@
|
||||
# Copyright (C) 2018 Dmitriy Yefremov
|
||||
# This file is distributed under the MIT license.
|
||||
# Dmitriy Yefremov , 2018.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Language: ru\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
|
||||
# Main
|
||||
msgid "Service"
|
||||
msgstr "Сервис"
|
||||
|
||||
msgid "Package"
|
||||
msgstr "Пакет"
|
||||
|
||||
msgid "Type"
|
||||
msgstr "Тип"
|
||||
|
||||
msgid "Picon"
|
||||
msgstr "Пикон"
|
||||
|
||||
msgid "Freq"
|
||||
msgstr "Частота"
|
||||
|
||||
msgid "Rate"
|
||||
msgstr "Сим. скорость"
|
||||
|
||||
msgid "Pol"
|
||||
msgstr "Пол."
|
||||
|
||||
msgid "System"
|
||||
msgstr "Система"
|
||||
|
||||
msgid "Pos"
|
||||
msgstr "Поз."
|
||||
|
||||
msgid "Num"
|
||||
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 "Отправить вайлы в ресивер"
|
||||
|
||||
#: 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 ""
|
||||
|
||||
msgid "Extra:"
|
||||
msgstr "Дополнительно:"
|
||||
|
||||
# Picons dialog
|
||||
msgid "Load providers"
|
||||
msgstr "Загрузить провайдеров"
|
||||
|
||||
msgid "Receive picons"
|
||||
msgstr "Загрузить пиконы"
|
||||
|
||||
msgid "Picons name format:"
|
||||
msgstr "Формат имени пиконов:"
|
||||
|
||||
msgid "Resize:"
|
||||
msgstr "Обрезать:"
|
||||
|
||||
msgid "Current picons path:"
|
||||
msgstr "Текущий путь к пиконам:"
|
||||
|
||||
msgid "Receiver picons path:"
|
||||
msgstr "Путь к пиконам ресивера:"
|
||||
|
||||
msgid "Picons download tool"
|
||||
msgstr "Загрузчик пиконов"
|
||||
|
||||
msgid "Transfer to receiver"
|
||||
msgstr "Загрузить в ресивер"
|
||||
|
||||
msgid "Downloader"
|
||||
msgstr "Загрузчик"
|
||||
|
||||
msgid "Converter"
|
||||
msgstr "Конвертер"
|
||||
|
||||
msgid "Convert"
|
||||
msgstr "Конвертировать"
|
||||
|
||||
msgid "Path to save:"
|
||||
msgstr "Путь для сохранения:"
|
||||
|
||||
msgid "Path to Enigma2 picons:"
|
||||
msgstr "Путь к пиконам формата Enigma2:"
|
||||
|
||||
# Satellites editor
|
||||
msgid "Satellites edit tool"
|
||||
msgstr "Редактор спутников"
|
||||
|
||||
msgid "Add"
|
||||
msgstr "Добавить"
|
||||
|
||||
msgid "Satellite"
|
||||
msgstr "Спутник"
|
||||
|
||||
msgid "Transponder"
|
||||
msgstr "Транспондер"
|
||||
|
||||
msgid "Satellite properties:"
|
||||
msgstr "Параметры спутника:"
|
||||
|
||||
msgid "Transponder properties:"
|
||||
msgstr "Параметры транспондера:"
|
||||
|
||||
msgid "Name"
|
||||
msgstr "Имя"
|
||||
|
||||
msgid "Position"
|
||||
msgstr "Позиция"
|
||||
|
||||
# Service details dialog
|
||||
msgid "Service data:"
|
||||
msgstr "Данные сервиса:"
|
||||
|
||||
msgid "Transponder data:"
|
||||
msgstr "Данные транспондера:"
|
||||
|
||||
msgid "Service data"
|
||||
msgstr "Данные сервиса"
|
||||
|
||||
msgid "Transponder details"
|
||||
msgstr "Данные транспондера"
|
||||
|
||||
msgid "Changes will be applied to all services of this transponder!\nContinue?"
|
||||
msgstr "Изменения будут применены ко всем сервисам данного транспондера!\nПродолжить?"
|
||||
|
||||
# Dialogs messages
|
||||
msgid "Error. No bouquet is selected!"
|
||||
msgstr "Ошибка. Не выбран букет!"
|
||||
|
||||
msgid "This item is not allowed to be removed!"
|
||||
msgstr "Этот элемент не разрешен к удалению!"
|
||||
|
||||
msgid "This item is not allowed to edit!"
|
||||
msgstr "Элемент не предназначен для редактирования!"
|
||||
|
||||
msgid "Please, download files from receiver or setup your path for read data!"
|
||||
msgstr "Пожалуйста, загрузите файлы из приемника или настройте путь для чтения данных!"
|
||||
|
||||
msgid "Reading data error!"
|
||||
msgstr "Ошибка чтения данных!"
|
||||
|
||||
msgid "No m3u file is selected!"
|
||||
msgstr "Не выбран m3u файл!"
|
||||
|
||||
msgid "Not implemented yet!"
|
||||
msgstr "Пока не реализовано!"
|
||||
|
||||
msgid "The text of marker is empty, please try again!"
|
||||
msgstr "Текст маркера пуст, попробуйте еще!"
|
||||
|
||||
msgid "Please, select only one item!"
|
||||
msgstr "Пожалуйста, выберите только один элемент!"
|
||||
|
||||
msgid "No png file is selected!"
|
||||
msgstr "Не выбран png файл!"
|
||||
|
||||
msgid "No reference is present!"
|
||||
msgstr "Ссылка не найдена!"
|
||||
|
||||
msgid "No selected item!"
|
||||
msgstr "Не выбран элемент!"
|
||||
|
||||
msgid "The task is already running!"
|
||||
msgstr "Задача уже запущена!"
|
||||
|
||||
msgid "Done!"
|
||||
msgstr "Готово!"
|
||||
|
||||
msgid "Please, wait..."
|
||||
msgstr "Пожалуйста, подождите..."
|
||||
|
||||
msgid "Resizing..."
|
||||
msgstr "Изменение размера..."
|
||||
|
||||
msgid "Select paths!"
|
||||
msgstr "Укажите пути!"
|
||||
|
||||
msgid "No satellite is selected!"
|
||||
msgstr "Не выбран спутник!"
|
||||
|
||||
msgid "Please, select only one satellite!"
|
||||
msgstr "Пожалуйста, выберите только один спутник!"
|
||||
|
||||
msgid "Please check your parameters and try again."
|
||||
msgstr "Пожалуйста, проверте параметры и попробуйте снова!"
|
||||
|
||||
msgid "No satellites.xml file is selected!"
|
||||
msgstr "Не выбран файл satellites.xml!"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user