mirror of
https://github.com/DYefremov/DemonEditor.git
synced 2026-05-08 13:45:41 +02:00
Compare commits
32 Commits
1.0.2-b1-m
...
0.4.7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aa4b31edfc | ||
|
|
3d627b57a4 | ||
|
|
6b1bec500c | ||
|
|
7444db7e21 | ||
|
|
8be92a9c7e | ||
|
|
7554f40c6a | ||
|
|
17ab321e44 | ||
|
|
ac345d4ef3 | ||
|
|
e2a56a316d | ||
|
|
9b79bf2b81 | ||
|
|
ee2a9bda90 | ||
|
|
da0c5fa8a6 | ||
|
|
e202ec6abe | ||
|
|
e87be79f42 | ||
|
|
6372ac474c | ||
|
|
c6b0f70c8e | ||
|
|
6a921ad394 | ||
|
|
4c8743517f | ||
|
|
74ec0fe956 | ||
|
|
041f717a01 | ||
|
|
67dbdb19d7 | ||
|
|
de49179dd2 | ||
|
|
2723d255fe | ||
|
|
4515b2538b | ||
|
|
88e3a22cf0 | ||
|
|
7ac63b81c0 | ||
|
|
234611b686 | ||
|
|
fdb2691430 | ||
|
|
d81700c30c | ||
|
|
e91c4c33a5 | ||
|
|
40bf54e94f | ||
|
|
4a50c36ab4 |
15
README.md
15
README.md
@@ -10,18 +10,19 @@ Focused on the convenience of working in lists from the keyboard. The mouse is a
|
||||
* Backup function.
|
||||
* Extended support of IPTV.
|
||||
* Support of picons.
|
||||
* Downloading of picons and updating of satellites (transponders) from the Internet.
|
||||
* Downloading of picons and updating of satellites (transponders) from the web.
|
||||
* Import to bouquet(Neutrino WEBTV) from m3u.
|
||||
* Export of bouquets with IPTV services in m3u.
|
||||
* Assignment of EPGs from DVB or XML for IPTV services (only Enigma2, experimental).
|
||||
* Preview (playback) of IPTV or other streams directly from the bouquet list (should be installed [VLC](https://www.videolan.org/vlc/)).
|
||||
|
||||
### Keyboard shortcuts:
|
||||
### Keyboard shortcuts:
|
||||
* **Ctrl + X** - only in bouquet list.
|
||||
* **Ctrl + C** - only in services list.
|
||||
Clipboard is **"rubber"**. There is an accumulation before the insertion!
|
||||
* **Ctrl + Insert** - copies the selected channels from the main list to the the bouquet beginning
|
||||
or inserts (creates) a new bouquet.
|
||||
* **Ctrl + BackSpace** - copies the selected channels from the main list to the bouquet end.
|
||||
* **Ctrl + X** - only in bouquet list. **Ctrl + C** - only in services list.
|
||||
Clipboard is **"rubber"**. There is an accumulation before the insertion!
|
||||
* **Ctrl + BackSpace** - copies the selected channels from the main list to the bouquet end.
|
||||
* **Ctrl + E** - edit.
|
||||
* **Ctrl + R, F2** - rename.
|
||||
* **Ctrl + S, T** in Satellites edit tool for create satellite or transponder.
|
||||
@@ -36,6 +37,10 @@ Clipboard is **"rubber"**. There is an accumulation before the insertion!
|
||||
* **Ctrl + O** - (re)load user data from current dir.
|
||||
* **Ctrl + D** - load data from receiver.
|
||||
* **Ctrl + U/B** upload data/bouquets to receiver.
|
||||
* **Ctrl + F** - show/hide search bar.
|
||||
* **Ctrl + Shift + F** - show/hide filter bar.
|
||||
|
||||
For multiple mouse selection (including Drag and Drop), press and hold the **Ctrl** key!
|
||||
|
||||
### Minimum requirements:
|
||||
Python >= 3.5.2 and GTK+ >= 3.16 with PyGObject bindings, python3-requests.
|
||||
|
||||
@@ -23,6 +23,7 @@ _DATA_FILES_LIST = ("lamedb", "lamedb5", "services.xml", "blacklist", "whitelist
|
||||
|
||||
_SAT_XML_FILE = "satellites.xml"
|
||||
_WEBTV_XML_FILE = "webtv.xml"
|
||||
_PICONS_SUF = (".jpg", ".png")
|
||||
|
||||
|
||||
class DownloadType(Enum):
|
||||
@@ -41,9 +42,15 @@ class HttpRequestType(Enum):
|
||||
STREAM = "stream.m3u?ref="
|
||||
STREAM_CURRENT = "streamcurrent.m3u"
|
||||
CURRENT = "getcurrent"
|
||||
PLAY = "mediaplayerplay?file=4097:0:1:0:0:0:0:0:0:0:"
|
||||
TEST = None
|
||||
TOKEN = "session"
|
||||
PLAY = "mediaplayerplay?file="
|
||||
PLAYER_LIST = "mediaplayerlist?path=playlist"
|
||||
PLAYER_PLAY = "mediaplayercmd?command=play"
|
||||
PLAYER_NEXT = "mediaplayercmd?command=next"
|
||||
PLAYER_PREV = "mediaplayercmd?command=previous"
|
||||
PLAYER_STOP = "mediaplayercmd?command=stop"
|
||||
PLAYER_REMOVE = "mediaplayerremove?file="
|
||||
|
||||
|
||||
class TestException(Exception):
|
||||
@@ -83,6 +90,11 @@ def download_data(*, settings, download_type=DownloadType.ALL, callback=print):
|
||||
download_file(ftp, _SAT_XML_FILE, save_path, callback)
|
||||
if download_type in (DownloadType.ALL, DownloadType.WEBTV) and name.endswith(_WEBTV_XML_FILE):
|
||||
download_file(ftp, _WEBTV_XML_FILE, save_path, callback)
|
||||
|
||||
if download_type is DownloadType.PICONS:
|
||||
picons_path = settings.picons_local_path
|
||||
os.makedirs(os.path.dirname(picons_path), exist_ok=True)
|
||||
download_picons(ftp, settings.picons_path, picons_path, callback)
|
||||
# epg.dat
|
||||
if download_type is DownloadType.EPG:
|
||||
stb_path = settings.services_path
|
||||
@@ -216,6 +228,8 @@ def upload_xml(ftp, data_path, xml_path, xml_file, callback):
|
||||
send_file(xml_file, data_path, ftp, callback)
|
||||
|
||||
|
||||
# ***************** Picons *******************#
|
||||
|
||||
def upload_picons(ftp, src, dest, callback):
|
||||
try:
|
||||
ftp.cwd(dest)
|
||||
@@ -223,17 +237,55 @@ def upload_picons(ftp, src, dest, callback):
|
||||
if str(e).startswith("550"):
|
||||
ftp.mkd(dest) # if not exist
|
||||
ftp.cwd(dest)
|
||||
|
||||
delete_picons(ftp, callback)
|
||||
|
||||
for file_name in os.listdir(src):
|
||||
if file_name.endswith(_PICONS_SUF):
|
||||
send_file(file_name, src, ftp, callback)
|
||||
|
||||
|
||||
def download_picons(ftp, src, dest, callback):
|
||||
try:
|
||||
ftp.cwd(src)
|
||||
except error_perm as e:
|
||||
callback(str(e))
|
||||
return
|
||||
|
||||
files = []
|
||||
ftp.dir(files.append)
|
||||
picons_suf = (".jpg", ".png")
|
||||
|
||||
for file in files:
|
||||
name = str(file).strip()
|
||||
if name.endswith(picons_suf):
|
||||
if name.endswith(_PICONS_SUF):
|
||||
name = name.split()[-1]
|
||||
ftp.delete(name)
|
||||
for file_name in os.listdir(src):
|
||||
if file_name.endswith(picons_suf):
|
||||
send_file(file_name, src, ftp, callback)
|
||||
download_file(ftp, name, dest, callback)
|
||||
|
||||
|
||||
def delete_picons(ftp, callback, dest=None):
|
||||
if dest:
|
||||
try:
|
||||
ftp.cwd(dest)
|
||||
except error_perm as e:
|
||||
callback(str(e))
|
||||
return
|
||||
|
||||
files = []
|
||||
ftp.dir(files.append)
|
||||
for file in files:
|
||||
name = str(file).strip()
|
||||
if name.endswith(_PICONS_SUF):
|
||||
name = name.split()[-1]
|
||||
callback("Delete file: {}. Status: {}\n".format(name, ftp.delete(name)))
|
||||
|
||||
|
||||
def remove_picons(*, settings, callback, done_callback=None):
|
||||
with FTP(host=settings.host, user=settings.user, passwd=settings.password) as ftp:
|
||||
ftp.encoding = "utf-8"
|
||||
callback("FTP OK.\n")
|
||||
delete_picons(ftp, callback, settings.picons_path)
|
||||
if done_callback:
|
||||
done_callback()
|
||||
|
||||
|
||||
def download_file(ftp, name, save_path, callback):
|
||||
@@ -298,7 +350,7 @@ class HttpAPI:
|
||||
from concurrent.futures import ThreadPoolExecutor as PoolExecutor
|
||||
self._executor = PoolExecutor(max_workers=self.__MAX_WORKERS)
|
||||
|
||||
def send(self, req_type, ref, callback=print):
|
||||
def send(self, req_type, ref, callback=print, ref_prefix=""):
|
||||
if self._shutdown:
|
||||
return
|
||||
|
||||
@@ -306,8 +358,8 @@ class HttpAPI:
|
||||
|
||||
if req_type is HttpRequestType.ZAP or req_type is HttpRequestType.STREAM:
|
||||
url += urllib.parse.quote(ref)
|
||||
elif req_type is HttpRequestType.PLAY:
|
||||
url += urllib.parse.quote(ref).replace("%3A", "%253A")
|
||||
elif req_type is HttpRequestType.PLAY or req_type is HttpRequestType.PLAYER_REMOVE:
|
||||
url += "{}{}".format(ref_prefix, urllib.parse.quote(ref).replace("%3A", "%253A"))
|
||||
|
||||
future = self._executor.submit(get_response, req_type, url, self._data)
|
||||
future.add_done_callback(lambda f: callback(f.result()))
|
||||
@@ -338,6 +390,9 @@ def get_response(req_type, url, data=None):
|
||||
elif req_type is HttpRequestType.CURRENT:
|
||||
for el in ETree.fromstring(f.read().decode("utf-8")).iter("e2event"):
|
||||
return {el.tag: el.text for el in el.iter()} # return first[current] event from the list
|
||||
elif req_type is HttpRequestType.PLAYER_LIST:
|
||||
return [{el.tag: el.text for el in el.iter()} for el in
|
||||
ETree.fromstring(f.read().decode("utf-8")).iter("e2file")]
|
||||
else:
|
||||
return {el.tag: el.text for el in ETree.fromstring(f.read().decode("utf-8")).iter()}
|
||||
except HTTPError as e:
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
""" Module for parsing bouquets """
|
||||
import re
|
||||
from collections import Counter
|
||||
|
||||
from app.commons import log
|
||||
from app.eparser.ecommons import BqServiceType, BouquetService, Bouquets, Bouquet, BqType
|
||||
|
||||
_TV_ROOT_FILE_NAME = "bouquets.tv"
|
||||
@@ -98,6 +100,8 @@ def parse_bouquets(path, bq_name, bq_type):
|
||||
bouquets = None
|
||||
nm_sep = "#NAME"
|
||||
bq_pattern = re.compile(".*userbouquet\\.+(.*)\\.+[tv|radio].*")
|
||||
b_names = set()
|
||||
real_b_names = Counter()
|
||||
|
||||
for line in lines:
|
||||
if nm_sep in line:
|
||||
@@ -106,8 +110,21 @@ def parse_bouquets(path, bq_name, bq_type):
|
||||
if bouquets and "#SERVICE" in line:
|
||||
name = re.match(bq_pattern, line)
|
||||
if name:
|
||||
b_name, services = get_bouquet(path, name.group(1), bq_type)
|
||||
bouquets[2].append(Bouquet(name=b_name,
|
||||
b_name = name.group(1)
|
||||
if b_name in b_names:
|
||||
raise ValueError("The list of bouquets contains duplicate [{}] names!".format(b_name))
|
||||
else:
|
||||
b_names.add(b_name)
|
||||
|
||||
rb_name, services = get_bouquet(path, b_name, bq_type)
|
||||
if rb_name in real_b_names:
|
||||
log("Bouquet file 'userbouquet.{}.{}' has duplicate name: {}".format(b_name, bq_type, rb_name))
|
||||
real_b_names[rb_name] += 1
|
||||
rb_name = "{} {}".format(rb_name, real_b_names[rb_name])
|
||||
else:
|
||||
real_b_names[rb_name] = 0
|
||||
|
||||
bouquets[2].append(Bouquet(name=rb_name,
|
||||
type=bq_type,
|
||||
services=services,
|
||||
locked=None,
|
||||
|
||||
@@ -7,9 +7,10 @@ from pathlib import Path
|
||||
from pprint import pformat
|
||||
from textwrap import dedent
|
||||
|
||||
CONFIG_PATH = str(Path.home()) + "/.config/demon-editor/"
|
||||
HOME_PATH = str(Path.home())
|
||||
CONFIG_PATH = HOME_PATH + "/.config/demon-editor/"
|
||||
CONFIG_FILE = CONFIG_PATH + "config.json"
|
||||
DATA_PATH = "data/"
|
||||
DATA_PATH = HOME_PATH + "/DemonEditor/data/"
|
||||
|
||||
|
||||
class Defaults(Enum):
|
||||
@@ -99,7 +100,9 @@ class Settings:
|
||||
self._settings = settings
|
||||
self._current_profile = self._settings.get("default_profile", "default")
|
||||
self._profiles = self._settings.get("profiles", {"default": SettingsType.ENIGMA_2.get_default_settings()})
|
||||
self._cp_settings = self._profiles.get(self._current_profile) # Current profile settings
|
||||
self._cp_settings = self._profiles.get(self._current_profile, None) # Current profile settings
|
||||
if not self._cp_settings:
|
||||
raise SettingsException("Error reading settings [current profile].")
|
||||
|
||||
def __str__(self):
|
||||
return dedent(""" Current profile: {}
|
||||
|
||||
@@ -125,7 +125,7 @@ class ProviderParser(HTMLParser):
|
||||
_POSITION_PATTERN = re.compile("at\s\d+\..*(?:E|W)']")
|
||||
_ONID_TID_PATTERN = re.compile("^\d+-\d+.*")
|
||||
_TRANSPONDER_FREQUENCY_PATTERN = re.compile("^\d+ [HVLR]+")
|
||||
_DOMAIN = "https://www.lyngsat.com"
|
||||
_DOMAIN = "http://www.lyngsat.com"
|
||||
_TV_DOMAIN = _DOMAIN + "/tvchannels/"
|
||||
_RADIO_DOMAIN = _DOMAIN + "/radiochannels/"
|
||||
_PKG_DOMAIN = _DOMAIN + "/packages/"
|
||||
|
||||
@@ -99,6 +99,7 @@ class SatellitesParser(HTMLParser):
|
||||
return list(map(get_sat, filter(lambda x: all(x) and len(x) == 5, self._rows)))
|
||||
elif self._source is SatelliteSource.LYNGSAT:
|
||||
extra_pattern = re.compile("^https://www\.lyngsat\.com/[\w-]+\.html")
|
||||
base_url = "https://www.lyngsat.com/"
|
||||
sats = []
|
||||
current_pos = "0"
|
||||
for row in filter(lambda x: len(x) in (5, 7, 8), self._rows):
|
||||
@@ -106,8 +107,8 @@ class SatellitesParser(HTMLParser):
|
||||
if r_len == 7:
|
||||
current_pos = self.parse_position(row[2])
|
||||
name = row[1].rsplit("/")[-1].rstrip(".html").replace("-", " ")
|
||||
sats.append((name, current_pos, row[5], row[1], False)) # coupled [all in one] satellites
|
||||
sats.append((row[4], current_pos, row[5], row[3], False))
|
||||
sats.append((name, current_pos, row[5], base_url + row[1], False)) # [all in one] satellites
|
||||
sats.append((row[4], current_pos, row[5], base_url + row[3], False))
|
||||
if r_len == 8: # for a very limited number of satellites
|
||||
data = list(filter(None, row))
|
||||
urls = set()
|
||||
@@ -121,9 +122,9 @@ class SatellitesParser(HTMLParser):
|
||||
current_pos = self.parse_position(data[1])
|
||||
for url in urls:
|
||||
name = url.rsplit("/")[-1].rstrip(".html").replace("-", " ")
|
||||
sats.append((name, current_pos, sat_type, url, False))
|
||||
sats.append((name, current_pos, sat_type, base_url + url, False))
|
||||
elif r_len == 5:
|
||||
sats.append((row[2], current_pos, row[3], row[1], False))
|
||||
sats.append((row[2], current_pos, row[3], base_url + row[1], False))
|
||||
return sats
|
||||
|
||||
def get_satellite(self, sat):
|
||||
|
||||
@@ -241,9 +241,6 @@ Author: Dmitriy Yefremov
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="focus_on_click">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="margin_top">1</property>
|
||||
<property name="margin_bottom">1</property>
|
||||
<property name="active">0</property>
|
||||
<property name="has_frame">False</property>
|
||||
<property name="has_entry">True</property>
|
||||
@@ -252,9 +249,6 @@ Author: Dmitriy Yefremov
|
||||
<object class="GtkEntry">
|
||||
<property name="can_focus">True</property>
|
||||
<property name="has_tooltip">True</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="margin_top">1</property>
|
||||
<property name="margin_bottom">1</property>
|
||||
<property name="editable">False</property>
|
||||
<property name="has_frame">False</property>
|
||||
<property name="max_width_chars">9</property>
|
||||
|
||||
@@ -96,7 +96,7 @@ class DownloadDialog:
|
||||
elif self._satellites_radio_button.get_active():
|
||||
download_type = DownloadType.SATELLITES
|
||||
elif self._webtv_radio_button.get_active():
|
||||
download_type = DownloadType.WEB_TV
|
||||
download_type = DownloadType.WEBTV
|
||||
return download_type
|
||||
|
||||
def destroy(self):
|
||||
@@ -140,6 +140,7 @@ class DownloadDialog:
|
||||
if active in self._settings.profiles:
|
||||
self._settings.current_profile = active
|
||||
self._profile_combo_box.set_active_id(active)
|
||||
self._s_type = self._settings.setting_type
|
||||
self.init_ui_settings()
|
||||
|
||||
def on_info_bar_close(self, bar=None, resp=None):
|
||||
|
||||
@@ -1,23 +1,21 @@
|
||||
import concurrent.futures
|
||||
import glob
|
||||
import os
|
||||
import re
|
||||
import urllib
|
||||
from functools import lru_cache
|
||||
from urllib.error import HTTPError
|
||||
from urllib.parse import urlparse
|
||||
from urllib.request import Request, urlopen
|
||||
|
||||
from gi.repository import GLib
|
||||
|
||||
from app.commons import run_idle, run_task, log
|
||||
from app.commons import run_idle, run_task
|
||||
from app.eparser.ecommons import BqServiceType, Service
|
||||
from app.eparser.iptv import NEUTRINO_FAV_ID_FORMAT, StreamType, ENIGMA2_FAV_ID_FORMAT, get_fav_id, MARKER_FORMAT
|
||||
from app.settings import SettingsType
|
||||
from app.tools.yt import YouTube, PlayListParser
|
||||
from .dialogs import Action, show_dialog, DialogType, get_dialogs_string, get_message
|
||||
from .main_helper import get_base_model, get_iptv_url, on_popup_menu
|
||||
from .uicommons import Gtk, Gdk, TEXT_DOMAIN, UI_RESOURCES_PATH, IPTV_ICON, Column, IS_GNOME_SESSION, KeyboardKey
|
||||
from .uicommons import Gtk, Gdk, TEXT_DOMAIN, UI_RESOURCES_PATH, IPTV_ICON, Column, IS_GNOME_SESSION, KeyboardKey, \
|
||||
get_yt_icon
|
||||
|
||||
_DIGIT_ENTRY_NAME = "digit-entry"
|
||||
_ENIGMA2_REFERENCE = "{}:0:{}:{:X}:{:X}:{:X}:{:X}:0:0:0"
|
||||
@@ -43,22 +41,6 @@ def get_stream_type(box):
|
||||
return StreamType.NONE_REC_2.value
|
||||
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def get_yt_icon(icon_name, size=24):
|
||||
""" Getting YouTube icon. If the icon is not found in the icon themes, the "Info" icon is returned by default! """
|
||||
default_theme = Gtk.IconTheme.get_default()
|
||||
if default_theme.has_icon(icon_name):
|
||||
return default_theme.load_icon(icon_name, size, 0)
|
||||
|
||||
theme = Gtk.IconTheme.new()
|
||||
for theme_name in map(os.path.basename, filter(os.path.isdir, glob.glob("/usr/share/icons/*"))):
|
||||
theme.set_custom_theme(theme_name)
|
||||
if theme.has_icon(icon_name):
|
||||
return theme.load_icon(icon_name, size, 0)
|
||||
|
||||
return default_theme.load_icon("info", size, 0)
|
||||
|
||||
|
||||
class IptvDialog:
|
||||
|
||||
def __init__(self, transient, view, services, bouquet, profile=SettingsType.ENIGMA_2, action=Action.ADD):
|
||||
|
||||
Binary file not shown.
BIN
app/ui/lang/pl/LC_MESSAGES/demon-editor.mo
Normal file
BIN
app/ui/lang/pl/LC_MESSAGES/demon-editor.mo
Normal file
Binary file not shown.
Binary file not shown.
@@ -77,9 +77,6 @@ class Application(Gtk.Application):
|
||||
"on_about_app": self.on_about_app,
|
||||
"on_settings": self.on_settings,
|
||||
"on_profile_changed": self.on_profile_changed,
|
||||
"on_download": self.on_download,
|
||||
"on_data_open": self.on_data_open,
|
||||
"on_data_save": self.on_data_save,
|
||||
"on_new_configuration": self.on_new_configuration,
|
||||
"on_tree_view_key_press": self.on_tree_view_key_press,
|
||||
"on_tree_view_key_release": self.on_tree_view_key_release,
|
||||
@@ -93,13 +90,11 @@ class Application(Gtk.Application):
|
||||
"on_bouquets_copy": self.on_bouquets_copy,
|
||||
"on_fav_paste": self.on_fav_paste,
|
||||
"on_bouquets_paste": self.on_bouquets_paste,
|
||||
"on_edit": self.on_rename,
|
||||
"on_rename_for_bouquet": self.on_rename_for_bouquet,
|
||||
"on_set_default_name_for_bouquet": self.on_set_default_name_for_bouquet,
|
||||
"on_service_edit": self.on_service_edit,
|
||||
"on_services_add_new": self.on_services_add_new,
|
||||
"on_delete": self.on_delete,
|
||||
"on_tool_edit": self.on_header_edit,
|
||||
"on_edit": self.on_edit,
|
||||
"on_to_fav_copy": self.on_to_fav_copy,
|
||||
"on_to_fav_end_copy": self.on_to_fav_end_copy,
|
||||
"on_view_drag_begin": self.on_view_drag_begin,
|
||||
@@ -109,8 +104,6 @@ class Application(Gtk.Application):
|
||||
"on_view_press": self.on_view_press,
|
||||
"on_view_popup_menu": self.on_view_popup_menu,
|
||||
"on_view_focus": self.on_view_focus,
|
||||
"on_hide": self.on_hide,
|
||||
"on_locked": self.on_locked,
|
||||
"on_model_changed": self.on_model_changed,
|
||||
"on_import_yt_list": self.on_import_yt_list,
|
||||
"on_import_m3u": self.on_import_m3u,
|
||||
@@ -127,8 +120,6 @@ class Application(Gtk.Application):
|
||||
"on_remove_picon": self.on_remove_picon,
|
||||
"on_reference_picon": self.on_reference_picon,
|
||||
"on_remove_unused_picons": self.on_remove_unused_picons,
|
||||
"on_filter_toggled": self.on_filter_toggled,
|
||||
"on_search_toggled": self.on_search_toggled,
|
||||
"on_search_down": self.on_search_down,
|
||||
"on_search_up": self.on_search_up,
|
||||
"on_search": self.on_search,
|
||||
@@ -150,7 +141,6 @@ class Application(Gtk.Application):
|
||||
"on_main_window_state": self.on_main_window_state,
|
||||
"on_remove_all_unavailable": self.on_remove_all_unavailable,
|
||||
"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,
|
||||
"on_create_bouquet_for_each_satellite": self.on_create_bouquet_for_each_satellite,
|
||||
"on_create_bouquet_for_current_package": self.on_create_bouquet_for_current_package,
|
||||
@@ -212,12 +202,13 @@ class Application(Gtk.Application):
|
||||
self._app_info_box = builder.get_object("app_info_box")
|
||||
self._app_info_box.bind_property("visible", self._status_bar_box, "visible", 4)
|
||||
self._app_info_box.bind_property("visible", builder.get_object("main_paned"), "visible", 4)
|
||||
self._app_info_box.bind_property("visible", builder.get_object("right_header_box"), "sensitive", 4)
|
||||
self._app_info_box.bind_property("visible", builder.get_object("left_header_box"), "sensitive", 4)
|
||||
self._app_info_box.bind_property("visible", builder.get_object("right_header_box"), "visible", 4)
|
||||
self._app_info_box.bind_property("visible", builder.get_object("left_header_box"), "visible", 4)
|
||||
# Status bar
|
||||
self._profile_combo_box = builder.get_object("profile_combo_box")
|
||||
self._receiver_info_box = builder.get_object("receiver_info_box")
|
||||
self._receiver_info_label = builder.get_object("receiver_info_label")
|
||||
self._current_ip_label = builder.get_object("current_ip_label")
|
||||
self._signal_box = builder.get_object("signal_box")
|
||||
self._service_name_label = builder.get_object("service_name_label")
|
||||
self._service_epg_label = builder.get_object("service_epg_label")
|
||||
@@ -230,7 +221,8 @@ class Application(Gtk.Application):
|
||||
self._radio_count_label = builder.get_object("radio_count_label")
|
||||
self._data_count_label = builder.get_object("data_count_label")
|
||||
self._save_header_button = builder.get_object("save_header_button")
|
||||
self._save_header_button.bind_property("sensitive", builder.get_object("save_menu_button"), "sensitive")
|
||||
self._app_info_box.bind_property("visible", self._save_header_button, "visible", 4)
|
||||
self._save_header_button.bind_property("visible", builder.get_object("save_menu_button"), "visible")
|
||||
self._signal_level_bar.bind_property("visible", builder.get_object("play_current_service_button"), "visible")
|
||||
self._receiver_info_box.bind_property("visible", self._http_status_image, "visible", 4)
|
||||
self._receiver_info_box.bind_property("visible", builder.get_object("signal_box"), "visible")
|
||||
@@ -267,9 +259,9 @@ class Application(Gtk.Application):
|
||||
self._player_box.bind_property("visible", builder.get_object("left_header_box"), "visible", 4)
|
||||
self._player_box.bind_property("visible", builder.get_object("right_header_box"), "visible", 4)
|
||||
self._player_box.bind_property("visible", builder.get_object("main_popover_menu_box"), "visible", 4)
|
||||
self._player_box.bind_property("visible", builder.get_object("download_header_button"), "visible", 4)
|
||||
self._player_box.bind_property("visible", builder.get_object("main_header_box"), "visible", 4)
|
||||
self._player_box.bind_property("visible", builder.get_object("left_header_separator"), "visible", 4)
|
||||
self._player_box.bind_property("visible", self._profile_combo_box, "sensitive", 4)
|
||||
self._player_box.bind_property("visible", self._profile_combo_box, "visible", 4)
|
||||
self._fav_view.bind_property("sensitive", self._player_prev_button, "sensitive")
|
||||
self._fav_view.bind_property("sensitive", self._player_next_button, "sensitive")
|
||||
# Enabling events for the drawing area
|
||||
@@ -277,6 +269,7 @@ class Application(Gtk.Application):
|
||||
self._player_frame = builder.get_object("player_frame")
|
||||
# Search
|
||||
self._search_bar = builder.get_object("search_bar")
|
||||
self._search_entry = builder.get_object("search_entry")
|
||||
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"))
|
||||
@@ -292,6 +285,10 @@ class Application(Gtk.Application):
|
||||
|
||||
def do_startup(self):
|
||||
Gtk.Application.do_startup(self)
|
||||
|
||||
self.init_keys()
|
||||
self.set_accels()
|
||||
|
||||
self.init_drag_and_drop()
|
||||
self.init_colors()
|
||||
if self._settings.load_last_config:
|
||||
@@ -304,6 +301,50 @@ class Application(Gtk.Application):
|
||||
gen = self.init_http_api()
|
||||
GLib.idle_add(lambda: next(gen, False), priority=GLib.PRIORITY_LOW)
|
||||
|
||||
def init_keys(self):
|
||||
def set_action(n, fun, enabled=True):
|
||||
ac = Gio.SimpleAction.new(n, None)
|
||||
ac.connect("activate", fun)
|
||||
ac.set_enabled(enabled)
|
||||
self.add_action(ac)
|
||||
return ac
|
||||
|
||||
set_action("on_close_app", self.on_close_app)
|
||||
set_action("on_data_save", self.on_data_save)
|
||||
set_action("on_download", self.on_download)
|
||||
set_action("on_data_open", self.on_data_open)
|
||||
# Search, Filter
|
||||
search_action = Gio.SimpleAction.new_stateful("search", None, GLib.Variant.new_boolean(False))
|
||||
search_action.connect("change-state", self.on_search_toggled)
|
||||
self._main_window.add_action(search_action) # For "win.*" actions!
|
||||
filter_action = Gio.SimpleAction.new_stateful("filter", None, GLib.Variant.new_boolean(False))
|
||||
filter_action.connect("change-state", self.on_filter_toggled)
|
||||
self._main_window.add_action(filter_action)
|
||||
# Lock, Hide
|
||||
set_action("on_hide", self.on_hide)
|
||||
set_action("on_locked", self.on_locked)
|
||||
# Open and download/upload data
|
||||
set_action("open_data", lambda a, v: self.open_data())
|
||||
set_action("on_download_data", self.on_download_data)
|
||||
set_action("upload_all", lambda a, v: self.on_upload_data(DownloadType.ALL))
|
||||
set_action("upload_bouquets", lambda a, v: self.on_upload_data(DownloadType.BOUQUETS))
|
||||
# Edit
|
||||
set_action("on_edit", self.on_edit)
|
||||
|
||||
def set_accels(self):
|
||||
""" Setting accelerators for the actions. """
|
||||
self.set_accels_for_action("app.on_data_save", ["<primary>s"])
|
||||
self.set_accels_for_action("app.on_download_data", ["<primary>d"])
|
||||
self.set_accels_for_action("app.upload_all", ["<primary>u"])
|
||||
self.set_accels_for_action("app.upload_bouquets", ["<primary>b"])
|
||||
self.set_accels_for_action("app.open_data", ["<primary>o"])
|
||||
self.set_accels_for_action("app.on_hide", ["<primary>h"])
|
||||
self.set_accels_for_action("app.on_locked", ["<primary>l"])
|
||||
self.set_accels_for_action("app.on_close_app", ["<primary>q"])
|
||||
self.set_accels_for_action("app.on_edit", ["<primary>e"])
|
||||
self.set_accels_for_action("win.search", ["<primary>f"])
|
||||
self.set_accels_for_action("win.filter", ["<shift><primary>f"])
|
||||
|
||||
def do_activate(self):
|
||||
self._main_window.set_application(self)
|
||||
self._main_window.set_wmclass("DemonEditor", "DemonEditor")
|
||||
@@ -336,7 +377,7 @@ class Application(Gtk.Application):
|
||||
|
||||
def init_profiles(self, profile=None):
|
||||
self.update_profiles()
|
||||
self._profile_combo_box.set_active_id(profile if profile else self._settings.default_profile)
|
||||
self._profile_combo_box.set_active_id(profile if profile else self._settings.current_profile)
|
||||
if profile:
|
||||
self.set_profile(profile)
|
||||
|
||||
@@ -591,6 +632,8 @@ class Application(Gtk.Application):
|
||||
continue
|
||||
|
||||
self._fav_model.clear()
|
||||
b_row = self._bouquets_model[itr][:]
|
||||
self._bouquets.pop("{}:{}".format(b_row[Column.BQ_NAME], b_row[Column.BQ_TYPE]), None)
|
||||
self._bouquets_model.remove(itr)
|
||||
|
||||
# ***************** ####### *********************#
|
||||
@@ -622,6 +665,16 @@ class Application(Gtk.Application):
|
||||
|
||||
bq = response, None, None, bq_type
|
||||
key = "{}:{}".format(response, bq_type)
|
||||
|
||||
while key in self._bouquets:
|
||||
self.show_error_dialog(get_message("A bouquet with that name exists!"))
|
||||
response = show_dialog(DialogType.INPUT, self._main_window, bq_name)
|
||||
if response == Gtk.ResponseType.CANCEL:
|
||||
return
|
||||
|
||||
key = "{}:{}".format(response, bq_type)
|
||||
bq = response, None, None, bq_type
|
||||
|
||||
self._current_bq_name = response
|
||||
|
||||
if model.iter_n_children(itr): # parent
|
||||
@@ -633,7 +686,7 @@ class Application(Gtk.Application):
|
||||
scroll_to(model.get_path(it), view, paths)
|
||||
self._bouquets[key] = []
|
||||
|
||||
def on_header_edit(self, item):
|
||||
def on_edit(self, *args):
|
||||
""" Edit header bar button """
|
||||
if self._services_view.is_focus():
|
||||
self.on_service_edit(self._services_view)
|
||||
@@ -821,19 +874,18 @@ class Application(Gtk.Application):
|
||||
menu.popup(None, None, None, None, event.button, event.time)
|
||||
return True
|
||||
|
||||
@run_idle
|
||||
def on_satellite_editor_show(self, model):
|
||||
""" Shows satellites editor dialog """
|
||||
show_satellites_dialog(self._main_window, self._settings)
|
||||
|
||||
def on_download(self, item):
|
||||
def on_download(self, action=None, value=None):
|
||||
DownloadDialog(transient=self._main_window,
|
||||
settings=self._settings,
|
||||
open_data_callback=self.open_data,
|
||||
update_settings_callback=self.update_settings).show()
|
||||
|
||||
@run_task
|
||||
def on_download_data(self):
|
||||
def on_download_data(self, *args):
|
||||
try:
|
||||
download_data(settings=self._settings,
|
||||
download_type=DownloadType.ALL,
|
||||
@@ -865,7 +917,7 @@ class Application(Gtk.Application):
|
||||
except Exception as e:
|
||||
self.show_error_dialog(str(e))
|
||||
|
||||
def on_data_open(self, model):
|
||||
def on_data_open(self, action=None, value=None):
|
||||
response = show_dialog(DialogType.CHOOSER, self._main_window, settings=self._settings)
|
||||
if response in (Gtk.ResponseType.CANCEL, Gtk.ResponseType.DELETE_EVENT):
|
||||
return
|
||||
@@ -885,6 +937,10 @@ class Application(Gtk.Application):
|
||||
yield from self.clear_current_data()
|
||||
|
||||
try:
|
||||
current_profile = self._profile_combo_box.get_active_text()
|
||||
if current_profile != self._settings.current_profile:
|
||||
self.init_profiles(self._settings.current_profile)
|
||||
|
||||
prf = self._s_type
|
||||
black_list = get_blacklist(data_path)
|
||||
bouquets = get_bouquets(data_path, prf)
|
||||
@@ -913,6 +969,8 @@ class Application(Gtk.Application):
|
||||
if callback:
|
||||
callback()
|
||||
yield True
|
||||
self.on_view_focus(self._services_view)
|
||||
yield True
|
||||
|
||||
def append_data(self, bouquets, services):
|
||||
if self._app_info_box.get_visible():
|
||||
@@ -1035,6 +1093,9 @@ class Application(Gtk.Application):
|
||||
yield True
|
||||
|
||||
def on_data_save(self, *args):
|
||||
if self._app_info_box.get_visible():
|
||||
return
|
||||
|
||||
if len(self._bouquets_model) == 0:
|
||||
self.show_error_dialog("No data to save!")
|
||||
return
|
||||
@@ -1228,21 +1289,26 @@ class Application(Gtk.Application):
|
||||
yield from gen
|
||||
|
||||
def on_profile_changed(self, entry):
|
||||
if self._app_info_box.get_visible():
|
||||
self.update_profile_label()
|
||||
active = self._profile_combo_box.get_active_text()
|
||||
if not active:
|
||||
return
|
||||
|
||||
active = self._profile_combo_box.get_active_text()
|
||||
changed = self._settings.current_profile != active
|
||||
|
||||
if active in self._settings.profiles:
|
||||
self.set_profile(active)
|
||||
|
||||
if self._app_info_box.get_visible():
|
||||
return
|
||||
|
||||
gen = self.init_http_api()
|
||||
GLib.idle_add(lambda: next(gen, False), priority=GLib.PRIORITY_LOW)
|
||||
self.open_data()
|
||||
if changed:
|
||||
self.open_data()
|
||||
|
||||
def set_profile(self, active):
|
||||
self._settings.current_profile = active
|
||||
self._s_type = self._settings.setting_type
|
||||
self._profile_combo_box.set_tooltip_text(self._profile_combo_box.get_tooltip_text() + self._settings.host)
|
||||
self.update_profile_label()
|
||||
|
||||
def update_profiles(self):
|
||||
@@ -1257,14 +1323,13 @@ class Application(Gtk.Application):
|
||||
return
|
||||
|
||||
key = KeyboardKey(key_code)
|
||||
if key is KeyboardKey.F:
|
||||
return True
|
||||
|
||||
ctrl = event.state & Gdk.ModifierType.CONTROL_MASK
|
||||
model_name, model = get_model_data(view)
|
||||
|
||||
if ctrl and key is KeyboardKey.O:
|
||||
self.open_data()
|
||||
elif ctrl and key is KeyboardKey.Q:
|
||||
self.quit()
|
||||
elif ctrl and key in MOVE_KEYS:
|
||||
if ctrl and key in MOVE_KEYS:
|
||||
self.move_items(key)
|
||||
elif ctrl and key is KeyboardKey.C:
|
||||
if model_name == self._SERVICE_LIST_NAME:
|
||||
@@ -1296,13 +1361,7 @@ class Application(Gtk.Application):
|
||||
ctrl = event.state & Gdk.ModifierType.CONTROL_MASK
|
||||
model_name, model = get_model_data(view)
|
||||
|
||||
if ctrl and key is KeyboardKey.D:
|
||||
self.on_download_data()
|
||||
elif ctrl and key is KeyboardKey.U:
|
||||
self.on_upload_data(DownloadType.ALL)
|
||||
elif ctrl and key is KeyboardKey.B:
|
||||
self.on_upload_data(DownloadType.BOUQUETS)
|
||||
elif ctrl and key is KeyboardKey.INSERT:
|
||||
if ctrl and key is KeyboardKey.INSERT:
|
||||
# Move items from app to fav list
|
||||
if model_name == self._SERVICE_LIST_NAME:
|
||||
self.on_to_fav_copy(view)
|
||||
@@ -1310,17 +1369,8 @@ class Application(Gtk.Application):
|
||||
self.on_new_bouquet(view)
|
||||
elif ctrl and key is KeyboardKey.BACK_SPACE and model_name == self._SERVICE_LIST_NAME:
|
||||
self.on_to_fav_end_copy(view)
|
||||
elif ctrl and key is KeyboardKey.L:
|
||||
self.on_locked(None)
|
||||
elif ctrl and key is KeyboardKey.H:
|
||||
self.on_hide(None)
|
||||
elif ctrl and key is KeyboardKey.R or key is KeyboardKey.F2:
|
||||
self.on_rename(view)
|
||||
elif ctrl and key is KeyboardKey.E:
|
||||
if model_name == self._BOUQUETS_LIST_NAME:
|
||||
self.on_rename(view)
|
||||
return
|
||||
self.on_service_edit(view)
|
||||
elif key is KeyboardKey.LEFT or key is KeyboardKey.RIGHT:
|
||||
view.do_unselect_all(view)
|
||||
elif ctrl and model_name == self._FAV_LIST_NAME:
|
||||
@@ -1376,10 +1426,10 @@ class Application(Gtk.Application):
|
||||
for elem in self._FAV_ENIGMA_ELEMENTS:
|
||||
self._tool_elements[elem].set_sensitive(False)
|
||||
|
||||
def on_hide(self, item):
|
||||
def on_hide(self, action=None, value=None):
|
||||
self.set_service_flags(Flag.HIDE)
|
||||
|
||||
def on_locked(self, item):
|
||||
def on_locked(self, action=None, value=None):
|
||||
self.set_service_flags(Flag.LOCK)
|
||||
|
||||
def set_service_flags(self, flag):
|
||||
@@ -1900,13 +1950,17 @@ class Application(Gtk.Application):
|
||||
|
||||
# ***************** Filter and search *********************#
|
||||
|
||||
def on_filter_toggled(self, toggle_button: Gtk.ToggleToolButton):
|
||||
active = toggle_button.get_active()
|
||||
if active:
|
||||
self.update_filter_sat_positions()
|
||||
def on_filter_toggled(self, action, value):
|
||||
if self._app_info_box.get_visible():
|
||||
return True
|
||||
|
||||
self._filter_bar.set_search_mode(active)
|
||||
self._filter_bar.set_visible(active)
|
||||
action.set_state(value)
|
||||
if value:
|
||||
self.update_filter_sat_positions()
|
||||
self._filter_entry.grab_focus()
|
||||
|
||||
self._filter_bar.set_search_mode(value)
|
||||
self._filter_bar.set_visible(value)
|
||||
|
||||
def init_sat_positions(self):
|
||||
self._sat_positions.clear()
|
||||
@@ -1986,8 +2040,14 @@ class Application(Gtk.Application):
|
||||
|
||||
return txt and free
|
||||
|
||||
def on_search_toggled(self, toggle_button: Gtk.ToggleToolButton):
|
||||
self._search_bar.set_search_mode(toggle_button.get_active())
|
||||
def on_search_toggled(self, action, value):
|
||||
if self._app_info_box.get_visible():
|
||||
return True
|
||||
|
||||
action.set_state(value)
|
||||
self._search_bar.set_search_mode(value)
|
||||
if value:
|
||||
self._search_entry.grab_focus()
|
||||
|
||||
def on_search_down(self, item):
|
||||
self._search_provider.on_search_down()
|
||||
@@ -2053,8 +2113,13 @@ class Application(Gtk.Application):
|
||||
if response == Gtk.ResponseType.CANCEL:
|
||||
return
|
||||
|
||||
bq = "{}:{}".format(response, bq_type)
|
||||
if bq in self._bouquets:
|
||||
self.show_error_dialog(get_message("A bouquet with that name exists!"))
|
||||
return
|
||||
|
||||
model.set_value(itr, 0, response)
|
||||
self._bouquets["{}:{}".format(response, bq_type)] = self._bouquets.pop("{}:{}".format(bq_name, bq_type))
|
||||
self._bouquets[bq] = self._bouquets.pop("{}:{}".format(bq_name, bq_type))
|
||||
self._current_bq_name = response
|
||||
self._bq_name_label.set_text(self._current_bq_name)
|
||||
self._bq_selected = "{}:{}".format(response, bq_type)
|
||||
@@ -2130,7 +2195,6 @@ class Application(Gtk.Application):
|
||||
|
||||
# ***************** Picons *********************#
|
||||
|
||||
@run_idle
|
||||
def on_picons_loader_show(self, item):
|
||||
ids = {}
|
||||
if self._s_type is SettingsType.ENIGMA_2:
|
||||
@@ -2202,9 +2266,10 @@ class Application(Gtk.Application):
|
||||
|
||||
@run_idle
|
||||
def update_profile_label(self):
|
||||
label, sep, ip = self._profile_combo_box.get_tooltip_text().partition(":")
|
||||
label, sep, ip = self._current_ip_label.get_text().partition(":")
|
||||
self._current_ip_label.set_text("{}: {}".format(label, self._settings.host))
|
||||
|
||||
profile_name = self._profile_combo_box.get_active_text()
|
||||
self._profile_combo_box.set_tooltip_text("{}: {}".format(label, self._settings.host))
|
||||
msg = get_message("Profile:")
|
||||
|
||||
if self._s_type is SettingsType.ENIGMA_2:
|
||||
|
||||
@@ -264,7 +264,7 @@ Author: Dmitriy Yefremov
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="activate" handler="on_bouquets_edit" object="bouquets_tree_view" swapped="no"/>
|
||||
<signal name="activate" handler="on_edit" swapped="no"/>
|
||||
<accelerator key="e" signal="activate" modifiers="GDK_CONTROL_MASK"/>
|
||||
</object>
|
||||
</child>
|
||||
@@ -444,8 +444,8 @@ Author: Dmitriy Yefremov
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="action_name">app.on_data_open</property>
|
||||
<property name="text" translatable="yes">Open</property>
|
||||
<signal name="clicked" handler="on_data_open" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
@@ -455,11 +455,10 @@ Author: Dmitriy Yefremov
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkModelButton" id="save_menu_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="action_name">app.on_data_save</property>
|
||||
<property name="text" translatable="yes">Save</property>
|
||||
<signal name="clicked" handler="on_data_save" swapped="no"/>
|
||||
<accelerator key="s" signal="clicked" modifiers="GDK_CONTROL_MASK"/>
|
||||
</object>
|
||||
<packing>
|
||||
@@ -485,8 +484,8 @@ Author: Dmitriy Yefremov
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="action_name">app.on_download</property>
|
||||
<property name="text" translatable="yes">FTP-transfer</property>
|
||||
<signal name="clicked" handler="on_download" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
@@ -800,7 +799,7 @@ Author: Dmitriy Yefremov
|
||||
<property name="can_focus">False</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"/>
|
||||
<signal name="activate" handler="on_edit" swapped="no"/>
|
||||
<accelerator key="e" signal="activate" modifiers="GDK_CONTROL_MASK"/>
|
||||
</object>
|
||||
</child>
|
||||
@@ -976,7 +975,7 @@ Author: Dmitriy Yefremov
|
||||
<property name="can_focus">False</property>
|
||||
<property name="title" translatable="yes">DemonEditor</property>
|
||||
<property name="subtitle" translatable="yes">Profile:</property>
|
||||
<property name="spacing">1</property>
|
||||
<property name="spacing">0</property>
|
||||
<property name="show_close_button">True</property>
|
||||
<child>
|
||||
<object class="GtkMenuButton" id="file_header_button">
|
||||
@@ -1005,37 +1004,64 @@ Author: Dmitriy Yefremov
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="download_header_button">
|
||||
<object class="GtkComboBoxText" id="profile_combo_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">FTP-transfer</property>
|
||||
<signal name="clicked" handler="on_download" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="download_header_button_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">network-wired</property>
|
||||
</object>
|
||||
</child>
|
||||
<property name="focus_on_click">False</property>
|
||||
<property name="margin_left">1</property>
|
||||
<property name="margin_right">1</property>
|
||||
<property name="active">0</property>
|
||||
<signal name="changed" handler="on_profile_changed" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="left_header_box">
|
||||
<object class="GtkBox" id="main_header_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">1</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="save_header_button">
|
||||
<object class="GtkSeparator" id="main_header_box_separator">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">1</property>
|
||||
<property name="margin_right">1</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="download_header_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">FTP-transfer</property>
|
||||
<property name="action_name">app.on_download</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="download_header_button_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">network-wired</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="save_header_button">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Save</property>
|
||||
<signal name="clicked" handler="on_data_save" swapped="no"/>
|
||||
<property name="action_name">app.on_data_save</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="save_header_button_image">
|
||||
<property name="visible">True</property>
|
||||
@@ -1051,10 +1077,41 @@ Author: Dmitriy Yefremov
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="backup_tool_header_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Backup</property>
|
||||
<signal name="clicked" handler="on_backup_tool_show" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="backup_tool_header_button_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-revert-to-saved</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="left_header_box">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">1</property>
|
||||
<child>
|
||||
<object class="GtkSeparator" id="left_header_box_separator">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">1</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
@@ -1066,10 +1123,11 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="filter_header_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Filter</property>
|
||||
<signal name="toggled" handler="on_filter_toggled" swapped="no"/>
|
||||
<property name="action_name">win.filter</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="filter_header_button_image">
|
||||
<property name="visible">True</property>
|
||||
@@ -1087,10 +1145,11 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="search_header_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Search</property>
|
||||
<signal name="toggled" handler="on_search_toggled" swapped="no"/>
|
||||
<property name="action_name">win.search</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="search_header_button_image">
|
||||
<property name="visible">True</property>
|
||||
@@ -1109,6 +1168,8 @@ Author: Dmitriy Yefremov
|
||||
<object class="GtkSeparator" id="left_header_box_separator_2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">1</property>
|
||||
<property name="margin_right">1</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
@@ -1124,7 +1185,7 @@ Author: Dmitriy Yefremov
|
||||
<property name="can_focus">False</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Parent lock On/Off Ctrl + L</property>
|
||||
<signal name="clicked" handler="on_locked" swapped="no"/>
|
||||
<property name="action_name">app.on_locked</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="locked_tool_button_image">
|
||||
<property name="visible">True</property>
|
||||
@@ -1146,7 +1207,7 @@ Author: Dmitriy Yefremov
|
||||
<property name="can_focus">False</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Hide/Skip On/Off Ctrl + H</property>
|
||||
<signal name="clicked" handler="on_hide" swapped="no"/>
|
||||
<property name="action_name">app.on_hide</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
@@ -1163,13 +1224,11 @@ Author: Dmitriy Yefremov
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">4</property>
|
||||
<property name="position">6</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="right_header_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">1</property>
|
||||
<child>
|
||||
@@ -1214,31 +1273,12 @@ Author: Dmitriy Yefremov
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="backup_tool_header_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Backup</property>
|
||||
<signal name="clicked" handler="on_backup_tool_show" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="backup_tool_header_button_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-revert-to-saved</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparator" id="right_header_box_separator">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">2</property>
|
||||
<property name="margin_right">2</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
@@ -1758,6 +1798,7 @@ Author: Dmitriy Yefremov
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="model">services_model_tree_model_sort</property>
|
||||
<property name="enable_search">False</property>
|
||||
<property name="search_column">3</property>
|
||||
<property name="rubber_banding">True</property>
|
||||
<property name="enable_grid_lines">both</property>
|
||||
@@ -2307,6 +2348,7 @@ Author: Dmitriy Yefremov
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="model">fav_list_store</property>
|
||||
<property name="enable_search">False</property>
|
||||
<property name="search_column">2</property>
|
||||
<property name="rubber_banding">True</property>
|
||||
<property name="enable_grid_lines">both</property>
|
||||
@@ -2798,7 +2840,10 @@ Author: Dmitriy Yefremov
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="status_bar_box">
|
||||
<property name="height_request">28</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_top">1</property>
|
||||
<property name="margin_bottom">1</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="receiver_info_box">
|
||||
<property name="can_focus">False</property>
|
||||
@@ -2841,34 +2886,13 @@ Author: Dmitriy Yefremov
|
||||
</packing>
|
||||
</child>
|
||||
<child type="center">
|
||||
<object class="GtkComboBoxText" id="profile_combo_box">
|
||||
<object class="GtkLabel" id="current_ip_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="focus_on_click">False</property>
|
||||
<property name="tooltip_text" translatable="yes">Current IP:</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="margin_top">1</property>
|
||||
<property name="margin_bottom">1</property>
|
||||
<property name="active">0</property>
|
||||
<property name="has_entry">True</property>
|
||||
<child internal-child="entry">
|
||||
<object class="GtkEntry" id="profile_entry">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="has_tooltip">True</property>
|
||||
<property name="halign">baseline</property>
|
||||
<property name="valign">baseline</property>
|
||||
<property name="margin_top">1</property>
|
||||
<property name="margin_bottom">1</property>
|
||||
<property name="editable">False</property>
|
||||
<property name="has_frame">False</property>
|
||||
<property name="max_width_chars">9</property>
|
||||
<property name="overwrite_mode">True</property>
|
||||
<property name="caps_lock_warning">False</property>
|
||||
<property name="primary_icon_stock">gtk-connect</property>
|
||||
<signal name="changed" handler="on_profile_changed" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<property name="label" translatable="yes">Current IP:</property>
|
||||
<attributes>
|
||||
<attribute name="size" value="8000"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
@@ -2979,9 +3003,6 @@ Author: Dmitriy Yefremov
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<style>
|
||||
<class name="primary-toolbar"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
@@ -3050,7 +3071,7 @@ Author: Dmitriy Yefremov
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="activate" handler="on_service_edit" object="fav_tree_view" swapped="no"/>
|
||||
<signal name="activate" handler="on_edit" swapped="no"/>
|
||||
<accelerator key="e" signal="activate" modifiers="GDK_CONTROL_MASK"/>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
@@ -153,6 +153,17 @@ Author: Dmitriy Yefremov
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparator">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="receive_button">
|
||||
<property name="visible">True</property>
|
||||
@@ -171,17 +182,6 @@ Author: Dmitriy Yefremov
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparator">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
@@ -210,6 +210,59 @@ Author: Dmitriy Yefremov
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparator">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="download_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Download picons from the receiver</property>
|
||||
<signal name="clicked" handler="on_download" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="download_button_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-go-down</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">5</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="remove_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Remove picons from the receiver</property>
|
||||
<signal name="clicked" handler="on_remove" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="remove_button_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-delete</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">6</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">6</property>
|
||||
|
||||
@@ -7,13 +7,13 @@ import tempfile
|
||||
from gi.repository import GLib, GdkPixbuf
|
||||
|
||||
from app.commons import run_idle, run_task
|
||||
from app.connections import upload_data, DownloadType
|
||||
from app.tools.picons import PiconsParser, parse_providers, Provider, convert_to
|
||||
from app.connections import upload_data, DownloadType, download_data, remove_picons
|
||||
from app.settings import SettingsType
|
||||
from app.tools.picons import PiconsParser, parse_providers, Provider, convert_to
|
||||
from app.tools.satellites import SatellitesParser, SatelliteSource
|
||||
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, TEXT_DOMAIN, TV_ICON
|
||||
from .dialogs import show_dialog, DialogType, get_message
|
||||
from .main_helper import update_entry_data, append_text_to_tview, scroll_to, on_popup_menu
|
||||
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, TEXT_DOMAIN, TV_ICON
|
||||
|
||||
|
||||
class PiconsDialog:
|
||||
@@ -32,6 +32,8 @@ class PiconsDialog:
|
||||
"on_cancel": self.on_cancel,
|
||||
"on_close": self.on_close,
|
||||
"on_send": self.on_send,
|
||||
"on_download": self.on_download,
|
||||
"on_remove": self.on_remove,
|
||||
"on_info_bar_close": self.on_info_bar_close,
|
||||
"on_picons_dir_open": self.on_picons_dir_open,
|
||||
"on_selected_toggled": self.on_selected_toggled,
|
||||
@@ -77,9 +79,11 @@ class PiconsDialog:
|
||||
self._resize_220_132_radio_button = builder.get_object("resize_220_132_radio_button")
|
||||
self._resize_100_60_radio_button = builder.get_object("resize_100_60_radio_button")
|
||||
self._satellite_label = builder.get_object("satellite_label")
|
||||
self._header_download_box = builder.get_object("header_download_box")
|
||||
self._satellite_label.bind_property("visible", builder.get_object("loading_data_label"), "visible", 4)
|
||||
self._satellite_label.bind_property("visible", builder.get_object("loading_data_spinner"), "visible", 4)
|
||||
self._cancel_button.bind_property("visible", builder.get_object("header_download_box"), "visible", 4)
|
||||
self._cancel_button.bind_property("visible", self._header_download_box, "visible", 4)
|
||||
self._convert_button.bind_property("visible", self._header_download_box, "visible", 4)
|
||||
# style
|
||||
self._style_provider = Gtk.CssProvider()
|
||||
self._style_provider.load_from_path(UI_RESOURCES_PATH + "style.css")
|
||||
@@ -92,6 +96,10 @@ class PiconsDialog:
|
||||
self._picons_path = self._settings.picons_local_path
|
||||
self._picons_dir_entry.set_text(self._picons_path)
|
||||
|
||||
window_size = self._settings.get("picons_downloader_window_size")
|
||||
if window_size:
|
||||
self._dialog.resize(*window_size)
|
||||
|
||||
if not len(self._picon_ids) and self._s_type is SettingsType.ENIGMA_2:
|
||||
message = get_message("To automatically set the identifiers for picons,\n"
|
||||
"first load the required services list into the main application window.")
|
||||
@@ -135,14 +143,19 @@ class PiconsDialog:
|
||||
self._cancel_button.show()
|
||||
url = self._url_entry.get_text()
|
||||
|
||||
self._current_process = subprocess.Popen(["wget", "-pkP", self._TMP_DIR, url],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
universal_newlines=True)
|
||||
GLib.io_add_watch(self._current_process.stderr, GLib.IO_IN, self.write_to_buffer)
|
||||
model = self._providers_tree_view.get_model()
|
||||
model.clear()
|
||||
self.append_providers(url, model)
|
||||
try:
|
||||
self._current_process = subprocess.Popen(["wget", "-pkP", self._TMP_DIR, url],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
universal_newlines=True)
|
||||
except FileNotFoundError as e:
|
||||
self._cancel_button.hide()
|
||||
self.show_info_message(str(e), Gtk.MessageType.ERROR)
|
||||
else:
|
||||
GLib.io_add_watch(self._current_process.stderr, GLib.IO_IN, self.write_to_buffer)
|
||||
model = self._providers_tree_view.get_model()
|
||||
model.clear()
|
||||
self.append_providers(url, model)
|
||||
|
||||
@run_task
|
||||
def append_providers(self, url, model):
|
||||
@@ -228,7 +241,7 @@ class PiconsDialog:
|
||||
def resize(self, path):
|
||||
self.show_info_message(get_message("Resizing..."), Gtk.MessageType.INFO)
|
||||
command = "mogrify -resize {}! *.png".format(
|
||||
"320x240" if self._resize_220_132_radio_button.get_active() else "100x60").split()
|
||||
"220x132" if self._resize_220_132_radio_button.get_active() else "100x60").split()
|
||||
try:
|
||||
self._current_process = subprocess.Popen(command, universal_newlines=True, cwd=path)
|
||||
self._current_process.wait()
|
||||
@@ -253,9 +266,16 @@ class PiconsDialog:
|
||||
if self.on_cancel():
|
||||
return True
|
||||
|
||||
self.save_window_size(window)
|
||||
self.clean_data()
|
||||
GLib.idle_add(self._dialog.destroy)
|
||||
|
||||
def save_window_size(self, window):
|
||||
t, _ = self._text_view.get_allocated_size()
|
||||
b, _ = self._info_bar.get_allocated_size()
|
||||
size = window.get_size()
|
||||
self._settings.add("picons_downloader_window_size", (size.width, size.height - t.height - b.height))
|
||||
|
||||
@run_task
|
||||
def clean_data(self):
|
||||
path = self._TMP_DIR + "www.lyngsat.com"
|
||||
@@ -267,22 +287,38 @@ class PiconsDialog:
|
||||
return
|
||||
|
||||
self.show_info_message(get_message("Please, wait..."), Gtk.MessageType.INFO)
|
||||
self.upload_picons()
|
||||
self.run_func(lambda: upload_data(settings=self._settings,
|
||||
download_type=DownloadType.PICONS,
|
||||
callback=self.append_output,
|
||||
done_callback=lambda: self.show_info_message(get_message("Done!"),
|
||||
Gtk.MessageType.INFO)))
|
||||
|
||||
@run_task
|
||||
def upload_picons(self):
|
||||
if self.is_task_running():
|
||||
self.show_dialog("The task is already running!", DialogType.ERROR)
|
||||
def on_download(self, item):
|
||||
if show_dialog(DialogType.QUESTION, self._dialog) == Gtk.ResponseType.CANCEL:
|
||||
return
|
||||
|
||||
self.run_func(lambda: download_data(settings=self._settings,
|
||||
download_type=DownloadType.PICONS,
|
||||
callback=self.append_output))
|
||||
|
||||
def on_remove(self, item):
|
||||
if show_dialog(DialogType.QUESTION, self._dialog) == Gtk.ResponseType.CANCEL:
|
||||
return
|
||||
|
||||
self.run_func(lambda: remove_picons(settings=self._settings,
|
||||
callback=self.append_output,
|
||||
done_callback=lambda: self.show_info_message(get_message("Done!"),
|
||||
Gtk.MessageType.INFO)))
|
||||
|
||||
@run_task
|
||||
def run_func(self, func):
|
||||
try:
|
||||
GLib.idle_add(self._expander.set_expanded, True)
|
||||
upload_data(settings=self._settings,
|
||||
download_type=DownloadType.PICONS,
|
||||
callback=self.append_output,
|
||||
done_callback=lambda: self.show_info_message(get_message("Done!"), Gtk.MessageType.INFO))
|
||||
GLib.idle_add(self._header_download_box.set_sensitive, False)
|
||||
func()
|
||||
except OSError as e:
|
||||
self.show_info_message(str(e), Gtk.MessageType.ERROR)
|
||||
GLib.idle_add(self._header_download_box.set_sensitive, True)
|
||||
|
||||
def on_info_bar_close(self, bar=None, resp=None):
|
||||
self._info_bar.set_visible(False)
|
||||
@@ -323,10 +359,7 @@ class PiconsDialog:
|
||||
|
||||
@run_idle
|
||||
def on_notebook_switch_page(self, nb, box, tab_num):
|
||||
self._load_providers_button.set_visible(not tab_num)
|
||||
self._receive_button.set_visible(not tab_num)
|
||||
self._convert_button.set_visible(tab_num)
|
||||
self._send_button.set_visible(not tab_num)
|
||||
|
||||
@run_idle
|
||||
def on_convert(self, item):
|
||||
|
||||
@@ -427,6 +427,7 @@ Author: Dmitriy Yefremov
|
||||
<object class="GtkToolButton" id="profile_set_default_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="tooltip_text" translatable="yes">Set default</property>
|
||||
<property name="halign">end</property>
|
||||
<property name="label" translatable="yes">Set default</property>
|
||||
<property name="use_underline">True</property>
|
||||
@@ -1332,6 +1333,7 @@ Author: Dmitriy Yefremov
|
||||
<item id="de_DE" translatable="yes">Deutsch</item>
|
||||
<item id="es_ES" translatable="yes">Español</item>
|
||||
<item id="nl_NL" translatable="yes">Nederlands</item>
|
||||
<item id="pl_PL" translatable="yes">Polski</item>
|
||||
<item id="pt_PT" translatable="yes">Português</item>
|
||||
<item id="ru_RU" translatable="yes">Русский</item>
|
||||
</items>
|
||||
@@ -1809,7 +1811,7 @@ Author: Dmitriy Yefremov
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="label" translatable="yes">Enable send to receiver (experimental)</property>
|
||||
<property name="label" translatable="yes">Enable direct playback bar (experimental)</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
@@ -1821,7 +1823,7 @@ Author: Dmitriy Yefremov
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Enables direct sending of media links to the receiver</property>
|
||||
<property name="tooltip_text" translatable="yes">Enables direct sending and playback of media links on the receiver</property>
|
||||
<property name="halign">end</property>
|
||||
</object>
|
||||
<packing>
|
||||
|
||||
@@ -118,6 +118,7 @@ class SettingsDialog:
|
||||
self._profile_remove_button = builder.get_object("profile_remove_button")
|
||||
self._apply_profile_button = builder.get_object("apply_profile_button")
|
||||
self._apply_profile_button.bind_property("visible", builder.get_object("header_separator"), "visible")
|
||||
self._apply_profile_button.bind_property("visible", builder.get_object("reset_button"), "visible")
|
||||
# Language
|
||||
self._lang_combo_box = builder.get_object("lang_combo_box")
|
||||
# Settings
|
||||
@@ -145,8 +146,12 @@ class SettingsDialog:
|
||||
|
||||
def init_profiles(self):
|
||||
p_def = self._settings.default_profile
|
||||
for p in self._profiles:
|
||||
self._profile_view.get_model().append((p, DEFAULT_ICON if p == p_def else None))
|
||||
model = self._profile_view.get_model()
|
||||
for ind, p in enumerate(self._profiles):
|
||||
icon = DEFAULT_ICON if p == p_def else None
|
||||
model.append((p, icon))
|
||||
if icon:
|
||||
scroll_to(ind, self._profile_view)
|
||||
self._profile_remove_button.set_sensitive(len(self._profile_view.get_model()) > 1)
|
||||
|
||||
def update_header_bar(self):
|
||||
@@ -170,17 +175,19 @@ class SettingsDialog:
|
||||
update_entry_data(entry, self._dialog, self._settings)
|
||||
|
||||
def on_settings_type_changed(self, item):
|
||||
profile = SettingsType.ENIGMA_2 if self._enigma_radio_button.get_active() else SettingsType.NEUTRINO_MP
|
||||
self._s_type = profile
|
||||
self._settings.setting_type = profile
|
||||
self.on_reset()
|
||||
self.init_ui_elements(profile)
|
||||
s_type = SettingsType.ENIGMA_2 if self._enigma_radio_button.get_active() else SettingsType.NEUTRINO_MP
|
||||
if s_type is not self._s_type:
|
||||
self._settings.setting_type = s_type
|
||||
self._s_type = s_type
|
||||
self.on_reset()
|
||||
self.init_ui_elements(s_type)
|
||||
|
||||
def on_reset(self, item=None):
|
||||
self._settings.reset()
|
||||
self.set_settings()
|
||||
|
||||
def set_settings(self):
|
||||
self._s_type = self._settings.setting_type
|
||||
self._host_field.set_text(self._settings.host)
|
||||
self._port_field.set_text(self._settings.port)
|
||||
self._login_field.set_text(self._settings.user)
|
||||
@@ -218,6 +225,11 @@ class SettingsDialog:
|
||||
self._new_color_button.set_rgba(new_rgb)
|
||||
self._extra_color_button.set_rgba(extra_rgb)
|
||||
|
||||
if self._s_type is SettingsType.ENIGMA_2:
|
||||
self._enigma_radio_button.activate()
|
||||
else:
|
||||
self._neutrino_radio_button.activate()
|
||||
|
||||
def on_apply_profile_settings(self, item):
|
||||
self._s_type = SettingsType.ENIGMA_2 if self._enigma_radio_button.get_active() else SettingsType.NEUTRINO_MP
|
||||
self._settings.setting_type = self._s_type
|
||||
@@ -379,14 +391,19 @@ class SettingsDialog:
|
||||
self._profile_remove_button.set_sensitive(len(model) > 1)
|
||||
|
||||
def on_profile_edited(self, render, path, new_value):
|
||||
p_name = render.get_property("text")
|
||||
row = self._profile_view.get_model()[path]
|
||||
p_name = row[0]
|
||||
if p_name == new_value:
|
||||
return
|
||||
|
||||
if new_value in self._profiles:
|
||||
show_dialog(DialogType.ERROR, self._dialog, "A profile with that name exists!")
|
||||
return
|
||||
|
||||
p_name = self._profiles.pop(p_name, None)
|
||||
if p_name:
|
||||
row = self._profile_view.get_model()[path]
|
||||
row[0] = new_value
|
||||
self._profiles[new_value] = p_name
|
||||
|
||||
if p_name != new_value:
|
||||
self.update_local_paths(new_value)
|
||||
self.on_profile_selected(self._profile_view)
|
||||
|
||||
@@ -415,10 +432,6 @@ class SettingsDialog:
|
||||
if paths:
|
||||
profile = model.get_value(model.get_iter(paths), 0)
|
||||
self._settings.current_profile = profile
|
||||
if self._settings.setting_type is SettingsType.ENIGMA_2:
|
||||
self._enigma_radio_button.activate()
|
||||
else:
|
||||
self._neutrino_radio_button.activate()
|
||||
self.set_settings()
|
||||
|
||||
def on_profile_set_default(self, item):
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018-2019 Dmitriy Yefremov
|
||||
Copyright (c) 2018-2020 Dmitriy Yefremov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -26,20 +26,19 @@ THE SOFTWARE.
|
||||
Author: Dmitriy Yefremov
|
||||
|
||||
-->
|
||||
<interface>
|
||||
<interface domain="demon-editor">
|
||||
<requires lib="gtk+" version="3.16"/>
|
||||
<!-- interface-css-provider-path style.css -->
|
||||
<!-- interface-license-type mit -->
|
||||
<!-- interface-name DemonEditor -->
|
||||
<!-- interface-description Enigma2 channel and satellites list editor for GNU/Linux. -->
|
||||
<!-- interface-copyright 2018-2019 Dmitriy Yefremov -->
|
||||
<!-- interface-copyright 2018-2020 Dmitriy Yefremov -->
|
||||
<!-- interface-authors Dmitriy Yefremov -->
|
||||
<object class="GtkWindow" id="main_window">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="resizable">False</property>
|
||||
<property name="window_position">mouse</property>
|
||||
<property name="destroy_with_parent">True</property>
|
||||
<property name="type_hint">splashscreen</property>
|
||||
<property name="skip_taskbar_hint">True</property>
|
||||
<property name="skip_pager_hint">True</property>
|
||||
<property name="decorated">False</property>
|
||||
@@ -49,20 +48,29 @@ Author: Dmitriy Yefremov
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="main_box">
|
||||
<object class="GtkBox" id="tool_bar">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">1</property>
|
||||
<child>
|
||||
<object class="GtkEntry" id="url_entry">
|
||||
<object class="GtkButton" id="previous_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="margin_left">2</property>
|
||||
<property name="margin_right">2</property>
|
||||
<property name="margin_top">2</property>
|
||||
<property name="margin_bottom">2</property>
|
||||
<property name="primary_icon_stock">gtk-dnd-multiple</property>
|
||||
<signal name="drag-data-received" handler="on_drag_data_received" swapped="no"/>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Previous stream in the list</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="margin_left">1</property>
|
||||
<property name="margin_top">1</property>
|
||||
<property name="margin_bottom">1</property>
|
||||
<signal name="clicked" handler="on_previous" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="previous_button_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-media-previous</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
@@ -70,31 +78,156 @@ Author: Dmitriy Yefremov
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="next_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Next stream in the list</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="margin_top">1</property>
|
||||
<property name="margin_bottom">1</property>
|
||||
<signal name="clicked" handler="on_next" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="next_button_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-media-next</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="url_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Drag or paste the link here</property>
|
||||
<property name="margin_left">2</property>
|
||||
<property name="margin_right">2</property>
|
||||
<property name="margin_top">1</property>
|
||||
<property name="margin_bottom">1</property>
|
||||
<property name="primary_icon_stock">gtk-paste</property>
|
||||
<signal name="activate" handler="on_url_activate" swapped="no"/>
|
||||
<signal name="changed" handler="on_url_changed" swapped="no"/>
|
||||
<signal name="drag-data-received" handler="on_drag_data_received" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="play_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Play</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="margin_top">1</property>
|
||||
<property name="margin_bottom">1</property>
|
||||
<signal name="clicked" handler="on_play" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="play_button_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-media-play</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="stop_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Stop playback</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="margin_top">1</property>
|
||||
<property name="margin_bottom">1</property>
|
||||
<signal name="clicked" handler="on_stop" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="stop_button_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-media-stop</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="clear_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Remove added links in the playlist</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="margin_right">1</property>
|
||||
<property name="margin_top">1</property>
|
||||
<property name="margin_bottom">1</property>
|
||||
<signal name="clicked" handler="on_clear" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="clear_button_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-clear</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">6</property>
|
||||
</packing>
|
||||
</child>
|
||||
<style>
|
||||
<class name="primary-toolbar"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkStatusIcon" id="status_icon">
|
||||
<property name="icon_name">insert-link</property>
|
||||
<property name="has_tooltip">True</property>
|
||||
<signal name="activate" handler="on_status_icon_activate" object="main_window" swapped="no"/>
|
||||
<signal name="popup-menu" handler="on_popup_menu" object="staus_popup_menu" swapped="no"/>
|
||||
<signal name="query-tooltip" handler="on_query_tooltip" swapped="no"/>
|
||||
<object class="GtkImage" id="show_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">view-restore</property>
|
||||
</object>
|
||||
<object class="GtkMenu" id="staus_popup_menu">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="exit_menu_item">
|
||||
<property name="label">gtk-quit</property>
|
||||
<object class="GtkImageMenuItem" id="show_menu_item">
|
||||
<property name="label" translatable="yes">Show/Hide</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="activate" handler="on_exit" swapped="no"/>
|
||||
<property name="image">show_image</property>
|
||||
<property name="use_stock">False</property>
|
||||
<signal name="activate" handler="on_status_icon_activate" object="main_window" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkStatusIcon" id="status_icon">
|
||||
<property name="icon_name">demon-editor</property>
|
||||
<property name="has_tooltip">True</property>
|
||||
<signal name="activate" handler="on_status_icon_activate" object="main_window" swapped="no"/>
|
||||
<signal name="popup-menu" handler="on_popup_menu" object="staus_popup_menu" swapped="no"/>
|
||||
</object>
|
||||
</interface>
|
||||
|
||||
@@ -1,31 +1,69 @@
|
||||
from pathlib import Path
|
||||
from urllib.parse import urlparse
|
||||
|
||||
import gi
|
||||
from gi.repository import GLib
|
||||
|
||||
from app.commons import log
|
||||
from app.connections import HttpRequestType
|
||||
from app.tools.yt import YouTube
|
||||
from app.ui.iptv import get_yt_icon
|
||||
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, TEXT_DOMAIN
|
||||
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH
|
||||
|
||||
|
||||
class LinksTransmitter:
|
||||
""" The main class for the "send to" function.
|
||||
|
||||
It used for direct playback of media links by the enigma2 media player.
|
||||
"""
|
||||
__STREAM_PREFIX = "4097:0:1:0:0:0:0:0:0:0:"
|
||||
|
||||
def __init__(self, http_api, app_window):
|
||||
handlers = {"on_popup_menu": self.on_popup_menu,
|
||||
"on_status_icon_activate": self.on_status_icon_activate,
|
||||
"on_query_tooltip": self.on_query_tooltip,
|
||||
"on_url_changed": self.on_url_changed,
|
||||
"on_url_activate": self.on_url_activate,
|
||||
"on_drag_data_received": self.on_drag_data_received,
|
||||
"on_exit": self.on_exit}
|
||||
"on_previous": self.on_previous,
|
||||
"on_next": self.on_next,
|
||||
"on_stop": self.on_stop,
|
||||
"on_clear": self.on_clear,
|
||||
"on_play": self.on_play}
|
||||
|
||||
self._http_api = http_api
|
||||
self._app_window = app_window
|
||||
self._is_status_icon = True
|
||||
|
||||
builder = Gtk.Builder()
|
||||
builder.set_translation_domain(TEXT_DOMAIN)
|
||||
builder.add_from_file(UI_RESOURCES_PATH + "transmitter.glade")
|
||||
builder.connect_signals(handlers)
|
||||
|
||||
self._tray = builder.get_object("status_icon")
|
||||
self._main_window = builder.get_object("main_window")
|
||||
self._url_entry = builder.get_object("url_entry")
|
||||
self._tool_bar = builder.get_object("tool_bar")
|
||||
self._popup_menu = builder.get_object("staus_popup_menu")
|
||||
self._restore_menu_item = builder.get_object("restore_menu_item")
|
||||
self._status_active = None
|
||||
self._status_passive = None
|
||||
|
||||
try:
|
||||
gi.require_version("AppIndicator3", "0.1")
|
||||
from gi.repository import AppIndicator3
|
||||
except (ImportError, ValueError) as e:
|
||||
log("{}: Load library error: {}".format(__class__.__name__, e))
|
||||
self._tray = builder.get_object("status_icon")
|
||||
else:
|
||||
self._is_status_icon = False
|
||||
self._status_active = AppIndicator3.IndicatorStatus.ACTIVE
|
||||
self._status_passive = AppIndicator3.IndicatorStatus.PASSIVE
|
||||
|
||||
category = AppIndicator3.IndicatorCategory.APPLICATION_STATUS
|
||||
path = Path(UI_RESOURCES_PATH + "/icons/hicolor/scalable/apps/demon-editor.svg").resolve()
|
||||
path = str(path) if path.is_file() else "demon-editor"
|
||||
self._tray = AppIndicator3.Indicator.new("DemonEditor", path, category)
|
||||
self._tray.set_status(self._status_active)
|
||||
self._tray.set_secondary_activate_target(builder.get_object("show_menu_item"))
|
||||
self._tray.set_menu(self._popup_menu)
|
||||
|
||||
style_provider = Gtk.CssProvider()
|
||||
style_provider.load_from_path(UI_RESOURCES_PATH + "style.css")
|
||||
@@ -33,7 +71,10 @@ class LinksTransmitter:
|
||||
Gtk.STYLE_PROVIDER_PRIORITY_USER)
|
||||
|
||||
def show(self, show):
|
||||
self._tray.set_visible(show)
|
||||
if self._is_status_icon:
|
||||
self._tray.set_visible(show)
|
||||
elif self._status_active:
|
||||
self._tray.set_status(self._status_active if show else self._status_passive)
|
||||
if not show:
|
||||
self.hide()
|
||||
|
||||
@@ -48,12 +89,12 @@ class LinksTransmitter:
|
||||
window.hide() if visible else window.show()
|
||||
self._app_window.present() if visible else self._app_window.iconify()
|
||||
|
||||
def on_query_tooltip(self, icon, g, x, y, tooltip: Gtk.Tooltip):
|
||||
if self._main_window.get_visible() or not self._url_entry.get_text():
|
||||
return False
|
||||
def on_url_changed(self, entry):
|
||||
entry.set_name("GtkEntry" if self.is_url(entry.get_text()) else "digit-entry")
|
||||
|
||||
tooltip.set_text(self._url_entry.get_text())
|
||||
return True
|
||||
def on_url_activate(self, entry):
|
||||
gen = self.activate_url(entry.get_text())
|
||||
GLib.idle_add(lambda: next(gen, False), priority=GLib.PRIORITY_LOW)
|
||||
|
||||
def on_drag_data_received(self, entry, drag_context, x, y, data, info, time):
|
||||
url = data.get_text()
|
||||
@@ -63,10 +104,10 @@ class LinksTransmitter:
|
||||
|
||||
def activate_url(self, url):
|
||||
self._url_entry.set_name("GtkEntry")
|
||||
result = urlparse(url)
|
||||
self._url_entry.set_icon_from_stock(Gtk.EntryIconPosition.SECONDARY, None)
|
||||
|
||||
if result.scheme and result.netloc:
|
||||
self._url_entry.set_sensitive(False)
|
||||
if self.is_url(url):
|
||||
self._tool_bar.set_sensitive(False)
|
||||
yt_id = YouTube.get_yt_id(url)
|
||||
yield True
|
||||
|
||||
@@ -77,22 +118,56 @@ class LinksTransmitter:
|
||||
if links:
|
||||
url = links[sorted(links, key=lambda x: int(x.rstrip("p")), reverse=True)[0]]
|
||||
else:
|
||||
self.on_play(links)
|
||||
self.on_done(links)
|
||||
return
|
||||
else:
|
||||
self._url_entry.set_icon_from_stock(Gtk.EntryIconPosition.SECONDARY, None)
|
||||
|
||||
self._http_api.send(HttpRequestType.PLAY, url, self.on_play)
|
||||
self._http_api.send(HttpRequestType.PLAY, url, self.on_done, self.__STREAM_PREFIX)
|
||||
yield True
|
||||
|
||||
def on_play(self, res):
|
||||
def on_done(self, res):
|
||||
""" Play callback """
|
||||
GLib.idle_add(self._url_entry.set_sensitive, True)
|
||||
res = res.get("e2state", None) if res else res
|
||||
self._url_entry.set_name("GtkEntry" if res else "digit-entry")
|
||||
GLib.idle_add(self._tool_bar.set_sensitive, True)
|
||||
|
||||
def on_exit(self, item=None):
|
||||
self.show(False)
|
||||
def on_previous(self, item):
|
||||
self._http_api.send(HttpRequestType.PLAYER_PREV, None, self.on_done)
|
||||
|
||||
def on_next(self, item):
|
||||
self._http_api.send(HttpRequestType.PLAYER_NEXT, None, self.on_done)
|
||||
|
||||
def on_play(self, item):
|
||||
self._http_api.send(HttpRequestType.PLAYER_PLAY, None, self.on_done)
|
||||
|
||||
def on_stop(self, item):
|
||||
self._http_api.send(HttpRequestType.PLAYER_STOP, None, self.on_done)
|
||||
|
||||
def on_clear(self, item):
|
||||
""" Remove added links in the playlist. """
|
||||
GLib.idle_add(self._tool_bar.set_sensitive, False)
|
||||
self._http_api.send(HttpRequestType.PLAYER_LIST, None, self.clear_playlist)
|
||||
|
||||
def clear_playlist(self, res):
|
||||
GLib.idle_add(self._tool_bar.set_sensitive, not res)
|
||||
if "error_code" in res:
|
||||
log("Error clearing playlist. There may be no http connection.")
|
||||
self.on_done(res)
|
||||
return
|
||||
|
||||
for ref in res:
|
||||
GLib.idle_add(self._tool_bar.set_sensitive, False)
|
||||
self._http_api.send(HttpRequestType.PLAYER_REMOVE,
|
||||
ref.get("e2servicereference", ""),
|
||||
self.on_done,
|
||||
self.__STREAM_PREFIX)
|
||||
|
||||
@staticmethod
|
||||
def is_url(text):
|
||||
""" Simple url checking. """
|
||||
result = urlparse(text)
|
||||
return result.scheme and result.netloc
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import locale
|
||||
import os
|
||||
from enum import Enum, IntEnum
|
||||
from functools import lru_cache
|
||||
|
||||
import gi
|
||||
|
||||
from app.settings import Settings, SettingsException
|
||||
|
||||
gi.require_version('Gtk', '3.0')
|
||||
gi.require_version("Gtk", "3.0")
|
||||
gi.require_version("Gdk", "3.0")
|
||||
from gi.repository import Gtk, Gdk
|
||||
|
||||
# path to *.glade files
|
||||
@@ -39,23 +41,35 @@ EPG_ICON = theme.load_icon("gtk-index", 16, 0) if theme.lookup_icon("gtk-index",
|
||||
DEFAULT_ICON = theme.load_icon("emblem-default", 16, 0) if theme.lookup_icon("emblem-default", 16, 0) else None
|
||||
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def get_yt_icon(icon_name, size=24):
|
||||
""" Getting YouTube icon. If the icon is not found in the icon themes, the "Info" icon is returned by default! """
|
||||
default_theme = Gtk.IconTheme.get_default()
|
||||
if default_theme.has_icon(icon_name):
|
||||
return default_theme.load_icon(icon_name, size, 0)
|
||||
|
||||
n_theme = Gtk.IconTheme.new()
|
||||
import glob
|
||||
|
||||
for theme_name in map(os.path.basename, filter(os.path.isdir, glob.glob("/usr/share/icons/*"))):
|
||||
n_theme.set_custom_theme(theme_name)
|
||||
if n_theme.has_icon(icon_name):
|
||||
return n_theme.load_icon(icon_name, size, 0)
|
||||
|
||||
return default_theme.load_icon("info", size, 0)
|
||||
|
||||
|
||||
class KeyboardKey(Enum):
|
||||
""" The raw(hardware) codes of the keyboard keys. """
|
||||
Q = 24
|
||||
E = 26
|
||||
R = 27
|
||||
T = 28
|
||||
U = 30
|
||||
O = 32
|
||||
P = 33
|
||||
S = 39
|
||||
D = 40
|
||||
H = 43
|
||||
L = 46
|
||||
F = 41
|
||||
X = 53
|
||||
C = 54
|
||||
V = 55
|
||||
B = 56
|
||||
W = 25
|
||||
Z = 52
|
||||
INSERT = 118
|
||||
|
||||
Binary file not shown.
BIN
deb/usr/share/locale/pl/LC_MESSAGES/demon-editor.mo
Normal file
BIN
deb/usr/share/locale/pl/LC_MESSAGES/demon-editor.mo
Normal file
Binary file not shown.
Binary file not shown.
@@ -1,15 +1,20 @@
|
||||
# Copyright (C) 2018-2019 Dmitriy Yefremov
|
||||
# Copyright (C) 2018-2020 Dmitriy Yefremov
|
||||
# This file is distributed under the MIT license.
|
||||
#
|
||||
#Charly, 2019.
|
||||
#
|
||||
# Charly, 2019.
|
||||
# Dmitriy Yefremov, 2020.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Last-Translator: Charly\n"
|
||||
"Last-Translator: Dmitriy Yefremov\n"
|
||||
"Language: de\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Project-Id-Version: \n"
|
||||
"POT-Creation-Date: \n"
|
||||
"PO-Revision-Date: \n"
|
||||
"Language-Team: \n"
|
||||
"X-Generator: Poedit 2.0.6\n"
|
||||
|
||||
msgid "translator-credits"
|
||||
msgstr "Charly"
|
||||
@@ -672,7 +677,7 @@ msgid "Disabled"
|
||||
msgstr "Ausgeschaltet"
|
||||
|
||||
msgid "Enable ver. 5 support (experimental)"
|
||||
msgstr "Ver.5 Unterstützung aktivieren (experimentell)"
|
||||
msgstr "Lamedb ver. 5 Unterstützung aktivieren (experimentell)"
|
||||
|
||||
msgid "Enable HTTP API (experimental)"
|
||||
msgstr "HTTP-API aktivieren (experimentell)"
|
||||
@@ -684,4 +689,134 @@ msgid "Switch the channel and watch in the program(Ctrl + W)"
|
||||
msgstr "Kanal wechseln und im Programm ansehen(Strg + W)"
|
||||
|
||||
msgid "Play IPTV or other stream in the program(Ctrl + P)"
|
||||
msgstr "Wiedergabe von IPTV oder anderen Streams im Programm(Strg + P)"
|
||||
msgstr "Wiedergabe von IPTV oder anderen Streams im Programm(Strg + P)"
|
||||
|
||||
msgid "Export to m3u"
|
||||
msgstr "Export nach m3u"
|
||||
|
||||
msgid "EPG configuration"
|
||||
msgstr "EPG Konfiguration"
|
||||
|
||||
msgid "Apply"
|
||||
msgstr "Anwenden"
|
||||
|
||||
msgid "EPG source"
|
||||
msgstr "EPG Quelle"
|
||||
|
||||
msgid "Service names source:"
|
||||
msgstr "Quelle der Dienstnamen:"
|
||||
|
||||
msgid "Main service list"
|
||||
msgstr "Hauptdienstliste"
|
||||
|
||||
msgid "XML file"
|
||||
msgstr "XML-Datei"
|
||||
|
||||
msgid "Use web source"
|
||||
msgstr "Web-Quelle verwenden"
|
||||
|
||||
msgid "Url to *.xml.gz file:"
|
||||
msgstr "Url zur *.xml.gz Datei:"
|
||||
|
||||
msgid "Enable filtering"
|
||||
msgstr "Filterung einschalten"
|
||||
|
||||
msgid "Filter by presence in the epg.dat file."
|
||||
msgstr "Filtern nach dem Vorhandensein in der epg.dat Datei."
|
||||
|
||||
msgid "Paths to the epg.dat file:"
|
||||
msgstr "Pfade zur epg.dat Datei:"
|
||||
|
||||
msgid "Local path:"
|
||||
msgstr "Local path:"
|
||||
|
||||
msgid "STB path:"
|
||||
msgstr "STB-Pfad:"
|
||||
|
||||
msgid "Update on start"
|
||||
msgstr "Update beim Start"
|
||||
|
||||
msgid "Auto configuration by service names."
|
||||
msgstr "Automatische Konfiguration nach Dienstnamen."
|
||||
|
||||
msgid "Save list to xml."
|
||||
msgstr "Liste in XML speichern."
|
||||
|
||||
msgid "Download XML file error."
|
||||
msgstr "Fehler beim Herunterladen der XML-Datei."
|
||||
|
||||
msgid "Unsupported file type:"
|
||||
msgstr "Nicht unterstützter Dateityp:"
|
||||
|
||||
msgid "Unpacking data error."
|
||||
msgstr "Fehler beim Entpacken von Daten."
|
||||
|
||||
msgid "XML parsing error:"
|
||||
msgstr "XML Parsing-Fehler:"
|
||||
|
||||
msgid "Count of successfully configured services:"
|
||||
msgstr "Anzahl der erfolgreich konfigurierten Dienste:"
|
||||
|
||||
msgid "Current epg.dat file does not contains references for the services of this bouquet!"
|
||||
msgstr "Die aktuelle epg.dat Datei enthält keine Referenzen für die Dienste dieses Bouquets!"
|
||||
|
||||
msgid "Use HTTP"
|
||||
msgstr "HTTP verwenden"
|
||||
|
||||
msgid "Close playback"
|
||||
msgstr "Wiedergabe schliessen"
|
||||
|
||||
msgid "Import YouTube playlist"
|
||||
msgstr "YouTube-Wiedergabeliste importieren"
|
||||
|
||||
msgid ""
|
||||
"Found a link to the YouTube resource!\n"
|
||||
"Try to get a direct link to the video?"
|
||||
msgstr ""
|
||||
"Ich habe einen Link zur YouTube-Ressource gefunden!\n"
|
||||
"Versuchen einen direkten Link zum Video zu bekommen?"
|
||||
|
||||
msgid "Playlist import"
|
||||
msgstr "Playlist-Import"
|
||||
|
||||
msgid "Getting link error:"
|
||||
msgstr "Link-Fehler erhalten:"
|
||||
|
||||
msgid "Extra"
|
||||
msgstr "Extra"
|
||||
|
||||
msgid "Apply profile settings"
|
||||
msgstr "Profileinstellungen anwenden"
|
||||
|
||||
msgid "Settings type:"
|
||||
msgstr "Art der Einstellungen:"
|
||||
|
||||
msgid "Set default"
|
||||
msgstr "Standard setzen"
|
||||
|
||||
msgid "Language:"
|
||||
msgstr "Sprache:"
|
||||
|
||||
msgid "Load the last open configuration at program startup"
|
||||
msgstr "Laden der zuletzt geöffneten Konfiguration beim Programmstart"
|
||||
|
||||
msgid "Enable direct playback bar (experimental)"
|
||||
msgstr "Aktivieren der direkten Wiedergabeleiste (experimentell)"
|
||||
|
||||
msgid "Enables direct sending and playback of media links on the receiver"
|
||||
msgstr "Ermöglicht das direkte Senden und Abspielen von Medienlinks auf dem Box"
|
||||
|
||||
msgid "Watch the channel in the program"
|
||||
msgstr "Gucken den Kanal im Programm an"
|
||||
|
||||
msgid "Zap and Play"
|
||||
msgstr "Zap und Abspielen"
|
||||
|
||||
msgid "Drag or paste the link here"
|
||||
msgstr "Ziehe den Link hierher oder füge ihn ein"
|
||||
|
||||
msgid "Remove added links in the playlist"
|
||||
msgstr "Hinzugefügte Links in der Wiedergabeliste entfernen"
|
||||
|
||||
msgid "A bouquet with that name exists!"
|
||||
msgstr "Bouquet mit diesem Namen existiert!"
|
||||
|
||||
782
po/pl/demon-editor.po
Normal file
782
po/pl/demon-editor.po
Normal file
@@ -0,0 +1,782 @@
|
||||
# Copyright (C) 2018-2019 Dmitriy Yefremov
|
||||
# This file is distributed under the MIT license.
|
||||
#
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Last-Translator: wwns\n"
|
||||
"Language: pl\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Project-Id-Version: \n"
|
||||
"POT-Creation-Date: \n"
|
||||
"PO-Revision-Date: \n"
|
||||
"Language-Team: \n"
|
||||
"X-Generator: Poedit 2.3\n"
|
||||
|
||||
msgid "translator-credits"
|
||||
msgstr "wwns"
|
||||
|
||||
# Main
|
||||
msgid "Service"
|
||||
msgstr "Serwis"
|
||||
|
||||
msgid "Package"
|
||||
msgstr "Pakiet"
|
||||
|
||||
msgid "Type"
|
||||
msgstr "Typ"
|
||||
|
||||
msgid "Picon"
|
||||
msgstr "Pikon"
|
||||
|
||||
msgid "Freq"
|
||||
msgstr "Freq"
|
||||
|
||||
msgid "Rate"
|
||||
msgstr "Rate"
|
||||
|
||||
msgid "Pol"
|
||||
msgstr "Pol"
|
||||
|
||||
msgid "System"
|
||||
msgstr "System"
|
||||
|
||||
msgid "Pos"
|
||||
msgstr "Pos"
|
||||
|
||||
msgid "Num"
|
||||
msgstr "Num"
|
||||
|
||||
msgid "Current IP:"
|
||||
msgstr "Adres IP:"
|
||||
|
||||
msgid "Assign"
|
||||
msgstr "Przypisz"
|
||||
|
||||
msgid "Bouquet details"
|
||||
msgstr "Bukiet szczegóły"
|
||||
|
||||
msgid "Bouquets"
|
||||
msgstr "Bukiety"
|
||||
|
||||
msgid "Copy"
|
||||
msgstr "Kopiuj"
|
||||
|
||||
msgid "Copy reference"
|
||||
msgstr "Kopiuj odniesienie"
|
||||
|
||||
msgid "Download"
|
||||
msgstr "Pobierz"
|
||||
|
||||
msgid "Edit"
|
||||
msgstr "Edytuj"
|
||||
|
||||
msgid "Edit mаrker text"
|
||||
msgstr "Edytuj tekst znacznika"
|
||||
|
||||
msgid "FTP-transfer"
|
||||
msgstr "Transfer FTP"
|
||||
|
||||
msgid "Global search"
|
||||
msgstr "Globalne wyszukiwanie"
|
||||
|
||||
msgid "Hide"
|
||||
msgstr "Ukryj"
|
||||
|
||||
msgid "Hide/Skip On/Off Ctrl + H"
|
||||
msgstr "Ukryj/Pomiń Wł./Wył Ctrl + H"
|
||||
|
||||
msgid "Add IPTV or stream service"
|
||||
msgstr "Dodaj strumień IPTV"
|
||||
|
||||
msgid "Import m3u"
|
||||
msgstr "Importuj m3u"
|
||||
|
||||
msgid "Import m3u file"
|
||||
msgstr "Importuj plik m3u"
|
||||
|
||||
msgid "List configuration"
|
||||
msgstr "Konfiguracja listy"
|
||||
|
||||
msgid "Rename for this bouquet"
|
||||
msgstr "Zmień nazwę tego serwisu"
|
||||
|
||||
msgid "Set default name"
|
||||
msgstr "Ustaw domyślną nazwę"
|
||||
|
||||
msgid "Insert marker"
|
||||
msgstr "Wstaw znacznik"
|
||||
|
||||
msgid "Locate in services"
|
||||
msgstr "Znajdź w usługach"
|
||||
|
||||
msgid "Locked"
|
||||
msgstr "Zablokowany"
|
||||
|
||||
msgid "Move"
|
||||
msgstr "Przenieś"
|
||||
|
||||
msgid "New"
|
||||
msgstr "Nowy"
|
||||
|
||||
msgid "New bouquet"
|
||||
msgstr "Nowy bukiet"
|
||||
|
||||
msgid "Create bouquet"
|
||||
msgstr "Utwórz bukiet"
|
||||
|
||||
msgid "For current satellite"
|
||||
msgstr "Dla bieżącego satelity"
|
||||
|
||||
msgid "For current package"
|
||||
msgstr "Dla bieżącego pakietu"
|
||||
|
||||
msgid "For current type"
|
||||
msgstr "Dla bieżącego typu"
|
||||
|
||||
msgid "For each satellite"
|
||||
msgstr "Dla każdego satelity"
|
||||
|
||||
msgid "For each package"
|
||||
msgstr "Dla każdego pakietu"
|
||||
|
||||
msgid "For each type"
|
||||
msgstr "Dla każdego typu"
|
||||
|
||||
msgid "Open"
|
||||
msgstr "Otwórz"
|
||||
|
||||
msgid "Parent lock On/Off Ctrl + L"
|
||||
msgstr "Blokada rodzicielska On/Off Ctrl + L"
|
||||
|
||||
msgid "Picons"
|
||||
msgstr "Pikony"
|
||||
|
||||
msgid "Picons downloader"
|
||||
msgstr "Pobieranie pikonów"
|
||||
|
||||
msgid "Satellites downloader"
|
||||
msgstr "Pobierania satelitów"
|
||||
|
||||
msgid "Remove"
|
||||
msgstr "Usuń"
|
||||
|
||||
msgid "Remove all unavailable"
|
||||
msgstr "Usuń wszystkie niedostępne"
|
||||
|
||||
msgid "Satellites editor"
|
||||
msgstr "Edytor satelitów"
|
||||
|
||||
msgid "Save"
|
||||
msgstr "Zapisz"
|
||||
|
||||
msgid "Search"
|
||||
msgstr "Szukaj"
|
||||
|
||||
msgid "Services"
|
||||
msgstr "Kanały"
|
||||
|
||||
msgid "Services filter"
|
||||
msgstr "Filtr kanałów"
|
||||
|
||||
msgid "Settings"
|
||||
msgstr "Ustawienia"
|
||||
|
||||
msgid "Up"
|
||||
msgstr "Góra"
|
||||
|
||||
msgid "Down"
|
||||
msgstr "Dół"
|
||||
|
||||
msgid "Active profile:"
|
||||
msgstr "Aktywny Profil:"
|
||||
|
||||
msgid "All"
|
||||
msgstr "Wszystko"
|
||||
|
||||
msgid "Are you sure?"
|
||||
msgstr "Czy na pewno?"
|
||||
|
||||
msgid "Current data path:"
|
||||
msgstr "Aktualna ścieżka danych:"
|
||||
|
||||
msgid "Data:"
|
||||
msgstr "Dane:"
|
||||
|
||||
msgid "Enigma2 channel and satellites list editor for GNU/Linux"
|
||||
msgstr "Edytor kanałów Enigma2 i listy satelitów dla GNU/Linux"
|
||||
|
||||
msgid "Host:"
|
||||
msgstr "Host:"
|
||||
|
||||
msgid "Loading data..."
|
||||
msgstr "Ładowanie danych…."
|
||||
|
||||
msgid "Receive"
|
||||
msgstr "Pobieranie"
|
||||
|
||||
msgid "Receive files from receiver"
|
||||
msgstr "Pobieranie plików z odbiornika"
|
||||
|
||||
msgid "Receiver IP:"
|
||||
msgstr "Odbiornik IP:"
|
||||
|
||||
msgid "Remove unused bouquets"
|
||||
msgstr "Usuń nieużywany bouquet"
|
||||
|
||||
msgid "Reset profile"
|
||||
msgstr "Reset profilu"
|
||||
|
||||
msgid "Satellites"
|
||||
msgstr "Satelity"
|
||||
|
||||
msgid "Satellites.xml file:"
|
||||
msgstr "Plik Satellites.xml:"
|
||||
|
||||
msgid "Selected"
|
||||
msgstr "Wybrany"
|
||||
|
||||
msgid "Send"
|
||||
msgstr "Wyślij"
|
||||
|
||||
msgid "Send files to receiver"
|
||||
msgstr "Wysyłanie plików do odbiornika"
|
||||
|
||||
msgid "Services and Bouquets files:"
|
||||
msgstr "Usługi i bukiety plików:"
|
||||
|
||||
msgid "User bouquet files:"
|
||||
msgstr "Pliki bukietu użytkownika:"
|
||||
|
||||
msgid "Extra:"
|
||||
msgstr "Ekstra:"
|
||||
|
||||
# Filter bar
|
||||
msgid "Only free"
|
||||
msgstr "Tylko FTA"
|
||||
|
||||
msgid "All positions"
|
||||
msgstr "Wszystkie pozycje"
|
||||
|
||||
msgid "All types"
|
||||
msgstr "Wszystkie typy"
|
||||
|
||||
# Streams player
|
||||
msgid "Play"
|
||||
msgstr "Odtwarzaj"
|
||||
|
||||
msgid "Stop playback"
|
||||
msgstr "Zatrzymaj odtwarzanie"
|
||||
|
||||
msgid "Previous stream in the list"
|
||||
msgstr "Poprzedni strumień na liście"
|
||||
|
||||
msgid "Next stream in the list"
|
||||
msgstr "Następny strumień na liście"
|
||||
|
||||
msgid "Toggle in fullscreen"
|
||||
msgstr "Przełącz na pełny ekran"
|
||||
|
||||
msgid "Close"
|
||||
msgstr "Zamknij"
|
||||
|
||||
# Picons dialog
|
||||
msgid "Load providers"
|
||||
msgstr "Załaduj dostawców"
|
||||
|
||||
msgid "Providers"
|
||||
msgstr "Dostawca"
|
||||
|
||||
msgid "Receive picons"
|
||||
msgstr "Pobierz pikony"
|
||||
|
||||
msgid "Picons name format:"
|
||||
msgstr "Format nazw pikon:"
|
||||
|
||||
msgid "Resize:"
|
||||
msgstr "Zmień rozmiar:"
|
||||
|
||||
msgid "Current picons path:"
|
||||
msgstr "Aktualna ścieżka pikon:"
|
||||
|
||||
msgid "Receiver picons path:"
|
||||
msgstr "Ścieżka pikon odbiornika:"
|
||||
|
||||
msgid "Picons download tool"
|
||||
msgstr "Narzędzie pobierania pikon"
|
||||
|
||||
msgid "Transfer to receiver"
|
||||
msgstr "Wyślij do odbiornika"
|
||||
|
||||
msgid "Downloader"
|
||||
msgstr "Pobieranie"
|
||||
|
||||
msgid "Converter"
|
||||
msgstr "Konwerter"
|
||||
|
||||
msgid "Convert"
|
||||
msgstr "Konwertuj"
|
||||
|
||||
msgid "Path to save:"
|
||||
msgstr "Zapisz do:"
|
||||
|
||||
msgid "Path to Enigma2 picons:"
|
||||
msgstr "Ścieżka do pikon Enigma2:"
|
||||
|
||||
msgid "Specify the correct position value for the provider!"
|
||||
msgstr "Podaj poprawną wartość pozycji dla dostawcy!"
|
||||
|
||||
msgid "Converter between name formats"
|
||||
msgstr "Konwerter między formatami nazw"
|
||||
|
||||
msgid "Receive picons for providers"
|
||||
msgstr "Pobierz pikony od nadawcy"
|
||||
|
||||
msgid "Load satellite providers."
|
||||
msgstr "Załaduj dostawców satelitarnych."
|
||||
|
||||
msgid ""
|
||||
"To automatically set the identifiers for picons,\n"
|
||||
"first load the required services list into the main application window."
|
||||
msgstr ""
|
||||
"Aby automatycznie ustawić identyfikatory pikon,\n"
|
||||
"najpierw załaduj listę wymaganych usług do głównego okna aplikacji."
|
||||
|
||||
# Satellites editor
|
||||
msgid "Satellites edit tool"
|
||||
msgstr "Narzędzie do edycji satelitów"
|
||||
|
||||
msgid "Add"
|
||||
msgstr "Dodaj"
|
||||
|
||||
msgid "Satellite"
|
||||
msgstr "Satelita"
|
||||
|
||||
msgid "Transponder"
|
||||
msgstr "Transponder"
|
||||
|
||||
msgid "Satellite properties:"
|
||||
msgstr "Właściwości satelity:"
|
||||
|
||||
msgid "Transponder properties:"
|
||||
msgstr "Właściwości transpondera:"
|
||||
|
||||
msgid "Name"
|
||||
msgstr "Nazwa"
|
||||
|
||||
msgid "Position"
|
||||
msgstr "Pozycja"
|
||||
|
||||
# Satellites update dialog
|
||||
msgid "Satellites update"
|
||||
msgstr "Aktualizacja satelitów"
|
||||
|
||||
msgid "Remove selection"
|
||||
msgstr "Usuń wybrane"
|
||||
|
||||
# Service details dialog
|
||||
msgid "Service data:"
|
||||
msgstr "Dane usług:"
|
||||
|
||||
msgid "Transponder data:"
|
||||
msgstr "Dane transpondera:"
|
||||
|
||||
msgid "Service data"
|
||||
msgstr "Dane usług"
|
||||
|
||||
msgid "Transponder details"
|
||||
msgstr "Szczegóły transpondera"
|
||||
|
||||
msgid ""
|
||||
"Changes will be applied to all services of this transponder!\n"
|
||||
"Continue?"
|
||||
msgstr ""
|
||||
"Zmiany zostaną zastosowane do wszystkich usług transpondera!\n"
|
||||
"kontynuować?"
|
||||
|
||||
msgid "Reference"
|
||||
msgstr "Odniesienie"
|
||||
|
||||
msgid "Namespace"
|
||||
msgstr "Namespace"
|
||||
|
||||
msgid "Flags:"
|
||||
msgstr "Flagi:"
|
||||
|
||||
msgid "Delays (ms):"
|
||||
msgstr "Zwłoka (ms):"
|
||||
|
||||
msgid "Bitstream"
|
||||
msgstr "Bitstream"
|
||||
|
||||
msgid "Description"
|
||||
msgstr "Opis"
|
||||
|
||||
msgid "Source:"
|
||||
msgstr "Źródło:"
|
||||
|
||||
msgid "Cancel"
|
||||
msgstr "Anuluj"
|
||||
|
||||
msgid "Update"
|
||||
msgstr "Uaktualnienie"
|
||||
|
||||
msgid "Filter"
|
||||
msgstr "Filtr"
|
||||
|
||||
msgid "Find"
|
||||
msgstr "Znajdź"
|
||||
|
||||
# IPTV dialog
|
||||
msgid "Stream data"
|
||||
msgstr "Przesyłanie danych"
|
||||
|
||||
# IPTV list configuration dialog
|
||||
msgid "Starting values"
|
||||
msgstr "Wartości początkowe"
|
||||
|
||||
msgid "Reset to default"
|
||||
msgstr "Ustawienia domyślne"
|
||||
|
||||
msgid "IPTV streams list configuration"
|
||||
msgstr "Konfiguracja listy strumieni IPTV"
|
||||
|
||||
# Settings dialog
|
||||
msgid "Preferences"
|
||||
msgstr "Preferencje"
|
||||
|
||||
msgid "Profile:"
|
||||
msgstr "Profil:"
|
||||
|
||||
msgid "Timeout between commands in seconds"
|
||||
msgstr "Limit czasu między poleceniami w sekundach"
|
||||
|
||||
msgid "Timeout:"
|
||||
msgstr "Koniec czasu:"
|
||||
|
||||
msgid "Login:"
|
||||
msgstr "Login:"
|
||||
|
||||
msgid "Options"
|
||||
msgstr "Opcje"
|
||||
|
||||
msgid "Password:"
|
||||
msgstr "Hasło:"
|
||||
|
||||
msgid "Picons:"
|
||||
msgstr "Pikony:"
|
||||
|
||||
msgid "Port:"
|
||||
msgstr "Port:"
|
||||
|
||||
msgid "Data path:"
|
||||
msgstr "Ścieżka danych:"
|
||||
|
||||
msgid "Picons path:"
|
||||
msgstr "Ścieżka pikon:"
|
||||
|
||||
msgid "Network settings:"
|
||||
msgstr "Ustawienia sieci:"
|
||||
|
||||
msgid "STB file paths:"
|
||||
msgstr "Ścieżki do plików w STB:"
|
||||
|
||||
msgid "Local file paths:"
|
||||
msgstr "Lokalne ścieżki plików:"
|
||||
|
||||
# Dialogs messages
|
||||
msgid "Error. No bouquet is selected!"
|
||||
msgstr "Błąd. Nie wybrano żadnego bukietu!"
|
||||
|
||||
msgid "This item is not allowed to be removed!"
|
||||
msgstr "Tego elementu nie można usunąć!"
|
||||
|
||||
msgid "This item is not allowed to edit!"
|
||||
msgstr "Tego elementu nie można edytować!"
|
||||
|
||||
msgid "Not allowed in this context!"
|
||||
msgstr "Niedozwolone w tym kontekście!"
|
||||
|
||||
msgid "Please, download files from receiver or setup your path for read data!"
|
||||
msgstr "Pobierz pliki z odbiornika lub ustaw ścieżkę do odczytu danych!"
|
||||
|
||||
msgid "Reading data error!"
|
||||
msgstr "Błąd odczytu danych!"
|
||||
|
||||
msgid "No m3u file is selected!"
|
||||
msgstr "Nie wybrano pliku m3u!"
|
||||
|
||||
msgid "Not implemented yet!"
|
||||
msgstr "Jeszcze niezaimplementowane!"
|
||||
|
||||
msgid "The text of marker is empty, please try again!"
|
||||
msgstr "Tekst znacznika jest pusty, spróbuj ponownie!"
|
||||
|
||||
msgid "Please, select only one item!"
|
||||
msgstr "Wybierz tylko jeden element!"
|
||||
|
||||
msgid "No png file is selected!"
|
||||
msgstr "Nie wybrano pliku png!"
|
||||
|
||||
msgid "No reference is present!"
|
||||
msgstr "Brak referencji!"
|
||||
|
||||
msgid "No selected item!"
|
||||
msgstr "Brak wybranego elementu!"
|
||||
|
||||
msgid "The task is already running!"
|
||||
msgstr "Zadanie już działa!"
|
||||
|
||||
msgid "Done!"
|
||||
msgstr "Zrobione!"
|
||||
|
||||
msgid "Please, wait..."
|
||||
msgstr "Proszę czekać ..."
|
||||
|
||||
msgid "Resizing..."
|
||||
msgstr "Zmiana rozmiaru..."
|
||||
|
||||
msgid "Select paths!"
|
||||
msgstr "Wybierz ścieżki!"
|
||||
|
||||
msgid "No satellite is selected!"
|
||||
msgstr "Nie wybrano satelity!"
|
||||
|
||||
msgid "Please, select only one satellite!"
|
||||
msgstr "Wybierz tylko jednego satelitę!"
|
||||
|
||||
msgid "Please check your parameters and try again."
|
||||
msgstr "Sprawdź parametry i spróbuj ponownie."
|
||||
|
||||
msgid "No satellites.xml file is selected!"
|
||||
msgstr "Nie wybrano pliku satellites.xml!"
|
||||
|
||||
msgid "Error. Verify the data!"
|
||||
msgstr "Błąd. Zweryfikuj dane!"
|
||||
|
||||
msgid "Operation not allowed in this context!"
|
||||
msgstr "Operacja niedozwolona w tym kontekście!"
|
||||
|
||||
msgid "No VLC is found. Check that it is installed!"
|
||||
msgstr "Nie znaleziono VLC. Sprawdź, czy jest zainstalowany!"
|
||||
|
||||
# Search unavailable streams dialog
|
||||
msgid "Please wait, streams testing in progress..."
|
||||
msgstr "Proszę czekać, trwa testowanie strumieni..."
|
||||
|
||||
msgid "Found"
|
||||
msgstr "Znaleziono"
|
||||
|
||||
msgid "unavailable streams."
|
||||
msgstr "niedostępne strumienie."
|
||||
|
||||
msgid "No changes required!"
|
||||
msgstr "Nie wymaga zmian!"
|
||||
|
||||
msgid "This list does not contains IPTV streams!"
|
||||
msgstr "Ta lista nie zawiera strumieni IPTV!"
|
||||
|
||||
msgid "New empty configuration"
|
||||
msgstr "Nowa pusta konfiguracja"
|
||||
|
||||
msgid "No data to save!"
|
||||
msgstr "Brak danych do zapisania!"
|
||||
|
||||
msgid "Network"
|
||||
msgstr "Sieć"
|
||||
|
||||
msgid "Paths"
|
||||
msgstr "Ścieżki"
|
||||
|
||||
msgid "Program"
|
||||
msgstr "Program"
|
||||
|
||||
msgid "Backup:"
|
||||
msgstr "Kopia:"
|
||||
|
||||
msgid "Backup"
|
||||
msgstr "Kopia"
|
||||
|
||||
msgid "Backups"
|
||||
msgstr "Kopie zapasowe"
|
||||
|
||||
msgid "Backup path:"
|
||||
msgstr "Ścieżka kopii:"
|
||||
|
||||
msgid "Restore bouquets"
|
||||
msgstr "Przywróć bukiety"
|
||||
|
||||
msgid "Restore all"
|
||||
msgstr "Przywrócić wszystko"
|
||||
|
||||
msgid "Before saving"
|
||||
msgstr "Przed zapisaniem"
|
||||
|
||||
msgid "Before downloading from the receiver"
|
||||
msgstr "Przed pobraniem z odbiornika"
|
||||
|
||||
msgid "Set background color for the services"
|
||||
msgstr "Ustaw kolor tła dla usług"
|
||||
|
||||
msgid "Marked as new:"
|
||||
msgstr "Oznacz jako nowy:"
|
||||
|
||||
msgid "With an extra name in the bouquet:"
|
||||
msgstr "Z dodatkową nazwą w bukiecie:"
|
||||
|
||||
msgid "Select"
|
||||
msgstr "Wybierz"
|
||||
|
||||
msgid "About"
|
||||
msgstr "Wersja"
|
||||
|
||||
msgid "Exit"
|
||||
msgstr "Wyjście"
|
||||
|
||||
msgid "Tools"
|
||||
msgstr "Narzędzia"
|
||||
|
||||
# Import
|
||||
msgid "Import"
|
||||
msgstr "Importuj"
|
||||
|
||||
msgid "Bouquet"
|
||||
msgstr "Bukiet"
|
||||
|
||||
msgid "Bouquets and services"
|
||||
msgstr "Bukiety i kanały"
|
||||
|
||||
msgid "The main list does not contain services for this bouquet!"
|
||||
msgstr "Główna lista nie zawiera kanałów dla tego bukietu!"
|
||||
|
||||
msgid "No bouquet file is selected!"
|
||||
msgstr "Nie wybrano pliku bukietu!"
|
||||
|
||||
msgid "Remove all unused"
|
||||
msgstr "Usuń wszystkie nieużywane"
|
||||
|
||||
msgid "Test"
|
||||
msgstr "Test"
|
||||
|
||||
msgid "Test connection"
|
||||
msgstr "Testuj połączenie"
|
||||
|
||||
msgid "Double click on the service in the bouquet list:"
|
||||
msgstr "Kliknij dwukrotnie usługę na liście bukietów:"
|
||||
|
||||
msgid "Zap"
|
||||
msgstr "Przełącz"
|
||||
|
||||
msgid "Play stream"
|
||||
msgstr "Odtwórz strumień"
|
||||
|
||||
msgid "Disabled"
|
||||
msgstr "Wyłączone"
|
||||
|
||||
msgid "Enable ver. 5 support (experimental)"
|
||||
msgstr "Włącz wer. 5 wsparcie (eksperymentalne)"
|
||||
|
||||
msgid "Enable HTTP API (experimental)"
|
||||
msgstr "Włącz API HTTP (eksperymentalne)"
|
||||
|
||||
msgid "Switch(zap) the channel(Ctrl + Z)"
|
||||
msgstr "Przełącz(zap) kanał(Ctrl + Z)"
|
||||
|
||||
msgid "Switch the channel and watch in the program(Ctrl + W)"
|
||||
msgstr "Przełącz kanał i oglądaj w programie(Ctrl + W)"
|
||||
|
||||
msgid "Play IPTV or other stream in the program(Ctrl + P)"
|
||||
msgstr "Odtwórz IPTV lub inny strumień w programie(Ctrl + P)"
|
||||
|
||||
msgid "Export to m3u"
|
||||
msgstr "Eksportuj do m3u"
|
||||
|
||||
msgid "EPG configuration"
|
||||
msgstr "Koniguruj EPG"
|
||||
|
||||
msgid "Apply"
|
||||
msgstr "Zatwierdź"
|
||||
|
||||
msgid "EPG source"
|
||||
msgstr "Źródło EPG"
|
||||
|
||||
msgid "Service names source:"
|
||||
msgstr "Źródło nazw usług:"
|
||||
|
||||
msgid "Main service list"
|
||||
msgstr "Główna lista usług"
|
||||
|
||||
msgid "XML file"
|
||||
msgstr "Plik XML"
|
||||
|
||||
msgid "Use web source"
|
||||
msgstr "Użyj źródła internetowego"
|
||||
|
||||
msgid "Url to *.xml.gz file:"
|
||||
msgstr "URL do pliku *.xml.gz:"
|
||||
|
||||
msgid "Enable filtering"
|
||||
msgstr "Włącz filtrowanie"
|
||||
|
||||
msgid "Filter by presence in the epg.dat file."
|
||||
msgstr "Filtruj według ustawień w pliku epg.dat."
|
||||
|
||||
msgid "Paths to the epg.dat file:"
|
||||
msgstr "Ścieżka do pliku epg.dat:"
|
||||
|
||||
msgid "Local path:"
|
||||
msgstr "Ścieżka lokalna:"
|
||||
|
||||
msgid "STB path:"
|
||||
msgstr "Ścieżka STB:"
|
||||
|
||||
msgid "Update on start"
|
||||
msgstr "Aktualizuj przy starcie"
|
||||
|
||||
msgid "Auto configuration by service names."
|
||||
msgstr "Automatyczna konfiguracja serwisu według nazw."
|
||||
|
||||
msgid "Save list to xml."
|
||||
msgstr "Zapisz listę do XML."
|
||||
|
||||
msgid "Download XML file error."
|
||||
msgstr "Błąd pobierania pliku XML."
|
||||
|
||||
msgid "Unsupported file type:"
|
||||
msgstr "Nieobsługiwany typ pliku:"
|
||||
|
||||
msgid "Unpacking data error."
|
||||
msgstr "Błąd rozpakowywania danych."
|
||||
|
||||
msgid "XML parsing error:"
|
||||
msgstr "Błąd analizy XML:"
|
||||
|
||||
msgid "Count of successfully configured services:"
|
||||
msgstr "Liczba pomyślnie skonfigurowanych usług:"
|
||||
|
||||
msgid "Current epg.dat file does not contains references for the services of this bouquet!"
|
||||
msgstr "Bieżący plik epg.dat nie zawiera odniesień do usług tego bukietu!"
|
||||
|
||||
msgid "Use HTTP"
|
||||
msgstr "Użyj HTTP"
|
||||
|
||||
msgid "Close playback"
|
||||
msgstr "Zamknij odtwarzanie"
|
||||
|
||||
msgid "Import YouTube playlist"
|
||||
msgstr "Importuj listę odtwarzania YouTube"
|
||||
|
||||
msgid ""
|
||||
"Found a link to the YouTube resource!\n"
|
||||
"Try to get a direct link to the video?"
|
||||
msgstr ""
|
||||
"Znaleziono link do zasobu YouTube!\n"
|
||||
"Chcesz uzyskać bezpośredni link do filmu?"
|
||||
|
||||
msgid "Playlist import"
|
||||
msgstr "Import listy odtwarzania"
|
||||
|
||||
msgid "Getting link error:"
|
||||
msgstr "Błąd pobierania łącza:"
|
||||
@@ -763,3 +763,42 @@ msgstr "Импорт плейлиста"
|
||||
|
||||
msgid "Getting link error:"
|
||||
msgstr "Ошибка получения ссылки:"
|
||||
|
||||
msgid "Extra"
|
||||
msgstr "Дополнительно"
|
||||
|
||||
msgid "Apply profile settings"
|
||||
msgstr "Применить настройки профиля"
|
||||
|
||||
msgid "Settings type:"
|
||||
msgstr "Тип настроек:"
|
||||
|
||||
msgid "Set default"
|
||||
msgstr "Установить по умолчанию"
|
||||
|
||||
msgid "Language:"
|
||||
msgstr "Язык:"
|
||||
|
||||
msgid "Load the last open configuration at program startup"
|
||||
msgstr "Загружать последнюю открытую конфигурацию при запуске программы"
|
||||
|
||||
msgid "Enable direct playback bar (experimental)"
|
||||
msgstr "Включить панель прямого воспроизведения (экспериментально)"
|
||||
|
||||
msgid "Enables direct sending and playback of media links on the receiver"
|
||||
msgstr "Включает прямую отправку и воспроизведение медиа-ссылок на ресивере"
|
||||
|
||||
msgid "Watch the channel in the program"
|
||||
msgstr "Просмотр канала в программе"
|
||||
|
||||
msgid "Zap and Play"
|
||||
msgstr "Перекл. и просмотр"
|
||||
|
||||
msgid "Drag or paste the link here"
|
||||
msgstr "Перетащите или вставьте ссылку здесь"
|
||||
|
||||
msgid "Remove added links in the playlist"
|
||||
msgstr "Удалить добавленные ссылки из плейлиста"
|
||||
|
||||
msgid "A bouquet with that name exists!"
|
||||
msgstr "Букет с таким именем существует!"
|
||||
Reference in New Issue
Block a user