Compare commits

...

29 Commits
0.3.1 ... 0.3.2

Author SHA1 Message Date
DYefremov
93fd3cd2c3 stream play fix for enigma2 2018-09-01 23:17:03 +03:00
DYefremov
03c291a61e added lamedb5 to ftp 2018-06-05 20:45:47 +03:00
DYefremov
97d9ce8b68 lamedb5 reading fix 2018-06-01 18:41:59 +03:00
DYefremov
1a55df6674 lamedb5 writing 2018-06-01 17:45:26 +03:00
DYefremov
6ac10c1380 opening lamedb5 2018-06-01 11:16:30 +03:00
DYefremov
13270b6152 v5 support skeleton 2018-05-28 18:45:31 +03:00
DYefremov
b2c0359017 applying filter after values change 2018-05-22 21:59:17 +03:00
DYefremov
8a6dd1da93 added full screen mode for the player 2018-05-19 16:24:20 +03:00
DYefremov
2e1410ca36 satellites list update in the separate thread 2018-05-12 14:36:38 +03:00
DYefremov
3d96181450 translation for some elements 2018-05-12 12:42:42 +03:00
DYefremov
fe749ca594 added checking that vlc is installed 2018-05-12 12:21:34 +03:00
DYefremov
1b6cd58112 added transponder validity checking 2018-05-12 11:47:19 +03:00
DYefremov
8d405d223a new src for the sat update dialog 2018-05-10 23:28:51 +03:00
DYefremov
81ad19043a new source for sat update dialog 2018-05-10 00:44:42 +03:00
DYefremov
34db58f8e0 selection fix in satellites update dialog 2018-05-07 23:55:22 +03:00
DYefremov
890163af4a added search feature for satellites update dialog 2018-05-07 18:19:00 +03:00
DYefremov
c4e8a6646d added simple filter for satellites update dialog 2018-05-07 15:19:05 +03:00
DYefremov
639c8511bf added ui elements for find and filter for update dialog 2018-05-07 00:44:46 +03:00
DYefremov
5e082fc5d7 new header variant for sat update dialog 2018-05-06 00:08:56 +03:00
DYefremov
7f393ff9ba getting of satellites in separate processes 2018-05-05 22:01:50 +03:00
DYefremov
b37aac0cd9 satellite data update in the main model 2018-05-02 21:23:09 +03:00
DYefremov
d857c4b786 append output for sat update dialog 2018-05-01 21:05:18 +03:00
DYefremov
6ffd1d7926 receive_satellites skeleton 2018-04-30 18:37:02 +03:00
DYefremov
415ad79c80 new satellites update dialog skeleton 2018-04-30 11:11:55 +03:00
DYefremov
da4fef7f6b test implementation of IPTV preview 2018-04-29 15:36:35 +03:00
DYefremov
76c034435d iptv preview mode skeleton 2018-04-29 01:44:28 +03:00
Dmitriy Yefremov
f9239f0642 new variant of satellites download skeleton 2018-04-25 17:26:29 +03:00
DYefremov
7f096df998 satellites dialog skeleton 2018-04-23 23:14:07 +03:00
Dmitriy Yefremov
3f0738d874 skeleton of satellites downloader 2018-04-23 14:42:41 +03:00
28 changed files with 11045 additions and 586 deletions

View File

@@ -3,24 +3,26 @@
## 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)
### Keyboard shortcuts:
#### Ctrl + X, C, V, Up, Down, PageUp, PageDown, Home, End, 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 - 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.
Space - select/deselect.
Left/Right - remove selection.
**Ctrl + X, C, V, Up, Down, PageUp, PageDown, Home, End, S, T, E, L, H, Space; Insert, Delete, F2, Enter, P.**
* **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** - 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.
* **P** - enable/disable preview mode for IPTV in the bouquet list.
* **Enter** - start play IPTV or other stream in the bouquet list.
* **Space** - select/deselect.
* **Left/Right** - remove selection.
* **Ctrl + Up, Down, PageUp, PageDown, Home, End** - move selected items in the list.
### 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.
* Multiple selections in lists only with Space key (as in file managers).
* Ability to import IPTV into bouquet (Neutrino WEBTV) from m3u files.
* Ability to download picons and update satellites (transponders) from web.
* Preview (playing) IPTV or other streams directly from the bouquet list(should be installed VLC).
### Minimum requirements:
Python >= 3.5.2 and GTK+ 3 with PyGObject bindings.
#### Note.
@@ -29,6 +31,6 @@ 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)!
#### Terrestrial and cable channels at the moment are not supported!
**Terrestrial and cable channels at the moment are not supported!**

View File

@@ -1,6 +1,6 @@
from app.commons import run_task
from app.properties import Profile
from .ecommons import Service, Satellite, Transponder, Bouquet, Bouquets
from .ecommons import Service, Satellite, Transponder, Bouquet, Bouquets, is_transponder_valid
from .enigma.blacklist import get_blacklist, write_blacklist
from .enigma.bouquets import get_bouquets as get_enigma_bouquets, write_bouquets as write_enigma_bouquets, to_bouquet_id
from .enigma.lamedb import get_services as get_enigma_services, write_services as write_enigma_services
@@ -10,17 +10,17 @@ from .neutrino.services import get_services as get_neutrino_services, write_serv
from .satxml import get_satellites, write_satellites
def get_services(data_path, profile):
def get_services(data_path, profile, format_version):
if profile is Profile.ENIGMA_2:
return get_enigma_services(data_path)
return get_enigma_services(data_path, format_version)
elif profile is Profile.NEUTRINO_MP:
return get_neutrino_services(data_path)
@run_task
def write_services(path, channels, profile):
def write_services(path, channels, profile, format_version):
if profile is Profile.ENIGMA_2:
write_enigma_services(path, channels)
write_enigma_services(path, channels, format_version)
elif profile is Profile.NEUTRINO_MP:
write_neutrino_services(path, channels)

View File

@@ -142,3 +142,26 @@ def get_value_by_name(en, name):
for n in en:
if n.name == name:
return n.value
def is_transponder_valid(tr: Transponder):
""" Checks transponder validity """
try:
int(tr.frequency)
int(tr.symbol_rate)
tr.pls_mode is None or int(tr.pls_mode)
tr.pls_code is None or int(tr.pls_code)
tr.is_id is None or int(tr.is_id)
except TypeError:
return False
if tr.polarization not in POLARIZATION.values():
return False
if tr.fec_inner not in FEC.values():
return False
if tr.system not in SYSTEM.values():
return False
if tr.modulation not in MODULATION.values():
return False
return True

View File

@@ -1,24 +1,32 @@
""" This module used for parsing lamedb file
""" This module used for parsing and write lamedb file
Currently implemented only for satellite channels!!!
Description of format taken from here: http://www.satsupreme.com/showthread.php/194074-Lamedb-format-explained
"""
from app.commons import log
from app.ui.uicommons import CODED_ICON, LOCKED_ICON, HIDE_ICON
from .blacklist import get_blacklist
from ..ecommons import Service, POLARIZATION, SYSTEM, FEC, SERVICE_TYPE, Flag
from ..ecommons import Service, POLARIZATION, FEC, SERVICE_TYPE, Flag
_HEADER = "eDVB services /4/"
_HEADER = "eDVB services /{}/"
_SEP = ":" # separator
_FILE_NAME = "lamedb"
_END_LINE = "# File was created in DemonEditor.\n# ....Enjoy watching!....\n"
def get_services(path):
return parse(path)
def get_services(path, format_version):
return parse(path, format_version)
def write_services(path, services):
lines = [_HEADER, "\ntransponders\n"]
def write_services(path, services, format_version=4):
if format_version == 4:
write_to_lamedb(path, services)
elif format_version == 5:
write_to_lamedb5(path, services)
def write_to_lamedb(path, services):
""" Writing lamedb file ver.4 """
lines = [_HEADER.format(4), "\ntransponders\n"]
tr_lines = []
services_lines = ["end\nservices\n"]
tr_set = set()
@@ -36,14 +44,42 @@ def write_services(path, services):
tr_lines.sort()
lines.extend(tr_lines)
lines.extend(services_lines)
lines.append("end\nFile was created in DemonEditor.\n....Enjoy watching!....\n")
lines.append("end\n" + _END_LINE)
with open(path + _FILE_NAME, "w") as file:
file.writelines(lines)
def parse(path):
def write_to_lamedb5(path, services):
""" Writing lamedb5 file """
lines = [_HEADER.format(5) + "\n"]
services_lines = []
tr_set = set()
for srv in services:
data_id = str(srv.data_id).split(_SEP)
tr_id = "{}:{}:{}".format(data_id[1], data_id[2], data_id[3])
tr_set.add("t:{},{}\n".format(tr_id, srv.transponder.replace(" ", ":", 1)))
services_lines.append("s:{},\"{}\",{}\n".format(srv.data_id, srv.service, srv.flags_cas))
lines.extend(sorted(tr_set))
lines.extend(services_lines)
lines.append(_END_LINE)
with open(path + "lamedb5", "w") as file:
file.writelines(lines)
def parse(path, version=4):
""" Parsing lamedb """
if version == 4:
return parse_v4(path)
elif version == 5:
return parse_v5(path)
raise SyntaxError("Unsupported version of the format.")
def parse_v4(path):
""" Parsing version 4 """
with open(path + _FILE_NAME, "r", encoding="utf-8", errors="replace") as file:
try:
data = str(file.read())
@@ -58,7 +94,28 @@ def parse(path):
transponders, sep, services = services.partition("services") # 2 step
services, sep, _ = services.partition("\nend") # 3 step
return parse_services(services.split("\n"), transponders.split("/"), path)
return parse_services(services.split("\n"), parse_transponders(transponders.split("/")), path)
def parse_v5(path):
""" Parsing version 5 """
with open(path + "lamedb5", "r", encoding="utf-8", errors="replace") as file:
lns = file.readlines()
if lns and not lns[0].endswith("/5/\n"):
raise SyntaxError("lamedb v.5 parsing error: unsupported format.")
trs, srvs = {}, [""]
for l in lns:
if l.startswith("s:"):
srv_data = l.strip("s:").split(",", 2)
srv_data[1], srv_data[2] = srv_data[1].strip("\""), srv_data[2].strip()
srvs.extend(srv_data)
elif l.startswith("t:"):
tr, srv = l.split(",")
trs[tr.strip("t:")] = srv.strip().replace(":", " ", 1)
return parse_services(srvs, trs, path)
def parse_transponders(arg):
@@ -75,9 +132,7 @@ def parse_transponders(arg):
def parse_services(services, transponders, path):
""" Parsing channels """
channels = []
transponders = parse_transponders(transponders)
blacklist = str(get_blacklist(path))
srv = split(services, 3)
if srv[0][0] == "": # remove first empty element
srv.remove(srv[0])

View File

@@ -8,7 +8,7 @@ from telnetlib import Telnet
from app.commons import log
from app.properties import Profile
__DATA_FILES_LIST = ("tv", "radio", "lamedb", "blacklist", "whitelist", # enigma 2
__DATA_FILES_LIST = ("tv", "radio", "lamedb", "lamedb5", "blacklist", "whitelist", # enigma 2
"services.xml", "myservices.xml", "bouquets.xml", "ubouquets.xml") # neutrino
_SATELLITES_XML_FILE = "satellites.xml"
@@ -67,7 +67,7 @@ def upload_data(*, properties, download_type=DownloadDataType.ALL, remove_unused
tn = telnet(host=host, user=properties.get("telnet_user", "root"), password=properties.get("telnet_password", ""),
timeout=properties.get("telnet_timeout", 5))
next(tn)
# terminate enigma or enigma
# terminate enigma or neutrino
tn.send("init 4")
with FTP(host=host) as ftp:

View File

@@ -48,7 +48,8 @@ def get_default_settings():
"satellites_xml_path": "/etc/tuxbox/",
"picons_path": "/usr/share/enigma2/picon",
"data_dir_path": DATA_PATH + "enigma2/",
"picons_dir_path": DATA_PATH + "enigma2/picons/"},
"picons_dir_path": DATA_PATH + "enigma2/picons/",
"v5_support": False},
Profile.NEUTRINO_MP.value: {
"host": "127.0.0.1", "port": "21",
"user": "root", "password": "root",

96
app/tools/media.py Normal file
View File

@@ -0,0 +1,96 @@
from app.commons import run_idle
from app.tools import vlc
from app.ui.uicommons import Gtk, Gdk
MRL = "url"
class Player:
_VLC_INSTANCE = None
def __init__(self, url):
handlers = {"on_play": self.on_play,
"on_stop": self.on_stop,
"on_drawing_area_realize": self.on_drawing_area_realize,
"on_press": self.on_press,
"on_key_release": self.on_key_release,
"on_state_changed": self.on_state_changed,
"on_close_window": self.on_close_window}
builder = Gtk.Builder()
builder.add_objects_from_file("player.glade", ("player_main_window",))
builder.connect_signals(handlers)
self._main_window = builder.get_object("player_main_window")
self._main_box = builder.get_object("main_box")
self._buttonbox = builder.get_object("buttonbox")
self._frame = builder.get_object("")
self._drawing_area = builder.get_object("drawing_area")
self._drawing_area.set_events(Gdk.ModifierType.BUTTON1_MASK)
self._player = Player.get_vlc_instance().media_player_new()
self._is_played = False
self._url = url
self._full_screen = False
@staticmethod
def get_vlc_instance():
if Player._VLC_INSTANCE:
return Player._VLC_INSTANCE
_VLC_INSTANCE = vlc.Instance("--no-xlib")
return _VLC_INSTANCE
def on_play(self, item):
if not self._is_played:
self._player.play()
self._is_played = True
def on_stop(self, item):
if self._is_played:
self._player.stop()
self._is_played = False
def on_press(self, area, event: Gdk.EventButton):
if event.button == Gdk.BUTTON_PRIMARY and event.type == Gdk.EventType.DOUBLE_BUTTON_PRESS:
self.change_state()
def on_state_changed(self, window, event):
if event.new_window_state & Gdk.WindowState.FULLSCREEN:
if self._main_box in window:
window.remove(self._main_box)
self._drawing_area.reparent(self._main_window)
else:
if self._drawing_area in self._main_window:
window.remove(self._drawing_area)
window.add(self._main_box)
self._main_box.pack_start(self._drawing_area, True, True, 0)
self._main_box.reorder_child(self._drawing_area, 0)
def change_state(self):
self._full_screen = not self._full_screen
self._main_window.fullscreen() if self._full_screen else self._main_window.unfullscreen()
def on_key_release(self, area, key):
if key.keyval in (Gdk.KEY_F, Gdk.KEY_f):
self.change_state()
def on_drawing_area_realize(self, widget):
win_id = widget.get_window().get_xid()
if self._player:
self._is_played = True
self._player.set_xwindow(win_id)
self._player.set_mrl(self._url)
self._player.play()
@run_idle
def on_close_window(self, *args):
if self._player:
self.on_stop(None)
self._player.release()
Gtk.main_quit()
def show(self):
self._main_window.show()
Gtk.main()
if __name__ == "__main__":
Player(MRL).show()

View File

@@ -1,11 +1,11 @@
import glob
import os
import re
import shutil
from collections import namedtuple
from html.parser import HTMLParser
import re
from app.commons import log, run_task
from app.properties import Profile

116
app/tools/player.glade Normal file
View File

@@ -0,0 +1,116 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.18.3 -->
<interface>
<requires lib="gtk+" version="3.12"/>
<object class="GtkApplicationWindow" id="player_main_window">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Player</property>
<property name="icon_name">vlc</property>
<signal name="delete-event" handler="on_close_window" swapped="no"/>
<signal name="window-state-event" handler="on_state_changed" swapped="no"/>
<child>
<object class="GtkBox" id="main_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkDrawingArea" id="drawing_area">
<property name="width_request">320</property>
<property name="height_request">240</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="has_focus">True</property>
<signal name="button-press-event" handler="on_press" swapped="no"/>
<signal name="key-release-event" handler="on_key_release" swapped="no"/>
<signal name="realize" handler="on_drawing_area_realize" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="padding">2</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkSeparator" id="separator">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">2</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkButtonBox" id="buttonbox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">3</property>
<property name="margin_right">5</property>
<property name="spacing">2</property>
<property name="homogeneous">True</property>
<property name="layout_style">start</property>
<child>
<object class="GtkButton" id="play_button">
<property name="label">gtk-media-play</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="on_play" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="stop_button">
<property name="label">gtk-media-stop</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="on_stop" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="close_button">
<property name="label">gtk-close</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="on_close_window" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">2</property>
<property name="secondary">True</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">5</property>
<property name="position">4</property>
</packing>
</child>
</object>
</child>
</object>
</interface>

186
app/tools/satellites.py Normal file
View File

@@ -0,0 +1,186 @@
""" Module for download satellites from internet ("flysat.com")
for replace or update current satellites.xml file.
"""
import re
import requests
from enum import Enum
from html.parser import HTMLParser
from app.eparser import Satellite, Transponder, is_transponder_valid
class SatelliteSource(Enum):
FLYSAT = ("https://www.flysat.com/satlist.php",)
LYNGSAT = ("https://www.lyngsat.com/asia.html", "https://www.lyngsat.com/europe.html",
"https://www.lyngsat.com/atlantic.html", "https://www.lyngsat.com/america.html")
@staticmethod
def get_sources(src):
return src.value
class SatellitesParser(HTMLParser):
""" Parser for satellite html page. """
_HEADERS = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:45.0) Gecko/20100101 Firefox/59.02"}
def __init__(self, source=SatelliteSource.FLYSAT, entities=False, separator=' '):
HTMLParser.__init__(self)
self._parse_html_entities = entities
self._separator = separator
self._is_td = False
self._is_th = False
self._is_provider = False
self._current_row = []
self._current_cell = []
self._rows = []
self._source = source
def handle_starttag(self, tag, attrs):
if tag == 'td':
self._is_td = True
if tag == 'tr':
self._is_th = True
if tag == "a":
self._current_row.append(attrs[0][1])
def handle_data(self, data):
""" Save content to a cell """
if self._is_td or self._is_th:
self._current_cell.append(data.strip())
def handle_endtag(self, tag):
if tag == 'td':
self._is_td = False
elif tag == 'tr':
self._is_th = False
if tag in ('td', 'th'):
final_cell = self._separator.join(self._current_cell).strip()
self._current_row.append(final_cell)
self._current_cell = []
elif tag == 'tr':
row = self._current_row
self._rows.append(row)
self._current_row = []
def error(self, message):
pass
def get_satellites_list(self, source):
""" Getting complete list of satellites. """
self.reset()
self._rows.clear()
self._source = source
for src in SatelliteSource.get_sources(self._source):
request = requests.get(url=src, headers=self._HEADERS)
reason = request.reason
if reason == "OK":
self.feed(request.text)
else:
print(reason)
if self._rows:
if self._source is SatelliteSource.FLYSAT:
def get_sat(r):
return r[1], self.parse_position(r[2]), r[3], r[0], False
return list(map(get_sat, filter(lambda x: all(x) and len(x) == 5, self._rows)))
elif self._source is SatelliteSource.LYNGSAT:
rows = filter(lambda x: len(x) in (5, 7), self._rows)
sats = []
current_pos = "0"
for row in rows:
r_len = len(row)
if r_len == 7:
current_pos = self.parse_position(row[2])
sats.append((row[4], current_pos, row[5], row[1], False))
elif r_len == 5:
sats.append((row[2], current_pos, row[3], row[1], False))
return sats
def get_satellite(self, sat):
pos = sat[1]
return Satellite(name=sat[0] + " ({})".format(pos),
flags="0",
position=self.get_position(pos.replace(".", "")),
transponders=self.get_transponders(sat[3]))
@staticmethod
def parse_position(pos_str):
return "".join(c for c in pos_str if c.isdigit() or c.isalpha() or c == ".")
@staticmethod
def get_position(pos):
return "{}{}".format("-" if pos[-1] == "W" else "", pos[:-1])
def get_transponders(self, sat_url):
self._rows.clear()
url = "https://www.flysat.com/" + sat_url if self._source is SatelliteSource.FLYSAT else sat_url
request = requests.get(url=url, headers=self._HEADERS)
reason = request.reason
trs = []
if reason == "OK":
self.feed(request.text)
if self._source is SatelliteSource.FLYSAT:
self.get_transponders_for_fly_sat(trs)
elif self._source is SatelliteSource.LYNGSAT:
self.get_transponders_for_lyng_sat(trs)
return trs
def get_transponders_for_fly_sat(self, trs):
""" Parsing transponders for FlySat """
if self._rows:
zeros = "000"
for r in self._rows:
if len(r) < 3:
continue
data = r[2].split(" ")
if len(data) != 2:
continue
sr, fec = data
data = r[1].split(" ")
if len(data) < 3:
continue
freq, pol, sys = data[0], data[1], data[2]
sys = sys.split("/")
if len(sys) != 2:
continue
sys, mod = sys
mod = "QPSK" if sys == "DVB-S" else mod
tr = Transponder(freq + zeros, sr + zeros, pol, fec, sys, mod, None, None, None)
if is_transponder_valid(tr):
trs.append(tr)
def get_transponders_for_lyng_sat(self, trs):
""" Parsing transponders for LyngSat """
frq_pol_pattern = re.compile("(\d{4,5}).*([RLHV])(.*\d$)")
sr_fec_pattern = re.compile("^(\d{4,5})-(\d/\d)(.+PSK)?(.*)?$")
sys_pattern = re.compile("(DVB-S[2]?)(.*)?")
zeros = "000"
for r in filter(lambda x: len(x) > 8, self._rows):
freq = re.match(frq_pol_pattern, r[2])
if not freq:
continue
frq, pol = freq.group(1), freq.group(2)
sr_fec = re.match(sr_fec_pattern, r[-3])
if not sr_fec:
continue
sr, fec, mod = sr_fec.group(1), sr_fec.group(2), sr_fec.group(3)
mod = mod.strip() if mod else "Auto"
sys = re.match(sys_pattern, r[-4])
if not sys:
continue
sys = sys.group(1)
tr = Transponder(frq + zeros, sr + zeros, pol, fec, sys, mod, None, None, None)
if is_transponder_valid(tr):
trs.append(tr)
if __name__ == "__main__":
pass

8749
app/tools/vlc.py Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -9,7 +9,7 @@
<property name="icon_name">system-help</property>
<property name="type_hint">normal</property>
<property name="program_name">DemonEditor</property>
<property name="version">0.3.1 Pre-alpha</property>
<property name="version">0.3.2 Pre-alpha</property>
<property name="copyright">2018 Dmitriy Yefremov
</property>
<property name="comments" translatable="yes">Enigma2 channel and satellites list editor for GNU/Linux</property>
@@ -1425,7 +1425,7 @@
</packing>
</child>
<child>
<object class="GtkSeparator" id="separator1">
<object class="GtkSeparator" id="settings_separator1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">2</property>
@@ -1550,7 +1550,7 @@
</packing>
</child>
<child>
<object class="GtkSeparator" id="separator5">
<object class="GtkSeparator" id="settings_separator">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">5</property>
@@ -1564,75 +1564,120 @@
</packing>
</child>
<child>
<object class="GtkBox" id="box3">
<object class="GtkFrame" id="settings_profile_frame">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_right">5</property>
<property name="orientation">vertical</property>
<property name="label_xalign">0</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkBox" id="settings_profile_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkRadioButton" id="enigma_radio_button">
<property name="label">Enigma2 </property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="xalign">0</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">neutrino_radio_button</property>
<signal name="toggled" handler="on_profile_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="support_ver5_check_button">
<property name="label" translatable="yes">Ver. 5 support
(experimental)</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="xalign">0</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkSeparator" id="settings_prof_separator">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">2</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="neutrino_radio_button">
<property name="label">Neutrino-MP
(experimental)</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="xalign">0</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">enigma_radio_button</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkSeparator" id="settings_prof_separator2">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">2</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkButton" id="reset_button">
<property name="label" translatable="yes">Reset profile</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="margin_top">3</property>
<signal name="clicked" handler="on_reset" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">5</property>
</packing>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label12">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Active profile:</property>
<property name="xalign">0.20000000298023224</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="enigma_radio_button">
<property name="label">Enigma2 </property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="xalign">0</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">neutrino_radio_button</property>
<signal name="toggled" handler="on_profile_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkRadioButton" id="neutrino_radio_button">
<property name="label">Neutrino-MP
(experimental)</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="xalign">0</property>
<property name="active">True</property>
<property name="draw_indicator">True</property>
<property name="group">enigma_radio_button</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="reset_button">
<property name="label" translatable="yes">Reset profile</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="xalign">0.49000000953674316</property>
<signal name="clicked" handler="on_reset" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">3</property>
</packing>
</child>
</object>
<packing>

View File

@@ -11,6 +11,7 @@ from app.eparser.ecommons import CAS, Flag
from app.eparser.enigma.bouquets import BqServiceType
from app.eparser.neutrino.bouquets import BqType
from app.properties import get_config, write_config, Profile
from app.tools.media import Player
from .iptv import IptvDialog
from .search import SearchProvider
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, LOCKED_ICON, HIDE_ICON, IPTV_ICON, MOVE_KEYS
@@ -19,7 +20,7 @@ from .download_dialog import show_download_dialog
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, gen_bouquets, BqGenType
from .picons_dialog import PiconsDialog
from .picons_downloader import PiconsDialog
from .satellites_dialog import show_satellites_dialog
from .settings_dialog import show_settings_dialog
from .service_details_dialog import ServiceDetailsDialog, Action
@@ -50,7 +51,7 @@ class MainAppWindow:
"fav_import_m3u_popup_item", "fav_insert_marker_popup_item", "fav_edit_popup_item",
"fav_locate_popup_item", "fav_picon_popup_item", "fav_add_iptv_popup_item")
_FAV_ENIGMA_ELEMENTS = ("fav_insert_marker_popup_item", "fav_edit_marker_popup_item")
_FAV_ENIGMA_ELEMENTS = ("fav_insert_marker_popup_item",)
_FAV_M3U_ELEMENTS = ("import_m3u_tool_button", "fav_import_m3u_popup_item", "fav_add_iptv_popup_item")
@@ -64,9 +65,9 @@ class MainAppWindow:
"bouquets_new_popup_item", "bouquets_edit_popup_item", "services_remove_popup_item",
"bouquets_remove_popup_item", "fav_remove_popup_item", "hide_tool_button",
"import_m3u_tool_button", "fav_import_m3u_popup_item", "fav_insert_marker_popup_item",
"fav_edit_marker_popup_item", "fav_edit_popup_item", "fav_locate_popup_item",
"services_copy_popup_item", "services_picon_popup_item", "fav_picon_popup_item",
"services_add_new_popup_item", "fav_add_iptv_popup_item", "copy_tool_button")
"fav_edit_popup_item", "fav_locate_popup_item", "services_copy_popup_item",
"services_picon_popup_item", "fav_picon_popup_item", "services_add_new_popup_item",
"fav_add_iptv_popup_item", "copy_tool_button")
def __init__(self):
handlers = {"on_close_main_window": self.on_quit,
@@ -101,7 +102,7 @@ class MainAppWindow:
"on_import_m3u": self.on_import_m3u,
"on_insert_marker": self.on_insert_marker,
"on_edit_marker": self.on_edit_marker,
"on_fav_popup": self.on_fav_popup,
"on_fav_press": self.on_fav_press,
"on_locate_in_services": self.on_locate_in_services,
"on_picons_loader_show": self.on_picons_loader_show,
"on_filter_changed": self.on_filter_changed,
@@ -116,6 +117,10 @@ class MainAppWindow:
"on_service_edit": self.on_service_edit,
"on_services_add_new": self.on_services_add_new,
"on_iptv": self.on_iptv,
"on_fav_iptv_mode": self.on_fav_iptv_mode,
"on_drawing_area_realize": self.on_drawing_area_realize,
"on_player_press": self.on_player_press,
"on_main_window_state": self.on_main_window_state,
"on_new_bouquet": self.on_new_bouquet,
"on_bouquets_edit": self.on_bouquets_edit,
"on_create_bouquet_for_current_satellite": self.on_create_bouquet_for_current_satellite,
@@ -136,6 +141,11 @@ class MainAppWindow:
self._picons = {}
self._blacklist = set()
self._current_bq_name = None
# Player
self._iptv_preview_mode = False
self._player = None
self._is_played = False
self._full_screen = False
builder = Gtk.Builder()
builder.set_translation_domain("demon-editor")
@@ -153,10 +163,17 @@ class MainAppWindow:
self._services_model = builder.get_object("services_list_store")
self._bouquets_model = builder.get_object("bouquets_tree_store")
self._status_bar = builder.get_object("status_bar")
self._player_frame = builder.get_object("player_frame")
self._player_drawing_area = builder.get_object("player_drawing_area")
# enabling events for the drawing area
self._player_drawing_area.set_events(Gdk.ModifierType.BUTTON1_MASK)
self._drawing_area_xid = None
self._main_window_box = builder.get_object("main_window_box")
self._fav_iptv_mode_popup_item = builder.get_object("fav_iptv_mode_popup_item")
self._profile_label = builder.get_object("profile_label")
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")
self.update_profile_label()
# dynamically active elements depending on the selected view
self._tool_elements = {k: builder.get_object(k) for k in self._DYNAMIC_ELEMENTS}
self._picons_download_tool_button = builder.get_object("picons_download_tool_button")
@@ -166,7 +183,6 @@ class MainAppWindow:
self._tv_count_label = builder.get_object("tv_count_label")
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.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)
@@ -182,8 +198,7 @@ class MainAppWindow:
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._search_provider = SearchProvider((self._services_view, self._fav_view, self._bouquets_view),
builder.get_object("search_down_button"),
builder.get_object("search_up_button"))
self._main_window.show()
@@ -206,9 +221,13 @@ class MainAppWindow:
""" Function for force ctrl press event for view """
event.state |= Gdk.ModifierType.CONTROL_MASK
@run_idle
def on_quit(self, *args):
""" Called before app quit """
write_config(self._options) # storing current config
if self._player:
self._player.stop()
self._player.release()
Gtk.main_quit()
def on_resize(self, window):
@@ -570,7 +589,8 @@ class MainAppWindow:
def append_services(self, data_path):
try:
services = get_services(data_path, Profile(self._profile))
profile = Profile(self._profile)
services = get_services(data_path, profile, self.get_format_version() if profile is Profile.ENIGMA_2 else 0)
except Exception as e:
print(e)
log("Append services error: " + str(e))
@@ -626,7 +646,7 @@ class MainAppWindow:
write_bouquets(path, bouquets, profile)
# Getting services
services = [Service(*row[:]) for row in services_model]
write_services(path, services, profile)
write_services(path, services, profile, self.get_format_version() if profile is Profile.ENIGMA_2 else 0)
# removing bouquet files
if profile is Profile.ENIGMA_2:
# blacklist
@@ -717,12 +737,14 @@ class MainAppWindow:
if response != Gtk.ResponseType.CANCEL:
profile = self._options.get("profile")
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.update_profile_label()
def on_tree_view_key_release(self, view, event):
""" Handling keystrokes """
key = event.keyval
@@ -766,6 +788,13 @@ class MainAppWindow:
self.on_service_edit(view)
elif key == Gdk.KEY_Left or key == Gdk.KEY_Right:
view.do_unselect_all(view)
elif (key == Gdk.KEY_P or key == Gdk.KEY_p) and model_name == self._FAV_LIST_NAME:
self._iptv_preview_mode = not self._iptv_preview_mode
self._fav_iptv_mode_popup_item.set_active(self._iptv_preview_mode)
self.on_fav_iptv_mode(self._fav_iptv_mode_popup_item)
elif (key == Gdk.KEY_Return or key == Gdk.KEY_KP_Enter) and model_name == self._FAV_LIST_NAME:
if self._iptv_preview_mode:
self.on_play_stream()
def on_download(self, item):
show_download_dialog(transient=self._main_window,
@@ -908,11 +937,80 @@ class MainAppWindow:
def on_edit_marker(self, view):
edit_marker(view, self._bouquets, self.get_selected_bouquet(), self._services, self._main_window)
def on_fav_iptv_mode(self, item):
self._iptv_preview_mode = item.get_active()
self._player_frame.set_visible(self._iptv_preview_mode)
if not self._iptv_preview_mode:
self.on_player_stop(None)
def on_fav_press(self, menu, event):
self.on_view_popup_menu(menu, event)
if self._iptv_preview_mode and event.get_event_type() == Gdk.EventType.DOUBLE_BUTTON_PRESS:
self.on_play_stream()
@run_idle
def on_fav_popup(self, view, event):
model, paths = view.get_selection().get_selected_rows()
self._fav_edit_marker_popup_item.set_sensitive(
len(paths) == 1 and model.get_value(model.get_iter(paths[0]), 5) == BqServiceType.MARKER.name)
def on_play_stream(self):
path, column = self._fav_view.get_cursor()
if path:
row = self._fav_model[path][:]
if row[5] == BqServiceType.IPTV.value:
url = None
profile = Profile(self._profile)
data = row[7].split(":" if profile is Profile.ENIGMA_2 else "::")
if profile is Profile.ENIGMA_2:
data = list(filter(lambda x: "http" in x, data))
if data:
url = data[0]
url = url.replace("%3a", ":") if profile is Profile.ENIGMA_2 else url
if not url:
return
self.on_player_stop(None)
if not self._player:
try:
self._player = Player.get_vlc_instance().media_player_new()
except (NameError, AttributeError):
show_dialog(DialogType.ERROR, self._main_window, "No VLC is found. Check that it is installed!")
else:
self._player.set_xwindow(self._drawing_area_xid)
if self._player:
self._player.set_mrl(url)
self._is_played = True
self._player.play()
def on_player_stop(self, item):
if self._player:
self._player.stop()
self._is_played = False
def on_player_press(self, area, event):
if event.button == Gdk.BUTTON_PRIMARY:
if event.type == Gdk.EventType.DOUBLE_BUTTON_PRESS:
self._full_screen = not self._full_screen
self._main_window.fullscreen() if self._full_screen else self._main_window.unfullscreen()
elif event.type == Gdk.EventType.BUTTON_PRESS:
if self._player:
self._player.stop() if self._player.is_playing() else self._player.play()
def on_main_window_state(self, window, event):
if event.new_window_state & Gdk.WindowState.FULLSCREEN:
if self._main_window_box in window:
window.remove(self._main_window_box)
self._player_drawing_area.reparent(window)
if self._player:
self._player.set_xwindow(self._player_drawing_area.get_window().get_xid())
else:
if self._player_drawing_area in window:
window.remove(self._player_drawing_area)
window.add(self._main_window_box)
self._player_frame.add(self._player_drawing_area)
if self._player:
self._player.set_xwindow(self._player_drawing_area.get_window().get_xid())
def on_drawing_area_realize(self, widget):
self._drawing_area_xid = widget.get_window().get_xid()
def on_locate_in_services(self, view):
locate_in_services(view, self._services_view, self._main_window)
@@ -1040,6 +1138,16 @@ class MainAppWindow:
gen_bouquets(self._services_view, self._bouquets_view, self._main_window, g_type, self._TV_TYPES,
Profile(self._profile), self.append_bouquet)
def update_profile_label(self):
profile = Profile(self._profile)
if profile is Profile.ENIGMA_2:
self._profile_label.set_text("Enigma2 v.{}".format(self.get_format_version()))
elif profile is Profile.NEUTRINO_MP:
self._profile_label.set_text("Neutrino-MP")
def get_format_version(self):
return 5 if self._options.get(self._profile).get("v5_support", False) else 4
def start_app():
MainAppWindow()

View File

@@ -525,5 +525,13 @@ def get_base_model(model):
return model
def append_text_to_tview(char, view):
""" Appending text and scrolling to a given line in the text view. """
buf = view.get_buffer()
buf.insert_at_cursor(char)
insert = buf.get_insert()
view.scroll_to_mark(insert, 0.0, True, 0.0, 1.0)
if __name__ == "__main__":
pass

View File

@@ -58,7 +58,7 @@
<property name="can_focus">False</property>
<property name="stock">gtk-clear</property>
</object>
<object class="GtkImage" id="clearimage">
<object class="GtkImage" id="clear_image_2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-clear</property>
@@ -78,11 +78,6 @@
<property name="can_focus">False</property>
<property name="icon_name">emblem-downloads</property>
</object>
<object class="GtkImage" id="edit_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-edit</property>
</object>
<object class="GtkImage" id="edit_select_all_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
@@ -117,41 +112,6 @@
<property name="can_focus">False</property>
<property name="stock">gtk-find</property>
</object>
<object class="GtkImage" id="image1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-save-as</property>
</object>
<object class="GtkImage" id="image4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-select-all</property>
</object>
<object class="GtkImage" id="image5">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-new</property>
</object>
<object class="GtkImage" id="image6">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-save-as</property>
</object>
<object class="GtkImage" id="image7">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-select-all</property>
</object>
<object class="GtkImage" id="image8">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-save-as</property>
</object>
<object class="GtkImage" id="image9">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-select-all</property>
</object>
<object class="GtkImage" id="insert_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
@@ -172,222 +132,6 @@
<property name="can_focus">False</property>
<property name="icon_name">insert-link</property>
</object>
<object class="GtkMenu" id="services_popup_menu">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkImageMenuItem" id="services_to_fav_move_popup_item">
<property name="label">gtk-go-forward</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_to_fav_move" object="services_tree_view" swapped="no"/>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="services_separatormenuitem">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="services_create_bouquet_popup_item">
<property name="label" translatable="yes">Create bouquet</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="image">image5</property>
<property name="use_stock">False</property>
<child type="submenu">
<object class="GtkMenu" id="services_bouquet_popup_menu">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkImageMenuItem" id="services_create_bouquet_for_current_sat_popup_item">
<property name="label" translatable="yes">For current satellite</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">image1</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_create_bouquet_for_current_satellite" swapped="no"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="services_create_bouquet_for_current_package_popup_item">
<property name="label" translatable="yes">For current package</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">image6</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_create_bouquet_for_current_package" swapped="no"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="services_create_bouquet_for_current_type_popup_item">
<property name="label" translatable="yes">For current type</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">image8</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_create_bouquet_for_current_type" swapped="no"/>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="services_bouquet_separator">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="services_create_bouquet_for_each_sat_popup_item">
<property name="label" translatable="yes">For each satellite</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">image4</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_create_bouquet_for_each_satellite" swapped="no"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="services_create_bouquet_for_each_package_popup_item">
<property name="label" translatable="yes">For each package</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">image7</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_create_bouquet_for_each_package" swapped="no"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="services_create_bouquet_for_each_type_popup_item">
<property name="label" translatable="yes">For each type</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">image9</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_create_bouquet_for_each_type" swapped="no"/>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="services_separatormenuitem_2">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="services_copy_popup_item">
<property name="label">gtk-copy</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_copy" object="services_tree_view" swapped="no"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="services_edit_popup_item">
<property name="label">gtk-edit</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="resize_mode">immediate</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_service_edit" object="services_tree_view" swapped="no"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="services_add_new_popup_item">
<property name="label">gtk-new</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_services_add_new" swapped="no"/>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="services_separatormenuitem_3">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="services_picon_popup_item">
<property name="label" translatable="yes">Picon</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="image">insert_image_2</property>
<property name="use_stock">False</property>
<child type="submenu">
<object class="GtkMenu" id="services_picon_popoup_menu">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkImageMenuItem" id="services_assign_picon_popup_item">
<property name="label" translatable="yes">Assign</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">insert_link_image</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_assign_picon" object="services_tree_view" swapped="no"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="services_remove_picon_popup_item">
<property name="label" translatable="yes">Remove</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">clear_image</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_remove_picon" object="services_tree_view" swapped="no"/>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="services_separatormenuitem_4">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="services_reference_picon_popup_item">
<property name="label" translatable="yes">Copy reference</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">copy_image</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_reference_picon" object="services_tree_view" swapped="no"/>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="services_separatormenuitem_5">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="services_remove_popup_item">
<property name="label">gtk-remove</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_delete" swapped="no"/>
</object>
</child>
</object>
<object class="GtkImage" id="insert_link_image_2">
<property name="visible">True</property>
<property name="can_focus">False</property>
@@ -403,6 +147,11 @@
<property name="can_focus">False</property>
<property name="icon_name">network-transmit-receive</property>
</object>
<object class="GtkImage" id="networktransmit_receive_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">network-transmit-receive</property>
</object>
<object class="GtkMenu" id="fav_popup_menu">
<property name="visible">True</property>
<property name="can_focus">False</property>
@@ -474,18 +223,6 @@
<signal name="activate" handler="on_insert_marker" object="fav_tree_view" swapped="no"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="fav_edit_marker_popup_item">
<property name="label" translatable="yes">Edit mаrker text</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="image">edit_image</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_edit_marker" object="fav_tree_view" swapped="no"/>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="fav_pupup_separator_2">
<property name="visible">True</property>
@@ -493,26 +230,49 @@
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="fav_import_m3u_popup_item">
<property name="label" translatable="yes">Import m3u</property>
<object class="GtkImageMenuItem" id="fav_iptv_popup_item">
<property name="label" translatable="yes">IPTV</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="image">downloads_image</property>
<property name="image">networktransmit_receive_image</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_import_m3u" swapped="no"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="fav_add_iptv_popup_item">
<property name="label" translatable="yes">Add IPTV or stream service</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="image">network_transmit_receive_image</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_iptv" swapped="no"/>
<child type="submenu">
<object class="GtkMenu" id="fav_iptv_popoup_menu">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkCheckMenuItem" id="fav_iptv_mode_popup_item">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Preview mode</property>
<signal name="toggled" handler="on_fav_iptv_mode" swapped="no"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="fav_import_m3u_popup_item">
<property name="label" translatable="yes">Import m3u</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="image">downloads_image</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_import_m3u" swapped="no"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="fav_add_iptv_popup_item">
<property name="label" translatable="yes">Add IPTV or stream service</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="image">network_transmit_receive_image</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_iptv" swapped="no"/>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
@@ -548,7 +308,7 @@
<property name="label" translatable="yes">Remove</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">clearimage</property>
<property name="image">clear_image_2</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_remove_picon" object="fav_tree_view" swapped="no"/>
</object>
@@ -591,6 +351,36 @@
</object>
</child>
</object>
<object class="GtkImage" id="new_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-new</property>
</object>
<object class="GtkImage" id="save_as_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-save-as</property>
</object>
<object class="GtkImage" id="save_as_image_2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-save-as</property>
</object>
<object class="GtkImage" id="save_as_image_3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-save-as</property>
</object>
<object class="GtkImage" id="select_all_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-select-all</property>
</object>
<object class="GtkImage" id="select_all_image_3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-select-all</property>
</object>
<object class="GtkImage" id="send_recive_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
@@ -654,6 +444,7 @@
<property name="icon_name">accessories-text-editor</property>
<signal name="check-resize" handler="on_resize" swapped="no"/>
<signal name="delete-event" handler="on_close_main_window" swapped="no"/>
<signal name="window-state-event" handler="on_main_window_state" swapped="no"/>
<child>
<object class="GtkBox" id="main_window_box">
<property name="visible">True</property>
@@ -794,8 +585,8 @@
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="Picons loader">
<property name="label" translatable="yes">Picons loader</property>
<object class="GtkImageMenuItem" id="picons_downloader_menu_item">
<property name="label" translatable="yes">Picons downloader</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
@@ -805,7 +596,7 @@
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="menuitem5">
<object class="GtkSeparatorMenuItem" id="tools_separatormenuitem2">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
@@ -1458,7 +1249,7 @@
<property name="margin_right">1</property>
<property name="wide_handle">True</property>
<child>
<object class="GtkBox" id="box4">
<object class="GtkBox" id="services_main_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
@@ -2018,7 +1809,7 @@
<property name="can_focus">True</property>
<property name="wide_handle">True</property>
<child>
<object class="GtkBox" id="box2">
<object class="GtkBox" id="fav_main_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
@@ -2038,125 +1829,159 @@
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow2">
<object class="GtkPaned" id="fav_paned">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="margin_bottom">2</property>
<property name="shadow_type">in</property>
<property name="orientation">vertical</property>
<property name="wide_handle">True</property>
<child>
<object class="GtkTreeView" id="fav_tree_view">
<object class="GtkFrame" id="player_frame">
<property name="height_request">30</property>
<property name="can_focus">False</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkDrawingArea" id="player_drawing_area">
<property name="visible">True</property>
<property name="can_focus">True</property>
<signal name="button-press-event" handler="on_player_press" swapped="no"/>
<signal name="realize" handler="on_drawing_area_realize" swapped="no"/>
</object>
</child>
<child type="label_item">
<placeholder/>
</child>
</object>
<packing>
<property name="resize">True</property>
<property name="shrink">True</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="fav_scrolled_window">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="model">fav_list_store</property>
<property name="search_column">2</property>
<property name="rubber_banding">True</property>
<property name="enable_grid_lines">both</property>
<property name="activate_on_single_click">True</property>
<signal name="button-press-event" handler="on_fav_popup" swapped="no"/>
<signal name="button-press-event" handler="on_view_popup_menu" object="fav_popup_menu" swapped="no"/>
<signal name="drag-data-get" handler="on_fav_tree_view_drag_data_get" swapped="no"/>
<signal name="drag-data-received" handler="on_fav_tree_view_drag_data_received" swapped="no"/>
<signal name="focus-in-event" handler="on_view_focus" swapped="no"/>
<signal name="key-release-event" handler="on_tree_view_key_release" swapped="no"/>
<signal name="row-activated" handler="on_fav_selection" object="fav_list_store" swapped="no"/>
<child internal-child="selection">
<object class="GtkTreeSelection" id="fav_selection">
<property name="mode">multiple</property>
</object>
</child>
<property name="margin_bottom">2</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTreeViewColumn" id="num_column">
<property name="title" translatable="yes">Num</property>
<child>
<object class="GtkCellRendererText" id="num_cellrenderertext">
<property name="xalign">0.20000000298023224</property>
<object class="GtkTreeView" id="fav_tree_view">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="model">fav_list_store</property>
<property name="search_column">2</property>
<property name="rubber_banding">True</property>
<property name="enable_grid_lines">both</property>
<property name="activate_on_single_click">True</property>
<signal name="button-press-event" handler="on_fav_press" object="fav_popup_menu" swapped="no"/>
<signal name="drag-data-get" handler="on_fav_tree_view_drag_data_get" swapped="no"/>
<signal name="drag-data-received" handler="on_fav_tree_view_drag_data_received" swapped="no"/>
<signal name="focus-in-event" handler="on_view_focus" swapped="no"/>
<signal name="key-release-event" handler="on_tree_view_key_release" swapped="no"/>
<signal name="row-activated" handler="on_fav_selection" object="fav_list_store" swapped="no"/>
<child internal-child="selection">
<object class="GtkTreeSelection" id="fav_selection">
<property name="mode">multiple</property>
</object>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="fav_service_column">
<property name="resizable">True</property>
<property name="spacing">2</property>
<property name="sizing">autosize</property>
<property name="title" translatable="yes">Service</property>
<property name="expand">True</property>
<child>
<object class="GtkCellRendererPixbuf" id="fav_picon_cellrendererpixbuf"/>
<attributes>
<attribute name="pixbuf">8</attribute>
</attributes>
</child>
<child>
<object class="GtkCellRendererPixbuf" id="fav_coded_cellrendererpixbuf"/>
<attributes>
<attribute name="pixbuf">1</attribute>
</attributes>
</child>
<child>
<object class="GtkCellRendererText" id="fav_service_cellrenderertext"/>
<attributes>
<attribute name="text">2</attribute>
</attributes>
</child>
<child>
<object class="GtkCellRendererPixbuf" id="fav_locked_cellrendererpixbuf"/>
<attributes>
<attribute name="pixbuf">3</attribute>
</attributes>
</child>
<child>
<object class="GtkCellRendererPixbuf" id="fav_hide_cellrendererpixbuf"/>
<attributes>
<attribute name="pixbuf">4</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="fav_type_column">
<property name="title" translatable="yes">Type</property>
<property name="expand">True</property>
<child>
<object class="GtkCellRendererText" id="type_cellrenderertext">
<property name="xalign">0.50999999046325684</property>
<object class="GtkTreeViewColumn" id="num_column">
<property name="title" translatable="yes">Num</property>
<child>
<object class="GtkCellRendererText" id="num_cellrenderertext">
<property name="xalign">0.20000000298023224</property>
</object>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
<attributes>
<attribute name="text">5</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="fav_pos_column">
<property name="title" translatable="yes">Pos</property>
<property name="expand">True</property>
<child>
<object class="GtkCellRendererText" id="pos_cellrenderertext">
<property name="xalign">0.50999999046325684</property>
<object class="GtkTreeViewColumn" id="fav_service_column">
<property name="resizable">True</property>
<property name="spacing">2</property>
<property name="sizing">autosize</property>
<property name="title" translatable="yes">Service</property>
<property name="expand">True</property>
<child>
<object class="GtkCellRendererPixbuf" id="fav_picon_cellrendererpixbuf"/>
<attributes>
<attribute name="pixbuf">8</attribute>
</attributes>
</child>
<child>
<object class="GtkCellRendererPixbuf" id="fav_coded_cellrendererpixbuf"/>
<attributes>
<attribute name="pixbuf">1</attribute>
</attributes>
</child>
<child>
<object class="GtkCellRendererText" id="fav_service_cellrenderertext"/>
<attributes>
<attribute name="text">2</attribute>
</attributes>
</child>
<child>
<object class="GtkCellRendererPixbuf" id="fav_locked_cellrendererpixbuf"/>
<attributes>
<attribute name="pixbuf">3</attribute>
</attributes>
</child>
<child>
<object class="GtkCellRendererPixbuf" id="fav_hide_cellrendererpixbuf"/>
<attributes>
<attribute name="pixbuf">4</attribute>
</attributes>
</child>
</object>
<attributes>
<attribute name="text">6</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="fav_id_column">
<property name="visible">False</property>
<property name="title">fav_id</property>
<child>
<object class="GtkCellRendererText" id="fav_id_cellrenderertext4"/>
<attributes>
<attribute name="text">7</attribute>
</attributes>
<object class="GtkTreeViewColumn" id="fav_type_column">
<property name="title" translatable="yes">Type</property>
<property name="expand">True</property>
<child>
<object class="GtkCellRendererText" id="type_cellrenderertext">
<property name="xalign">0.50999999046325684</property>
</object>
<attributes>
<attribute name="text">5</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="fav_pos_column">
<property name="title" translatable="yes">Pos</property>
<property name="expand">True</property>
<child>
<object class="GtkCellRendererText" id="pos_cellrenderertext">
<property name="xalign">0.50999999046325684</property>
</object>
<attributes>
<attribute name="text">6</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="fav_id_column">
<property name="visible">False</property>
<property name="title">fav_id</property>
<child>
<object class="GtkCellRendererText" id="fav_id_cellrenderertext4"/>
<attributes>
<attribute name="text">7</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="resize">True</property>
<property name="shrink">True</property>
</packing>
</child>
</object>
<packing>
@@ -2205,7 +2030,7 @@
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
<property name="position">4</property>
</packing>
</child>
</object>
@@ -2215,7 +2040,7 @@
</packing>
</child>
<child>
<object class="GtkBox" id="box3">
<object class="GtkBox" id="bouquets_main_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
@@ -2469,7 +2294,7 @@
<object class="GtkLabel" id="ver_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label">Ver. 0.3.1 Pre-alpha</property>
<property name="label">Ver. 0.3.2 Pre-alpha</property>
<property name="xalign">0.94999998807907104</property>
</object>
<packing>
@@ -2492,4 +2317,225 @@
</object>
</child>
</object>
<object class="GtkImage" id="slect_all_image_2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-select-all</property>
</object>
<object class="GtkMenu" id="services_popup_menu">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkImageMenuItem" id="services_to_fav_move_popup_item">
<property name="label">gtk-go-forward</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_to_fav_move" object="services_tree_view" swapped="no"/>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="services_separatormenuitem">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="services_create_bouquet_popup_item">
<property name="label" translatable="yes">Create bouquet</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="image">new_image</property>
<property name="use_stock">False</property>
<child type="submenu">
<object class="GtkMenu" id="services_bouquet_popup_menu">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkImageMenuItem" id="services_create_bouquet_for_current_sat_popup_item">
<property name="label" translatable="yes">For current satellite</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">save_as_image_2</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_create_bouquet_for_current_satellite" swapped="no"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="services_create_bouquet_for_current_package_popup_item">
<property name="label" translatable="yes">For current package</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">save_as_image</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_create_bouquet_for_current_package" swapped="no"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="services_create_bouquet_for_current_type_popup_item">
<property name="label" translatable="yes">For current type</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">save_as_image_3</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_create_bouquet_for_current_type" swapped="no"/>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="services_bouquet_separator">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="services_create_bouquet_for_each_sat_popup_item">
<property name="label" translatable="yes">For each satellite</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">select_all_image</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_create_bouquet_for_each_satellite" swapped="no"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="services_create_bouquet_for_each_package_popup_item">
<property name="label" translatable="yes">For each package</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">slect_all_image_2</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_create_bouquet_for_each_package" swapped="no"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="services_create_bouquet_for_each_type_popup_item">
<property name="label" translatable="yes">For each type</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">select_all_image_3</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_create_bouquet_for_each_type" swapped="no"/>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="services_separatormenuitem_2">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="services_copy_popup_item">
<property name="label">gtk-copy</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_copy" object="services_tree_view" swapped="no"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="services_edit_popup_item">
<property name="label">gtk-edit</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="resize_mode">immediate</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_service_edit" object="services_tree_view" swapped="no"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="services_add_new_popup_item">
<property name="label">gtk-new</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_services_add_new" swapped="no"/>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="services_separatormenuitem_3">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="services_picon_popup_item">
<property name="label" translatable="yes">Picon</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="image">insert_image_2</property>
<property name="use_stock">False</property>
<child type="submenu">
<object class="GtkMenu" id="services_picon_popoup_menu">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkImageMenuItem" id="services_assign_picon_popup_item">
<property name="label" translatable="yes">Assign</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">insert_link_image</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_assign_picon" object="services_tree_view" swapped="no"/>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="services_remove_picon_popup_item">
<property name="label" translatable="yes">Remove</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">clear_image</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_remove_picon" object="services_tree_view" swapped="no"/>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="services_separatormenuitem_4">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="services_reference_picon_popup_item">
<property name="label" translatable="yes">Copy reference</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="image">copy_image</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_reference_picon" object="services_tree_view" swapped="no"/>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkSeparatorMenuItem" id="services_separatormenuitem_5">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
<child>
<object class="GtkImageMenuItem" id="services_remove_popup_item">
<property name="label">gtk-remove</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_delete" swapped="no"/>
</object>
</child>
</object>
</interface>

View File

@@ -7,11 +7,11 @@ 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, convert_to
from app.tools.picons import PiconsParser, parse_providers, Provider, convert_to
from app.properties import Profile
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, TEXT_DOMAIN
from .dialogs import show_dialog, DialogType, get_message
from .main_helper import update_entry_data
from .main_helper import update_entry_data, append_text_to_tview
class PiconsDialog:
@@ -166,13 +166,7 @@ class PiconsDialog:
@run_idle
def append_output(self, char):
buf = self._text_view.get_buffer()
buf.insert_at_cursor(char)
self.scroll_to_end(buf)
def scroll_to_end(self, buf):
insert = buf.get_insert()
self._text_view.scroll_to_mark(insert, 0.0, True, 0.0, 1.0)
append_text_to_tview(char, self._text_view)
def resize(self, path):
if self._resize_no_radio_button.get_active():

View File

@@ -194,6 +194,11 @@
<property name="step_increment">0.10000000000000001</property>
<property name="page_increment">10</property>
</object>
<object class="GtkAdjustment" id="pos_adjustment2">
<property name="upper">180</property>
<property name="step_increment">0.10000000000000001</property>
<property name="page_increment">10</property>
</object>
<object class="GtkTreeStore" id="satellites_tree_store">
<columns>
<!-- column-name satelitte -->
@@ -451,6 +456,31 @@
<property name="homogeneous">False</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="update_tool_button">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Update from internet</property>
<property name="label" translatable="yes">Receive from internet</property>
<property name="use_underline">True</property>
<property name="stock_id">gtk-refresh</property>
<signal name="clicked" handler="on_update" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkSeparatorToolItem" id="separatortoolitem4">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">False</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="up_tool_button">
<property name="visible">True</property>
@@ -739,7 +769,7 @@
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
<property name="position">4</property>
</packing>
</child>
</object>
@@ -1388,4 +1418,734 @@
<action-widget response="-5">button2</action-widget>
</action-widgets>
</object>
<object class="GtkListStore" id="update_sat_list_store">
<columns>
<!-- column-name satellite -->
<column type="gchararray"/>
<!-- column-name position -->
<column type="gchararray"/>
<!-- column-name type -->
<column type="gchararray"/>
<!-- column-name url -->
<column type="gchararray"/>
<!-- column-name selected -->
<column type="gboolean"/>
</columns>
</object>
<object class="GtkTreeModelFilter" id="update_sat_list_model_filter">
<property name="child_model">update_sat_list_store</property>
</object>
<object class="GtkTreeModelSort" id="update_sat_list_model_sort">
<property name="model">update_sat_list_model_filter</property>
</object>
<object class="GtkListStore" id="update_source_store">
<columns>
<!-- column-name source -->
<column type="gchararray"/>
</columns>
<data>
<row>
<col id="0">FlySat</col>
</row>
<row>
<col id="0">LyngSat</col>
</row>
</data>
</object>
<object class="GtkDialog" id="satellites_update_dialog">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Satellites update</property>
<property name="modal">True</property>
<property name="default_height">480</property>
<property name="destroy_with_parent">True</property>
<property name="type_hint">dialog</property>
<property name="skip_pager_hint">True</property>
<child internal-child="vbox">
<object class="GtkBox" id="sat_update_dialog_vbox">
<property name="width_request">480</property>
<property name="height_request">320</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox" id="sat_update_dialog_action_area">
<property name="can_focus">False</property>
<property name="layout_style">center</property>
<child>
<object class="GtkButton" id="sat_update_close_button">
<property name="label">gtk-close</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="satellites_update_main_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkToolbar" id="sat_update_header_tool_bar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkToolItem" id="sat_update_source_tool_button">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkLabel" id="source_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="margin_left">2</property>
<property name="label" translatable="yes">Source:</property>
<property name="track_visited_links">False</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkToolItem" id="source_tool_item">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkComboBox" id="source_combo_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="model">update_source_store</property>
<property name="active">0</property>
<child>
<object class="GtkCellRendererText" id="source_cellrenderertext"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">False</property>
</packing>
</child>
<child>
<object class="GtkToolItem" id="sep_tool_item">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkToggleToolButton" id="sat_update_filter_button">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="is_important">True</property>
<property name="label" translatable="yes">Filter</property>
<property name="use_underline">True</property>
<property name="stock_id">gtk-select-all</property>
<signal name="toggled" handler="on_filter_toggled" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">False</property>
</packing>
</child>
<child>
<object class="GtkToggleToolButton" id="sat_update_find_button">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="is_important">True</property>
<property name="label" translatable="yes">Find</property>
<property name="use_underline">True</property>
<property name="stock_id">gtk-find</property>
<signal name="toggled" handler="on_find_toggled" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">False</property>
</packing>
</child>
<style>
<class name="primary-toolbar"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkInfoBar" id="sat_update_search_info_bar">
<property name="app_paintable">True</property>
<property name="can_focus">False</property>
<child internal-child="action_area">
<object class="GtkButtonBox" id="infobar-action_area4">
<property name="can_focus">False</property>
<property name="spacing">6</property>
<property name="layout_style">end</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child internal-child="content_area">
<object class="GtkBox" id="infobar-content_area4">
<property name="can_focus">False</property>
<property name="homogeneous">True</property>
<child>
<object class="GtkBox" id="search_bar_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkSearchEntry" id="sat_update_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="sat_update_search_down_button">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="on_search_down" swapped="no"/>
<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="sat_update_search_up_button">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="on_search_up" swapped="no"/>
<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>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkInfoBar" id="sat_update_filter_info_bar">
<property name="app_paintable">True</property>
<property name="can_focus">False</property>
<child internal-child="action_area">
<object class="GtkButtonBox" id="infobar-action_area3">
<property name="can_focus">False</property>
<property name="spacing">2</property>
<property name="layout_style">end</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child internal-child="content_area">
<object class="GtkBox" id="infobar-content_area3">
<property name="can_focus">False</property>
<property name="spacing">5</property>
<property name="homogeneous">True</property>
<child>
<object class="GtkGrid" id="source_header_grid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_bottom">2</property>
<property name="column_spacing">2</property>
<child>
<object class="GtkLabel" id="from_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">From:</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="from_pos_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="input_purpose">number</property>
<property name="adjustment">pos_adjustment</property>
<property name="digits">1</property>
<property name="numeric">True</property>
<signal name="changed" handler="on_filter" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkComboBox" id="filter_from_combo_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="model">side_store</property>
<property name="active">0</property>
<signal name="changed" handler="on_filter" swapped="no"/>
<child>
<object class="GtkCellRendererText" id="from_filter_cellrenderertext"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
<packing>
<property name="left_attach">2</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="to_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">To:</property>
</object>
<packing>
<property name="left_attach">3</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="to_pos_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="input_purpose">number</property>
<property name="adjustment">pos_adjustment2</property>
<property name="digits">1</property>
<property name="numeric">True</property>
<signal name="changed" handler="on_filter" swapped="no"/>
</object>
<packing>
<property name="left_attach">4</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkComboBox" id="filter_to_combo_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="model">side_store</property>
<property name="active">0</property>
<signal name="changed" handler="on_filter" swapped="no"/>
<child>
<object class="GtkCellRendererText" id="filter_to_cellrenderertext"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
<packing>
<property name="left_attach">5</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="filter_apply_button">
<property name="label">gtk-apply</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="on_filter" swapped="no"/>
</object>
<packing>
<property name="left_attach">6</property>
<property name="top_attach">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkSeparator" id="separator8">
<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">4</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="sat_update_scrolled_window">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTreeView" id="sat_update_tree_view">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="model">update_sat_list_model_sort</property>
<child internal-child="selection">
<object class="GtkTreeSelection" id="sat_update_treeview_selection">
<property name="mode">multiple</property>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="upd_satellite_column">
<property name="title" translatable="yes">Satellite</property>
<property name="expand">True</property>
<property name="reorderable">True</property>
<property name="sort_column_id">0</property>
<child>
<object class="GtkCellRendererText" id="upd_satellite_cellrenderertext"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="upd_position_column">
<property name="title" translatable="yes">Position</property>
<property name="expand">True</property>
<property name="reorderable">True</property>
<property name="sort_column_id">1</property>
<child>
<object class="GtkCellRendererText" id="upd_position_cellrenderertext"/>
<attributes>
<attribute name="text">1</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="upd_type_column">
<property name="title" translatable="yes">Type</property>
<property name="expand">True</property>
<property name="reorderable">True</property>
<property name="sort_column_id">2</property>
<child>
<object class="GtkCellRendererText" id="upd_type_cellrenderertext"/>
<attributes>
<attribute name="text">2</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="upd_url_column">
<property name="visible">False</property>
<property name="title" translatable="yes">Url</property>
<child>
<object class="GtkCellRendererText" id="upd_url_cellrenderertext"/>
<attributes>
<attribute name="text">3</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="upd_selected_treeviewcolumn">
<property name="title" translatable="yes">Selected</property>
<property name="reorderable">True</property>
<property name="sort_column_id">4</property>
<child>
<object class="GtkCellRendererToggle" id="upd_selected_cellrenderertoggle">
<signal name="toggled" handler="on_selected_toggled" swapped="no"/>
</object>
<attributes>
<attribute name="active">4</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">5</property>
</packing>
</child>
<child>
<object class="GtkSeparator" id="separator7">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">2</property>
<property name="position">6</property>
</packing>
</child>
<child>
<object class="GtkToolbar" id="sat_update_toolbar">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkToolButton" id="cancel_tool_button">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="is_important">True</property>
<property name="label" translatable="yes">Cancel</property>
<property name="use_underline">True</property>
<property name="stock_id">gtk-cancel</property>
<signal name="clicked" handler="on_cancel_receive" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="update_sat_list_tool_button">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="is_important">True</property>
<property name="label" translatable="yes">Update</property>
<property name="use_underline">True</property>
<property name="stock_id">gtk-refresh</property>
<signal name="clicked" handler="on_update_satellites_list" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="receive_sat_list_tool_button">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">False</property>
<property name="is_important">True</property>
<property name="label" translatable="yes">Receive</property>
<property name="use_underline">True</property>
<property name="stock_id">gtk-goto-bottom</property>
<signal name="clicked" handler="on_receive_satellites_list" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="homogeneous">True</property>
</packing>
</child>
<style>
<class name="primary-toolbar"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">7</property>
</packing>
</child>
<child>
<object class="GtkExpander" id="sat_update_expander">
<property name="visible">True</property>
<property name="can_focus">True</property>
<child>
<object class="GtkScrolledWindow" id="text_view_scrolled_window">
<property name="height_request">120</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTextView" id="text_view">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="editable">False</property>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="Extra:">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Extra:</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">8</property>
</packing>
</child>
<child>
<object class="GtkInfoBar" id="sat_update_info_bar">
<property name="app_paintable">True</property>
<property name="can_focus">False</property>
<property name="show_close_button">True</property>
<signal name="response" handler="on_info_bar_close" swapped="no"/>
<child internal-child="action_area">
<object class="GtkButtonBox" id="infobar-action_area2">
<property name="can_focus">False</property>
<property name="spacing">6</property>
<property name="layout_style">end</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child internal-child="content_area">
<object class="GtkBox" id="infobar-content_area2">
<property name="can_focus">False</property>
<property name="spacing">16</property>
<child>
<object class="GtkLabel" id="info_bar_message_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Info</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">9</property>
</packing>
</child>
<child>
<object class="GtkSeparator" id="separator6">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">2</property>
<property name="position">10</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
<action-widgets>
<action-widget response="-6">sat_update_close_button</action-widget>
</action-widgets>
</object>
</interface>

View File

@@ -1,22 +1,22 @@
import re
import time
import concurrent.futures
from math import fabs
from app.commons import run_idle
from app.commons import run_idle, run_task
from app.eparser import get_satellites, write_satellites, Satellite, Transponder
from app.tools.satellites import SatellitesParser, SatelliteSource
from .search import SearchProvider
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, TEXT_DOMAIN, MOVE_KEYS
from .dialogs import show_dialog, DialogType, WaitDialog
from .main_helper import move_items, scroll_to
from .main_helper import move_items, scroll_to, append_text_to_tview, get_base_model
def show_satellites_dialog(transient, options):
dialog = SatellitesDialog(transient, options)
dialog.run()
dialog.destroy()
SatellitesDialog(transient, options).show()
class SatellitesDialog:
__slots__ = ["_dialog", "_data_path", "_stores", "_options", "_sat_view", "_wait_dialog"]
_aggr = [None for x in range(9)] # aggregate
def __init__(self, transient, options):
@@ -26,6 +26,7 @@ class SatellitesDialog:
handlers = {"on_open": self.on_open,
"on_remove": self.on_remove,
"on_save": self.on_save,
"on_update": self.on_update,
"on_up": self.on_up,
"on_down": self.on_down,
"on_popup_menu": self.on_popup_menu,
@@ -40,8 +41,8 @@ class SatellitesDialog:
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"))
("satellites_editor_dialog", "satellites_tree_store", "popup_menu",
"add_popup_menu", "add_menu_icon", "receive_menu_icon"))
builder.connect_signals(handlers)
# Adding custom image for add_menu_tool_button
add_menu_tool_button = builder.get_object("add_menu_tool_button")
@@ -63,10 +64,9 @@ class SatellitesDialog:
6: builder.get_object("mod_store")}
self.on_satellites_list_load(self._sat_view.get_model())
def run(self):
@run_idle
def show(self):
self._dialog.run()
def destroy(self):
self._dialog.destroy()
def on_resize(self, window):
@@ -75,7 +75,7 @@ class SatellitesDialog:
self._options["sat_editor_window_size"] = window.get_size()
def on_quit(self, item):
self.destroy()
self._dialog.destroy()
def on_open(self, model):
file_filter = Gtk.FileFilter()
@@ -147,10 +147,8 @@ class SatellitesDialog:
@run_idle
def append_data(self, model, satellites):
for name, flags, pos, transponders in satellites:
parent = model.append(None, [name, *self._aggr, flags, pos])
for transponder in transponders:
model.append(parent, ["Transponder:", *transponder, None, None])
for sat in satellites:
append_satellite(model, sat)
def on_add(self, view):
""" Common adding """
@@ -253,9 +251,7 @@ class SatellitesDialog:
returns selected path or None
"""
model, paths = view.get_selection().get_selected_rows()
paths_count = len(paths)
if paths_count > 1:
if len(paths) > 1:
show_dialog(DialogType.ERROR, self._dialog, message)
return
@@ -265,9 +261,8 @@ class SatellitesDialog:
def on_remove(view):
selection = view.get_selection()
model, paths = selection.get_selected_rows()
itrs = [model.get_iter(path) for path in paths]
for itr in itrs:
for itr in [model.get_iter(path) for path in paths]:
model.remove(itr)
def on_save(self, view):
@@ -279,6 +274,11 @@ class SatellitesDialog:
model.foreach(self.parse_data, satellites)
write_satellites(satellites, self._data_path)
def on_update(self, item):
dialog = SatellitesUpdateDialog(self._dialog, self._sat_view.get_model())
dialog.run()
dialog.destroy()
@staticmethod
def parse_data(model, path, itr, sats):
if model.iter_has_child(itr):
@@ -301,6 +301,8 @@ class SatellitesDialog:
menu.popup(None, None, None, None, event.button, event.time)
# ***************** Transponder dialog *******************#
class TransponderDialog:
""" Shows dialog for adding or edit transponder """
@@ -311,9 +313,7 @@ class TransponderDialog:
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",
"mod_store", "system_store",
("transponder_dialog", "pol_store", "fec_store", "mod_store", "system_store",
"pls_mode_store"))
builder.connect_signals(handlers)
@@ -388,6 +388,8 @@ class TransponderDialog:
return True
# ***************** Satellite dialog *******************#
class SatelliteDialog:
""" Shows dialog for adding or edit satellite """
@@ -429,5 +431,240 @@ class SatelliteDialog:
return Satellite(name=name, flags="0", position=pos, transponders=None)
# ***************** Satellite update dialog *******************#
class SatellitesUpdateDialog:
""" Dialog for update satellites over internet """
def __init__(self, transient, main_model):
handlers = {"on_update_satellites_list": self.on_update_satellites_list,
"on_receive_satellites_list": self.on_receive_satellites_list,
"on_cancel_receive": self.on_cancel_receive,
"on_selected_toggled": self.on_selected_toggled,
"on_info_bar_close": self.on_info_bar_close,
"on_filter_toggled": self.on_filter_toggled,
"on_find_toggled": self.on_find_toggled,
"on_filter": self.on_filter,
"on_search": self.on_search,
"on_search_down": self.on_search_down,
"on_search_up": self.on_search_up,
"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_update_dialog", "update_source_store", "update_sat_list_store",
"update_sat_list_model_filter", "update_sat_list_model_sort", "side_store",
"pos_adjustment", "pos_adjustment2"))
builder.connect_signals(handlers)
self._dialog = builder.get_object("satellites_update_dialog")
self._dialog.set_transient_for(transient)
self._main_model = main_model
# self._dialog.get_content_area().set_border_width(0)
self._sat_view = builder.get_object("sat_update_tree_view")
self._source_box = builder.get_object("source_combo_box")
self._sat_update_expander = builder.get_object("sat_update_expander")
self._text_view = builder.get_object("text_view")
self._receive_button = builder.get_object("receive_sat_list_tool_button")
self._sat_update_info_bar = builder.get_object("sat_update_info_bar")
self._info_bar_message_label = builder.get_object("info_bar_message_label")
# Filter
self._filter_info_bar = builder.get_object("sat_update_filter_info_bar")
self._from_pos_button = builder.get_object("from_pos_button")
self._to_pos_button = builder.get_object("to_pos_button")
self._filter_from_combo_box = builder.get_object("filter_from_combo_box")
self._filter_to_combo_box = builder.get_object("filter_to_combo_box")
self._filter_model = builder.get_object("update_sat_list_model_filter")
self._filter_model.set_visible_func(self.filter_function)
self._filter_positions = (0, 0)
# Search
self._search_info_bar = builder.get_object("sat_update_search_info_bar")
self._search_provider = SearchProvider((self._sat_view,),
builder.get_object("sat_update_search_down_button"),
builder.get_object("sat_update_search_up_button"))
self._download_task = False
self._parser = None
def run(self):
if self._dialog.run() == Gtk.ResponseType.CANCEL:
self._download_task = False
return
def destroy(self):
self._dialog.destroy()
def on_update_satellites_list(self, item):
if self._download_task:
show_dialog(DialogType.ERROR, self._dialog, "The task is already running!")
return
model = get_base_model(self._sat_view.get_model())
model.clear()
self._download_task = True
src = self._source_box.get_active()
if not self._parser:
self._parser = SatellitesParser()
self.get_sat_list(src, self.append_satellites)
@run_task
def get_sat_list(self, src, callback):
sats = self._parser.get_satellites_list(SatelliteSource.FLYSAT if src == 0 else SatelliteSource.LYNGSAT)
if sats:
callback(sats)
self._download_task = False
@run_idle
def append_satellites(self, sats):
model = get_base_model(self._sat_view.get_model())
for sat in sats:
model.append(sat)
@run_task
def on_receive_satellites_list(self, item):
if self._download_task:
show_dialog(DialogType.ERROR, self._dialog, "The task is already running!")
return
self.receive_satellites()
@run_task
def receive_satellites(self):
self._download_task = True
self._sat_update_expander.set_expanded(True)
self._text_view.get_buffer().set_text("", 0)
model = self._sat_view.get_model()
start = time.time()
with concurrent.futures.ProcessPoolExecutor(max_workers=4) as executor:
text = "Processing: {}\n"
sats = []
appender = self.append_output()
next(appender)
futures = {executor.submit(self._parser.get_satellite, sat[:-1]): sat for sat in [r for r in model if r[4]]}
for future in concurrent.futures.as_completed(futures):
if not self._download_task:
executor.shutdown()
appender.send("\nCanceled\n")
appender.close()
return
data = future.result()
appender.send(text.format(data[0]))
sats.append(data)
appender.send("-" * 75 + "\n")
appender.send("Consumed : {:0.0f}s, {} satellites received.".format(start - time.time(), len(sats)))
appender.close()
# self.show_info_message(message, Gtk.MessageType.INFO)
sats = {s[2]: s for s in sats} # key = position, v = satellite
for row in self._main_model:
pos = row[-1]
if pos in sats:
sat = sats.pop(pos)
itr = row.iter
self.update_satellite(itr, row, sat)
for sat in sats.values():
append_satellite(self._main_model, sat)
self._download_task = False
@run_idle
def update_satellite(self, itr, row, sat):
if self._main_model.iter_has_child(itr):
children = row.iterchildren()
for ch in children:
self._main_model.remove(ch.iter)
for tr in sat[3]:
self._main_model.append(itr, ["Transponder:", *tr, None, None])
def append_output(self):
@run_idle
def append(t):
append_text_to_tview(t, self._text_view)
while True:
text = yield
append(text)
@run_idle
def on_cancel_receive(self, item=None):
self._download_task = False
def on_selected_toggled(self, toggle, path):
s_model = self._sat_view.get_model()
itr = self._filter_model.convert_iter_to_child_iter(s_model.convert_iter_to_child_iter(s_model.get_iter(path)))
self._filter_model.get_model().set_value(itr, 4, not toggle.get_active())
self.update_receive_button_state(self._filter_model)
@run_idle
def update_receive_button_state(self, model):
self._receive_button.set_sensitive((any(r[4] for r in model)))
@run_idle
def show_info_message(self, text, message_type):
self._sat_update_info_bar.set_visible(True)
self._sat_update_info_bar.set_message_type(message_type)
self._info_bar_message_label.set_text(text)
def on_info_bar_close(self, bar=None, resp=None):
self._sat_update_info_bar.set_visible(False)
def on_find_toggled(self, button: Gtk.ToggleToolButton):
self._search_info_bar.set_visible(button.get_active())
def on_filter_toggled(self, button: Gtk.ToggleToolButton):
self._filter_info_bar.set_visible(button.get_active())
@run_idle
def on_filter(self, item):
self._filter_positions = self.get_positions()
self._filter_model.refilter()
def filter_function(self, model, iter, data):
if self._filter_model is None or self._filter_model == "None":
return True
from_pos, to_pos = self._filter_positions
if from_pos == 0 and to_pos == 0:
return True
if from_pos > to_pos:
from_pos, to_pos = to_pos, from_pos
return from_pos <= float(self._parser.get_position(model.get(iter, 1)[0])) <= to_pos
def get_positions(self):
from_pos = round(self._from_pos_button.get_value(), 1) * (-1 if self._filter_from_combo_box.get_active() else 1)
to_pos = round(self._to_pos_button.get_value(), 1) * (-1 if self._filter_to_combo_box.get_active() else 1)
return from_pos, to_pos
def on_search(self, entry):
self._search_provider.search(entry.get_text())
def on_search_down(self, item):
self._search_provider.on_search_down()
def on_search_up(self, item):
self._search_provider.on_search_up()
def on_quit(self):
self._download_task = False
# ***************** Commons *******************#
@run_idle
def append_satellite(model, sat):
""" Common function for append satellite to the model """
name, flags, pos, transponders = sat
parent = model.append(None, [name, *(None,) * 9, flags, pos])
for transponder in transponders:
model.append(parent, ["Transponder:", *transponder, None, None])
if __name__ == "__main__":
pass

View File

@@ -2,22 +2,18 @@
class SearchProvider:
def __init__(self, srv_view, fav_view, bqs_view, services, bouquets, down_button, up_button):
def __init__(self, views, down_button, up_button):
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
self._views = views
self._up_button = up_button
self._down_button = down_button
def search(self, text, ):
def search(self, text):
self._current_index = -1
self._paths.clear()
for view in self._srv_view, self._fav_view:
for view in self._views:
model = view.get_model()
selection = view.get_selection()
selection.unselect_all()

View File

@@ -8,6 +8,7 @@ def show_settings_dialog(transient, options):
class SettingsDialog:
def __init__(self, transient, options):
handlers = {"on_data_dir_field_icon_press": self.on_data_dir_field_icon_press,
"on_picons_dir_field_icon_press": self.on_picons_dir_field_icon_press,
@@ -39,11 +40,14 @@ class SettingsDialog:
self._picons_dir_field = builder.get_object("picons_dir_field")
self._enigma_radio_button = builder.get_object("enigma_radio_button")
self._neutrino_radio_button = builder.get_object("neutrino_radio_button")
self._support_ver5_check_button = builder.get_object("support_ver5_check_button")
self._options = options
self._active_profile = options.get("profile")
self.set_settings()
self._neutrino_radio_button.set_active(Profile(self._active_profile) is Profile.NEUTRINO_MP)
profile = Profile(self._active_profile)
self._neutrino_radio_button.set_active(profile is Profile.NEUTRINO_MP)
self._support_ver5_check_button.set_sensitive(profile is not Profile.NEUTRINO_MP)
def show(self):
response = self._dialog.run()
@@ -61,7 +65,9 @@ class SettingsDialog:
update_entry_data(entry, self._dialog, self._options.get(self._options.get("profile")))
def on_profile_changed(self, item):
self.set_profile(Profile.ENIGMA_2 if self._enigma_radio_button.get_active() else Profile.NEUTRINO_MP)
profile = Profile.ENIGMA_2 if self._enigma_radio_button.get_active() else Profile.NEUTRINO_MP
self.set_profile(profile)
self._support_ver5_check_button.set_sensitive(profile is Profile.ENIGMA_2)
def set_profile(self, profile):
self._active_profile = profile.value
@@ -94,11 +100,13 @@ class SettingsDialog:
self._picons_field.set_text(options.get("picons_path", ""))
self._data_dir_field.set_text(options.get("data_dir_path", ""))
self._picons_dir_field.set_text(options.get("picons_dir_path", ""))
if Profile(self._active_profile) is Profile.ENIGMA_2:
self._support_ver5_check_button.set_active(options.get("v5_support", False))
def apply_settings(self, item=None):
profile = Profile.ENIGMA_2.value if self._enigma_radio_button.get_active() else Profile.NEUTRINO_MP.value
self._active_profile = profile
self._options["profile"] = profile
profile = Profile.ENIGMA_2 if self._enigma_radio_button.get_active() else Profile.NEUTRINO_MP
self._active_profile = profile.value
self._options["profile"] = self._active_profile
options = self._options.get(self._active_profile)
options["host"] = self._host_field.get_text()
options["port"] = self._port_field.get_text()
@@ -114,6 +122,8 @@ class SettingsDialog:
options["picons_path"] = self._picons_field.get_text()
options["data_dir_path"] = self._data_dir_field.get_text()
options["picons_dir_path"] = self._picons_dir_field.get_text()
if profile is Profile.ENIGMA_2:
options["v5_support"] = self._support_ver5_check_button.get_active()
if __name__ == "__main__":

View File

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

View File

@@ -1,5 +1,5 @@
Package: DemonEditor
Version: 0.3.0-Pre-alpha
Version: 0.3.2-Pre-alpha
Section: utils
Priority: optional
Architecture: all

View File

@@ -3,23 +3,26 @@
## 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)
### 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 - 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.
**Ctrl + X, C, V, Up, Down, PageUp, PageDown, Home, End, S, T, E, L, H, Space; Insert, Delete, F2, Enter, P.**
* **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** - 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.
* **P** - enable/disable preview mode for IPTV in the bouquet list.
* **Enter** - start play IPTV or other stream in the bouquet list.
* **Space** - select/deselect.
* **Left/Right** - remove selection.
* **Ctrl + Up, Down, PageUp, PageDown, Home, End** - move selected items in the list.
### 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.
* Multiple selections in lists only with Space key (as in file managers).
* Ability to import IPTV into bouquet (Neutrino WEBTV) from m3u files.
* Ability to download picons and update satellites (transponders) from web.
* Preview (playing) IPTV or other streams directly from the bouquet list(should be installed VLC).
### Minimum requirements:
Python >= 3.5.2 and GTK+ 3 with PyGObject bindings.
#### Note.
@@ -28,6 +31,6 @@ 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)!
#### Terrestrial and cable channels at the moment are not supported!
**Terrestrial and cable channels at the moment are not supported!**

Binary file not shown.

View File

@@ -142,9 +142,12 @@ msgstr "Родительский замок Вкл/Выкл Ctrl + L"
msgid "Picons"
msgstr "Пиконы"
msgid "Picons loader"
msgid "Picons downloader"
msgstr "Загрузчик пиконов"
msgid "Satellites downloader"
msgstr "Загрузчик спутников"
msgid "Preferences"
msgstr "Настройки"
@@ -250,8 +253,8 @@ msgstr "Спутники"
msgid "Satellites.xml file:"
msgstr "Файл satellites.xml:"
msgid "Select"
msgstr ""
msgid "Selected"
msgstr "Выбор"
msgid "Send"
msgstr "Отправить"
@@ -284,6 +287,9 @@ msgstr "Дополнительно:"
msgid "Load providers"
msgstr "Загрузить провайдеров"
msgid "Providers"
msgstr "Провайдеры"
msgid "Receive picons"
msgstr "Загрузить пиконы"
@@ -394,6 +400,21 @@ msgstr "Поток"
msgid "Description"
msgstr "Описание"
msgid "Source:"
msgstr "Источник:"
msgid "Cancel"
msgstr "Отмена"
msgid "Update"
msgstr "Обновить"
msgid "Filter"
msgstr "Фильтр"
msgid "Find"
msgstr "Поиск"
# IPTV dialog
msgid "Stream data"
msgstr "Данные потока"
@@ -468,6 +489,9 @@ msgstr "Ошибка. Проверьте данные!"
msgid "Operation not allowed in this context!"
msgstr "Недопустимая операция в данном контексте!"
msgid "No VLC is found. Check that it is installed!"
msgstr "VLC не найден. Проверьте, что он установлен!"