mirror of
https://github.com/DYefremov/DemonEditor.git
synced 2026-05-09 10:25:36 +02:00
Compare commits
72 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e54719ca2c | ||
|
|
0c1c44c866 | ||
|
|
06b82251ef | ||
|
|
fb929ec723 | ||
|
|
fd1c1bfd6e | ||
|
|
c48a08b239 | ||
|
|
b647b0a338 | ||
|
|
9b608eeb74 | ||
|
|
07e55b3f1e | ||
|
|
7e639f5637 | ||
|
|
5570d47cae | ||
|
|
5c49c0d123 | ||
|
|
ee6dd511b5 | ||
|
|
1f847233b3 | ||
|
|
835e1af8e4 | ||
|
|
50e0d8b66a | ||
|
|
fb0789664a | ||
|
|
5dd39492f2 | ||
|
|
33be9f21a2 | ||
|
|
7acc9ae74f | ||
|
|
d492022232 | ||
|
|
b034995130 | ||
|
|
f037b3554d | ||
|
|
7f1f27da57 | ||
|
|
d7f3afecb0 | ||
|
|
f309005c52 | ||
|
|
25661816e7 | ||
|
|
a2652cef4b | ||
|
|
adbc9ad322 | ||
|
|
2dc8611294 | ||
|
|
72bfd21056 | ||
|
|
65ef018f81 | ||
|
|
1236c5ebc9 | ||
|
|
f0011ebcf2 | ||
|
|
392e94e7ba | ||
|
|
c6de18271d | ||
|
|
71a65242c1 | ||
|
|
4efc956870 | ||
|
|
a605fdd545 | ||
|
|
285c1cae69 | ||
|
|
2e937a42a3 | ||
|
|
e208cf4656 | ||
|
|
3db82e3e18 | ||
|
|
38e9a85694 | ||
|
|
438e9c10d4 | ||
|
|
920fa01159 | ||
|
|
d2787364cd | ||
|
|
839c0fae23 | ||
|
|
f87548e12e | ||
|
|
463702c371 | ||
|
|
0b84a81439 | ||
|
|
6b68740961 | ||
|
|
92aa2400f6 | ||
|
|
2cf4e5b756 | ||
|
|
6cfa68e219 | ||
|
|
138aa54b44 | ||
|
|
3e1a3d1595 | ||
|
|
b833458c45 | ||
|
|
d1e88be1cc | ||
|
|
72e128aeb9 | ||
|
|
457b4e4645 | ||
|
|
076243b0ac | ||
|
|
e5ff185791 | ||
|
|
2b6b0dd827 | ||
|
|
a11fdd683e | ||
|
|
636bc5c52f | ||
|
|
90d64d46c7 | ||
|
|
115f77108c | ||
|
|
2082f8e973 | ||
|
|
7e586bf0a6 | ||
|
|
c5c4823534 | ||
|
|
6235519cf9 |
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018-2021 Dmitriy Yefremov
|
||||
Copyright (c) 2018-2023 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
|
||||
|
||||
@@ -30,8 +30,7 @@ Experimental support of Neutrino-MP or others on the same basis (BPanther, etc).
|
||||
|
||||
#### 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 + C** - only in services list.
|
||||
* **Ctrl + Insert** - copies the selected channels from the main list to the bouquet
|
||||
beginning or inserts (creates) a new bouquet.
|
||||
* **Ctrl + BackSpace** - copies the selected channels from the main list to the bouquet end.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2018-2022 Dmitriy Yefremov
|
||||
# Copyright (c) 2018-2023 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
|
||||
@@ -35,6 +35,7 @@ import xml.etree.ElementTree as ETree
|
||||
from enum import Enum
|
||||
from ftplib import FTP, CRLF, Error, all_errors
|
||||
from http.client import RemoteDisconnected
|
||||
from pathlib import Path
|
||||
from telnetlib import Telnet
|
||||
from urllib.error import HTTPError, URLError
|
||||
from urllib.parse import urlencode, quote
|
||||
@@ -89,11 +90,11 @@ class UtfFTP(FTP):
|
||||
while 1:
|
||||
line = fp.readline(self.maxline + 1)
|
||||
if len(line) > self.maxline:
|
||||
msg = "UtfFTP [retrlines] error: got more than {} bytes".format(self.maxline)
|
||||
msg = f"UtfFTP [retrlines] error: got more than {self.maxline} bytes"
|
||||
log(msg)
|
||||
raise Error(msg)
|
||||
if self.debugging > 2:
|
||||
log('UtfFTP [retrlines] *retr* {}'.format(repr(line)))
|
||||
log(f"UtfFTP [retrlines] *retr* {repr(line)}")
|
||||
if not line:
|
||||
break
|
||||
if line[-2:] == CRLF:
|
||||
@@ -112,9 +113,8 @@ class UtfFTP(FTP):
|
||||
|
||||
def download_file(self, name, save_path, callback=None):
|
||||
with open(save_path + name, "wb") as f:
|
||||
msg = "Downloading file: {}. Status: {}"
|
||||
resp = self.download_binary(name, f)
|
||||
msg = msg.format(name, resp)
|
||||
msg = f"Downloading file: {name}. Status: {resp}"
|
||||
callback(msg) if callback else log(msg.rstrip())
|
||||
|
||||
return resp
|
||||
@@ -470,7 +470,7 @@ def upload_data(*, settings, download_type=DownloadType.ALL, callback=log, done_
|
||||
|
||||
z_name = "picons.zip"
|
||||
zip_file = f"{p_src}{z_name}"
|
||||
p_dst = os.path.abspath(os.path.join(p_dst, os.pardir))
|
||||
p_dst = Path(p_dst).parent.as_posix()
|
||||
|
||||
if files_filter and z_name in files_filter:
|
||||
files_filter.remove(z_name)
|
||||
@@ -650,6 +650,16 @@ class HttpAPI:
|
||||
|
||||
class Remote(str, Enum):
|
||||
""" Args for HttpRequestType [REMOTE] class. """
|
||||
ONE = "2"
|
||||
TWO = "3"
|
||||
THREE = "4"
|
||||
FOUR = "5"
|
||||
FIVE = "6"
|
||||
SIX = "7"
|
||||
SEVEN = "8"
|
||||
EIGHT = "9"
|
||||
NINE = "10"
|
||||
ZERO = "11"
|
||||
UP = "103"
|
||||
LEFT = "105"
|
||||
RIGHT = "106"
|
||||
@@ -658,6 +668,7 @@ class HttpAPI:
|
||||
EXIT = "174"
|
||||
OK = "352"
|
||||
INFO = "358"
|
||||
EPG = "365"
|
||||
TV = "377"
|
||||
RADIO = "385"
|
||||
AUDIO = "392"
|
||||
@@ -668,6 +679,7 @@ class HttpAPI:
|
||||
BLUE = "401"
|
||||
CH_UP = "402"
|
||||
CH_DOWN = "403"
|
||||
NEXT = "407"
|
||||
BACK = "412"
|
||||
|
||||
class Power(str, Enum):
|
||||
|
||||
@@ -38,9 +38,9 @@ from app.ui.uicommons import IPTV_ICON
|
||||
|
||||
# url, description, urlkey, account, usrname, psw, s_type, iconsrc, iconsrc_b, group
|
||||
NEUTRINO_FAV_ID_FORMAT = "{}::{}::{}::{}::{}::{}::{}::{}::{}::{}"
|
||||
ENIGMA2_FAV_ID_FORMAT = " {}:{}:{}:{:X}:{:X}:{:X}:{:X}:0:0:0:{}:{}\n#DESCRIPTION: {}\n"
|
||||
ENIGMA2_FAV_ID_FORMAT = " {}:{}:{}:{:X}:{:X}:{:X}:{:X}:0:0:0:{}:{}\n#DESCRIPTION {}\n"
|
||||
MARKER_FORMAT = " 1:64:{}:0:0:0:0:0:0:0::{}\n#DESCRIPTION {}\n"
|
||||
PICON_FORMAT = "1_{}_{:X}_{:X}_{:X}_{:X}_{:X}_0_0_0.png"
|
||||
PICON_FORMAT = "{}_{}_{:X}_{:X}_{:X}_{:X}_{:X}_0_0_0.png"
|
||||
|
||||
|
||||
class StreamType(Enum):
|
||||
@@ -163,9 +163,10 @@ def get_fav_id(url, name, settings_type, params=None, st_type=None, s_id=0, srv_
|
||||
return NEUTRINO_FAV_ID_FORMAT.format(url, "", 0, None, None, None, None, "", "", 1)
|
||||
|
||||
|
||||
def get_picon_id(params=None, s_id=0, srv_type=1):
|
||||
def get_picon_id(params=None, st_type=None, s_id=0, srv_type=1):
|
||||
st_type = st_type or StreamType.NONE_TS.value
|
||||
params = params or (0, 0, 0, 0)
|
||||
return PICON_FORMAT.format(s_id, srv_type, *params)
|
||||
return PICON_FORMAT.format(st_type, s_id, srv_type, *params)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2018-2022 Dmitriy Yefremov
|
||||
# Copyright (c) 2018-2023 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
|
||||
@@ -81,6 +81,7 @@ class Defaults(Enum):
|
||||
BACKUP_BEFORE_DOWNLOADING = True
|
||||
BACKUP_BEFORE_SAVE = True
|
||||
V5_SUPPORT = False
|
||||
UNLIMITED_COPY_BUFFER = False
|
||||
FORCE_BQ_NAMES = False
|
||||
HTTP_API_SUPPORT = True
|
||||
ENABLE_YT_DL = False
|
||||
@@ -606,6 +607,14 @@ class Settings:
|
||||
def v5_support(self, value):
|
||||
self._settings["v5_support"] = value
|
||||
|
||||
@property
|
||||
def unlimited_copy_buffer(self):
|
||||
return self._settings.get("unlimited_copy_buffer", Defaults.UNLIMITED_COPY_BUFFER.value)
|
||||
|
||||
@unlimited_copy_buffer.setter
|
||||
def unlimited_copy_buffer(self, value):
|
||||
self._settings["unlimited_copy_buffer"] = value
|
||||
|
||||
@property
|
||||
def force_bq_names(self):
|
||||
return self._settings.get("force_bq_names", Defaults.FORCE_BQ_NAMES.value)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2018-2022 Dmitriy Yefremov
|
||||
# Copyright (c) 2018-2023 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
|
||||
@@ -32,12 +32,12 @@ import os
|
||||
import shutil
|
||||
import struct
|
||||
import sys
|
||||
import xml.etree.ElementTree as ET
|
||||
from collections import namedtuple
|
||||
from datetime import datetime, timezone
|
||||
from tempfile import NamedTemporaryFile
|
||||
from urllib.parse import urlparse
|
||||
from xml.dom.minidom import parse, Node, Document
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
import requests
|
||||
|
||||
@@ -54,8 +54,8 @@ except ModuleNotFoundError:
|
||||
else:
|
||||
DETECT_ENCODING = True
|
||||
|
||||
EpgEvent = namedtuple("EpgEvent", ["service_name", "title", "time", "desc", "event_data"])
|
||||
EpgEvent.__new__.__defaults__ = ("N/A", "N/A", "N/A", "N/A", None) # For Python3 < 3.7
|
||||
EpgEvent = namedtuple("EpgEvent", ["service_name", "title", "start", "end", "length", "desc", "event_data"])
|
||||
EpgEvent.__new__.__defaults__ = ("N/A", "N/A", 0, 0, 0, "N/A", None) # For Python3 < 3.7
|
||||
|
||||
|
||||
class Reader(metaclass=abc.ABCMeta):
|
||||
@@ -298,14 +298,15 @@ class XmlTvReader(Reader):
|
||||
offset = datetime.now() - dt
|
||||
|
||||
for srv in filter(lambda s: any(name in names for name in s.names), self._ids.values()):
|
||||
ev = list(filter(lambda s: s.start < utc, srv.events))
|
||||
ev = max(filter(lambda s: s.start < utc, srv.events), key=lambda x: x.start, default=None)
|
||||
if ev:
|
||||
ev = ev[-1]
|
||||
start = datetime.fromtimestamp(ev.start) + offset
|
||||
end_time = datetime.fromtimestamp(ev.duration) + offset
|
||||
tm = f"{start.strftime('%H:%M')} - {end_time.strftime('%H:%M')}"
|
||||
start = start.timestamp()
|
||||
end_time = end_time.timestamp()
|
||||
|
||||
for n in srv.names:
|
||||
events[n] = EpgEvent(n, ev.title, tm, ev.desc, ev)
|
||||
events[n] = EpgEvent(n, ev.title, start, end_time, int(ev.duration), ev.desc, ev)
|
||||
|
||||
return events
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2018-2022 Dmitriy Yefremov
|
||||
# Copyright (c) 2018-2023 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
|
||||
@@ -63,6 +63,7 @@ class Player(Gtk.DrawingArea):
|
||||
parent = widget.get_parent()
|
||||
parent.connect("play", self.on_play)
|
||||
parent.connect("stop", self.on_stop)
|
||||
parent.connect("pause", self.on_pause)
|
||||
self.show()
|
||||
|
||||
def get_play_mode(self):
|
||||
@@ -107,6 +108,9 @@ class Player(Gtk.DrawingArea):
|
||||
def on_stop(self, widget, state):
|
||||
self.stop()
|
||||
|
||||
def on_pause(self, widget, state):
|
||||
self.pause()
|
||||
|
||||
def on_release(self, widget, state):
|
||||
self.release()
|
||||
|
||||
@@ -241,7 +245,7 @@ class MpvPlayer(Player):
|
||||
self._is_playing = True
|
||||
|
||||
def pause(self):
|
||||
pass
|
||||
self._player.pause = not self._player.pause
|
||||
|
||||
def set_time(self, time):
|
||||
pass
|
||||
@@ -330,7 +334,11 @@ class GstPlayer(Player):
|
||||
self._is_playing = False
|
||||
|
||||
def pause(self):
|
||||
self._player.set_state(self.STATE.PAUSED)
|
||||
state = self._player.get_state(self.STATE.NULL).state
|
||||
if state == self.STATE.PLAYING:
|
||||
self._player.set_state(self.STATE.PAUSED)
|
||||
elif state == self.STATE.PAUSED:
|
||||
self._player.set_state(self.STATE.PLAYING)
|
||||
|
||||
def set_time(self, time):
|
||||
pass
|
||||
|
||||
@@ -16,17 +16,17 @@
|
||||
# <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
from ctypes import *
|
||||
import ctypes.util
|
||||
import threading
|
||||
import os
|
||||
import sys
|
||||
from warnings import warn
|
||||
from functools import partial, wraps
|
||||
from contextlib import contextmanager
|
||||
import collections
|
||||
import ctypes.util
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import threading
|
||||
import traceback
|
||||
from contextlib import contextmanager
|
||||
from ctypes import *
|
||||
from functools import partial, wraps
|
||||
from warnings import warn
|
||||
|
||||
if os.name == 'nt':
|
||||
dll = ctypes.util.find_library('mpv-1.dll')
|
||||
@@ -569,10 +569,13 @@ _mpv_free_node_contents = backend.mpv_free_node_contents
|
||||
backend.mpv_create.restype = MpvHandle
|
||||
_mpv_create = backend.mpv_create
|
||||
|
||||
_API_VER = _mpv_client_api_version()[0]
|
||||
|
||||
_handle_func('mpv_destroy' if _API_VER > 1 else 'mpv_detach_destroy', [], None, errcheck=None)
|
||||
_handle_func('mpv_create_client', [c_char_p], MpvHandle, notnull_errcheck)
|
||||
_handle_func('mpv_client_name', [], c_char_p, errcheck=None)
|
||||
_handle_func('mpv_initialize', [], c_int, ec_errcheck)
|
||||
_handle_func('mpv_detach_destroy', [], None, errcheck=None)
|
||||
|
||||
_handle_func('mpv_terminate_destroy', [], None, errcheck=None)
|
||||
_handle_func('mpv_load_config_file', [c_char_p], c_int, ec_errcheck)
|
||||
_handle_func('mpv_get_time_us', [], c_ulonglong, errcheck=None)
|
||||
@@ -608,28 +611,6 @@ _handle_func('mpv_get_wakeup_pipe', [], c_int, errcheck=None)
|
||||
|
||||
_handle_func('mpv_stream_cb_add_ro', [c_char_p, c_void_p, StreamOpenFn], c_int, ec_errcheck)
|
||||
|
||||
# Disabled for compatibility with the old version of mpv!!!
|
||||
# _handle_func('mpv_render_context_create', [MpvRenderCtxHandle, MpvHandle, POINTER(MpvRenderParam)], c_int, ec_errcheck, ctx=None)
|
||||
# _handle_func('mpv_render_context_set_parameter', [MpvRenderParam], c_int, ec_errcheck, ctx=MpvRenderCtxHandle)
|
||||
# _handle_func('mpv_render_context_get_info', [MpvRenderParam], c_int, ec_errcheck, ctx=MpvRenderCtxHandle)
|
||||
# _handle_func('mpv_render_context_set_update_callback', [RenderUpdateFn, c_void_p], None, errcheck=None, ctx=MpvRenderCtxHandle)
|
||||
# _handle_func('mpv_render_context_update', [], c_int64, errcheck=None, ctx=MpvRenderCtxHandle)
|
||||
# _handle_func('mpv_render_context_render', [POINTER(MpvRenderParam)], c_int, ec_errcheck, ctx=MpvRenderCtxHandle)
|
||||
# _handle_func('mpv_render_context_report_swap', [], None, errcheck=None, ctx=MpvRenderCtxHandle)
|
||||
# _handle_func('mpv_render_context_free', [], None, errcheck=None, ctx=MpvRenderCtxHandle)
|
||||
|
||||
|
||||
# Deprecated in v0.29.0 and may disappear eventually
|
||||
if hasattr(backend, 'mpv_get_sub_api'):
|
||||
_handle_func('mpv_get_sub_api', [MpvSubApi], c_void_p, notnull_errcheck, deprecated=True)
|
||||
|
||||
_handle_gl_func('mpv_opengl_cb_set_update_callback', [OpenGlCbUpdateFn, c_void_p], deprecated=True)
|
||||
_handle_gl_func('mpv_opengl_cb_init_gl', [c_char_p, OpenGlCbGetProcAddrFn, c_void_p], c_int, deprecated=True)
|
||||
_handle_gl_func('mpv_opengl_cb_draw', [c_int, c_int, c_int], c_int, deprecated=True)
|
||||
_handle_gl_func('mpv_opengl_cb_render', [c_int, c_int], c_int, deprecated=True)
|
||||
_handle_gl_func('mpv_opengl_cb_report_flip', [c_ulonglong], c_int, deprecated=True)
|
||||
_handle_gl_func('mpv_opengl_cb_uninit_gl', [], c_int, deprecated=True)
|
||||
|
||||
|
||||
def _mpv_coax_proptype(value, proptype=str):
|
||||
"""Intelligently coax the given python value into something that can be understood as a proptype property."""
|
||||
@@ -934,7 +915,7 @@ class MPV(object):
|
||||
self._message_handlers[target](*args)
|
||||
|
||||
if eid == MpvEventID.SHUTDOWN:
|
||||
_mpv_detach_destroy(self._event_handle)
|
||||
_mpv_destroy(self._event_handle) if _API_VER > 1 else _mpv_detach_destroy(self._event_handle)
|
||||
return
|
||||
|
||||
except Exception as e:
|
||||
|
||||
@@ -59,7 +59,7 @@ class PiconsCzDownloader:
|
||||
_BASE_LOGO_URL = "https://picon.cz/picon/0/"
|
||||
_HEADER = {"User-Agent": "DemonEditor/3.0.0", "Referer": ""}
|
||||
_LINK_PATTERN = re.compile(r"((.*)-\d+x\d+)-(.*)_by_chocholousek.7z$")
|
||||
_FILE_PATTERN = re.compile(b"\\s+(1_.*\\.png).*")
|
||||
_FILE_PATTERN = re.compile(b"\\s+(\\w+\\.png).*")
|
||||
|
||||
def __init__(self, picon_ids=set(), appender=log):
|
||||
self._perm_links = {}
|
||||
@@ -220,7 +220,8 @@ class PiconsCzDownloader:
|
||||
"piconoled": "o96",
|
||||
"piconblack80": "b50",
|
||||
"piconblack3d": "b50",
|
||||
"piconwin11": "win11220"
|
||||
"piconwin11": "win11220",
|
||||
"piconSNPtransparent": "t50"
|
||||
}
|
||||
|
||||
def get_name_map(self):
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2018-2022 Dmitriy Yefremov
|
||||
# Copyright (c) 2018-2023 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
|
||||
@@ -36,10 +36,10 @@ from enum import Enum
|
||||
from pathlib import Path
|
||||
|
||||
from app.commons import run_idle, get_size_from_bytes
|
||||
from app.settings import SettingsType, SEP
|
||||
from app.settings import SettingsType, SEP, IS_DARWIN
|
||||
from app.ui.dialogs import show_dialog, DialogType, get_builder
|
||||
from app.ui.main_helper import append_text_to_tview
|
||||
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, KeyboardKey, MOD_MASK, IS_GNOME_SESSION
|
||||
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, KeyboardKey, MOD_MASK, IS_GNOME_SESSION, HeaderBar
|
||||
|
||||
|
||||
class RestoreType(Enum):
|
||||
@@ -77,8 +77,8 @@ class BackupDialog:
|
||||
self._message_label = builder.get_object("message_label")
|
||||
self._file_count_label = builder.get_object("file_count_label")
|
||||
|
||||
if IS_GNOME_SESSION:
|
||||
header_bar = Gtk.HeaderBar(visible=True, show_close_button=True)
|
||||
if IS_GNOME_SESSION or IS_DARWIN:
|
||||
header_bar = HeaderBar()
|
||||
self._dialog_window.set_titlebar(header_bar)
|
||||
|
||||
button_box = builder.get_object("main_button_box")
|
||||
@@ -245,8 +245,8 @@ def backup_data(path, backup_path, move=True):
|
||||
backup_path = f"{backup_path}{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}{SEP}"
|
||||
os.makedirs(os.path.dirname(backup_path), exist_ok=True)
|
||||
os.makedirs(os.path.dirname(path), exist_ok=True)
|
||||
# Backup files in data dir(skipping dirs and satellites.xml).
|
||||
for file in filter(lambda f: f != "satellites.xml" and os.path.isfile(os.path.join(path, f)), os.listdir(path)):
|
||||
# Backup files in data dir(skipping dirs and *.xml).
|
||||
for file in filter(lambda f: not f.endswith(".xml") and os.path.isfile(os.path.join(path, f)), os.listdir(path)):
|
||||
src, dst = os.path.join(path, file), backup_path + file
|
||||
shutil.move(src, dst) if move else shutil.copy(src, dst)
|
||||
# Compressing to zip and delete remaining files.
|
||||
@@ -263,8 +263,8 @@ def restore_data(src, dst):
|
||||
|
||||
|
||||
def clear_data_path(path):
|
||||
""" Clearing data at the specified path excluding satellites.xml file """
|
||||
for file in filter(lambda f: f != "satellites.xml" and os.path.isfile(os.path.join(path, f)), os.listdir(path)):
|
||||
""" Clearing data at the specified path excluding *.xml file. """
|
||||
for file in filter(lambda f: not f.endswith(".xml") and os.path.isfile(os.path.join(path, f)), os.listdir(path)):
|
||||
os.remove(os.path.join(path, file))
|
||||
|
||||
|
||||
|
||||
1107
app/ui/control.glade
1107
app/ui/control.glade
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2018-2022 Dmitriy Yefremov
|
||||
# Copyright (c) 2018-2023 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
|
||||
@@ -70,6 +70,7 @@ class ControlTool(Gtk.Box):
|
||||
self._agc_level_bar = builder.get_object("agc_level_bar")
|
||||
self._volume_button = builder.get_object("volume_button")
|
||||
self._header_box = builder.get_object("control_header_box")
|
||||
self._screenshot_button_box = builder.get_object("screenshot_button_box")
|
||||
# Network.
|
||||
self._network_button = builder.get_object("control_network_button")
|
||||
self._network_model = builder.get_object("network_model")
|
||||
@@ -83,15 +84,27 @@ class ControlTool(Gtk.Box):
|
||||
|
||||
def init_actions(self, app):
|
||||
# Remote controller actions.
|
||||
app.set_action("on_one", lambda a, v: self.on_remote_action(HttpAPI.Remote.ONE))
|
||||
app.set_action("on_two", lambda a, v: self.on_remote_action(HttpAPI.Remote.TWO))
|
||||
app.set_action("on_three", lambda a, v: self.on_remote_action(HttpAPI.Remote.THREE))
|
||||
app.set_action("on_four", lambda a, v: self.on_remote_action(HttpAPI.Remote.FOUR))
|
||||
app.set_action("on_five", lambda a, v: self.on_remote_action(HttpAPI.Remote.FIVE))
|
||||
app.set_action("on_six", lambda a, v: self.on_remote_action(HttpAPI.Remote.SIX))
|
||||
app.set_action("on_seven", lambda a, v: self.on_remote_action(HttpAPI.Remote.SEVEN))
|
||||
app.set_action("on_eight", lambda a, v: self.on_remote_action(HttpAPI.Remote.EIGHT))
|
||||
app.set_action("on_nine", lambda a, v: self.on_remote_action(HttpAPI.Remote.NINE))
|
||||
app.set_action("on_zero", lambda a, v: self.on_remote_action(HttpAPI.Remote.ZERO))
|
||||
app.set_action("on_up", lambda a, v: self.on_remote_action(HttpAPI.Remote.UP))
|
||||
app.set_action("on_down", lambda a, v: self.on_remote_action(HttpAPI.Remote.DOWN))
|
||||
app.set_action("on_left", lambda a, v: self.on_remote_action(HttpAPI.Remote.LEFT))
|
||||
app.set_action("on_right", lambda a, v: self.on_remote_action(HttpAPI.Remote.RIGHT))
|
||||
app.set_action("on_next", lambda a, v: self.on_remote_action(HttpAPI.Remote.NEXT))
|
||||
app.set_action("on_back", lambda a, v: self.on_remote_action(HttpAPI.Remote.BACK))
|
||||
app.set_action("on_info", lambda a, v: self.on_remote_action(HttpAPI.Remote.INFO))
|
||||
app.set_action("on_ok", lambda a, v: self.on_remote_action(HttpAPI.Remote.OK))
|
||||
app.set_action("on_menu", lambda a, v: self.on_remote_action(HttpAPI.Remote.MENU))
|
||||
app.set_action("on_exit", lambda a, v: self.on_remote_action(HttpAPI.Remote.EXIT))
|
||||
app.set_action("on_epg", lambda a, v: self.on_remote_action(HttpAPI.Remote.EPG))
|
||||
app.set_action("on_ch_up", lambda a, v: self.on_remote_action(HttpAPI.Remote.CH_UP))
|
||||
app.set_action("on_ch_down", lambda a, v: self.on_remote_action(HttpAPI.Remote.CH_DOWN))
|
||||
app.set_action("on_red", lambda a, v: self.on_remote_action(HttpAPI.Remote.RED))
|
||||
@@ -124,6 +137,8 @@ class ControlTool(Gtk.Box):
|
||||
self._remote_box.reorder_child(children[-1], 0)
|
||||
pack_type = Gtk.PackType.END if alt_layout else Gtk.PackType.START
|
||||
self._header_box.set_child_packing(self._network_button, False, False, 0, pack_type)
|
||||
pack_type = Gtk.PackType.START if alt_layout else Gtk.PackType.END
|
||||
self._header_box.set_child_packing(self._screenshot_button_box, False, False, 0, pack_type)
|
||||
|
||||
# ***************** Remote controller ********************* #
|
||||
|
||||
@@ -243,10 +258,11 @@ class ControlTool(Gtk.Box):
|
||||
|
||||
def update_signal(self, sig):
|
||||
snr = sig.get("e2snr", "0 %").strip() if sig else "0 %"
|
||||
snr_db = sig.get("e2snrdb", "0 dB").strip() if sig else "0 dB"
|
||||
acg = sig.get("e2acg", "0 %").strip() if sig else "0 %"
|
||||
ber = (sig.get("e2ber", None) or "").strip() if sig else ""
|
||||
# Labels.
|
||||
self._snr_value_label.set_text(snr)
|
||||
self._snr_value_label.set_text(f"{snr_db} ({snr})")
|
||||
self._agc_value_label.set_text(acg)
|
||||
self._ber_value_label.set_text(ber)
|
||||
# Level bars.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018-2022 Dmitriy Yefremov
|
||||
Copyright (c) 2018-2023 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
|
||||
@@ -31,7 +31,7 @@ Author: Dmitriy Yefremov
|
||||
<!-- interface-license-type mit -->
|
||||
<!-- interface-name DemonEditor -->
|
||||
<!-- interface-description Enigma2 channel and satellites list editor. -->
|
||||
<!-- interface-copyright 2018-2022 Dmitriy Yefremov -->
|
||||
<!-- interface-copyright 2018-2023 Dmitriy Yefremov -->
|
||||
<!-- interface-authors Dmitriy Yefremov -->
|
||||
<object class="GtkAboutDialog" id="about_dialog">
|
||||
<property name="can_focus">False</property>
|
||||
@@ -40,8 +40,8 @@ Author: Dmitriy Yefremov
|
||||
<property name="icon_name">system-help</property>
|
||||
<property name="type_hint">normal</property>
|
||||
<property name="program_name">DemonEditor</property>
|
||||
<property name="version">3.1.0 Alpha</property>
|
||||
<property name="copyright">2018-2022 Dmitriy Yefremov
|
||||
<property name="version">3.3.1 Beta</property>
|
||||
<property name="copyright">2018-2023 Dmitriy Yefremov
|
||||
</property>
|
||||
<property name="comments" translatable="yes">Enigma2 channel and satellite list editor.</property>
|
||||
<property name="website">https://dyefremov.github.io/DemonEditor/</property>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2018-2022 Dmitriy Yefremov
|
||||
# Copyright (c) 2018-2023 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
|
||||
@@ -43,13 +43,13 @@ from gi.repository import GLib
|
||||
from app.commons import run_idle, run_task, run_with_delay
|
||||
from app.connections import download_data, DownloadType, HttpAPI
|
||||
from app.eparser.ecommons import BouquetService, BqServiceType
|
||||
from app.settings import SEP, EpgSource
|
||||
from app.settings import SEP, EpgSource, IS_DARWIN, IS_WIN
|
||||
from app.tools.epg import EPG, ChannelsParser, EpgEvent, XmlTvReader
|
||||
from app.ui.dialogs import get_message, show_dialog, DialogType, get_builder
|
||||
from app.ui.tasks import BGTaskWidget
|
||||
from app.ui.timers import TimerTool
|
||||
from ..main_helper import on_popup_menu, update_entry_data, scroll_to
|
||||
from ..uicommons import Gtk, Gdk, UI_RESOURCES_PATH, Column, EPG_ICON, KeyboardKey, IS_GNOME_SESSION, Page
|
||||
from ..main_helper import on_popup_menu, update_entry_data, scroll_to, update_toggle_model, update_filter_sat_positions
|
||||
from ..uicommons import Gtk, Gdk, UI_RESOURCES_PATH, Column, EPG_ICON, KeyboardKey, IS_GNOME_SESSION, Page, HeaderBar
|
||||
|
||||
|
||||
class RefsSource(Enum):
|
||||
@@ -73,13 +73,14 @@ class EpgCache(dict):
|
||||
|
||||
self.init()
|
||||
|
||||
@run_idle
|
||||
@run_with_delay(5)
|
||||
def init(self):
|
||||
if self._src is EpgSource.XML:
|
||||
url = self._settings.epg_xml_source
|
||||
gz_file = f"{self._settings.profile_data_path}epg{os.sep}epg.gz"
|
||||
self._reader = XmlTvReader(gz_file, url)
|
||||
|
||||
@run_with_delay(2)
|
||||
def process_data():
|
||||
t = BGTaskWidget(self._app, "Processing XMLTV data...", self._reader.parse, )
|
||||
self._app.emit("add-background-task", t)
|
||||
@@ -202,7 +203,9 @@ class EpgTool(Gtk.Box):
|
||||
self._current_bq = None
|
||||
self._app = app
|
||||
self._app.connect("fav-changed", self.on_service_changed)
|
||||
self._app.connect("profile-changed", self.on_profile_changed)
|
||||
self._app.connect("bouquet-changed", self.on_bouquet_changed)
|
||||
self._app.connect("filter-toggled", self.on_filter_toggled)
|
||||
|
||||
handlers = {"on_epg_press": self.on_epg_press,
|
||||
"on_timer_add": self.on_timer_add,
|
||||
@@ -217,12 +220,24 @@ class EpgTool(Gtk.Box):
|
||||
self._model = builder.get_object("epg_model")
|
||||
self._filter_model = builder.get_object("epg_filter_model")
|
||||
self._filter_model.set_visible_func(self.epg_filter_function)
|
||||
self._filter_button = builder.get_object("epg_filter_button")
|
||||
self._filter_entry = builder.get_object("epg_filter_entry")
|
||||
self._multi_epg_button = builder.get_object("multi_epg_button")
|
||||
self._event_count_label = builder.get_object("event_count_label")
|
||||
self.pack_start(builder.get_object("epg_frame"), True, True, 0)
|
||||
# Custom sort function.
|
||||
self._view.get_model().set_sort_func(2, self.time_sort_func, 2)
|
||||
# Custom data functions.
|
||||
renderer = builder.get_object("epg_start_renderer")
|
||||
column = builder.get_object("epg_start_column")
|
||||
column.set_cell_data_func(renderer, self.start_data_func)
|
||||
renderer = builder.get_object("epg_end_renderer")
|
||||
column = builder.get_object("epg_end_column")
|
||||
column.set_cell_data_func(renderer, self.end_data_func)
|
||||
renderer = builder.get_object("epg_length_renderer")
|
||||
column = builder.get_object("epg_length_column")
|
||||
column.set_cell_data_func(renderer, self.duration_data_func)
|
||||
# Time formats.
|
||||
self._time_fmt = "%a %x - %H:%M"
|
||||
self._duration_fmt = f"%{'' if IS_WIN else '-'}Hh %Mm"
|
||||
|
||||
self.show()
|
||||
|
||||
@@ -279,29 +294,40 @@ class EpgTool(Gtk.Box):
|
||||
self._app.wait_dialog.show()
|
||||
self._app.send_http_request(HttpAPI.Request.EPG, quote(ref), self.update_epg_data)
|
||||
|
||||
def on_profile_changed(self, app, prf):
|
||||
self.update_epg_data()
|
||||
|
||||
@run_idle
|
||||
def update_epg_data(self, epg):
|
||||
def update_epg_data(self, epg=None):
|
||||
self._event_count_label.set_text("0")
|
||||
self._model.clear()
|
||||
list(map(self._model.append, (self.get_event(e) for e in epg.get("event_list", [])
|
||||
if e.get("e2eventid", "").isdigit())))
|
||||
if epg:
|
||||
list(map(self._model.append, (self.get_event(e) for e in epg.get("event_list", [])
|
||||
if e.get("e2eventid", "").isdigit())))
|
||||
self._event_count_label.set_text(str(len(self._model)))
|
||||
self._app.wait_dialog.hide()
|
||||
|
||||
@staticmethod
|
||||
def get_event(event, show_day=True):
|
||||
t_str = f"{'%a, ' if show_day else ''}%x, %H:%M"
|
||||
s_name = event.get("e2eventservicename", "")
|
||||
title = event.get("e2eventtitle", "") or ""
|
||||
desc = event.get("e2eventdescription", "") or ""
|
||||
desc = desc.strip()
|
||||
start, duration = int(event.get("e2eventstart", "0")), int(event.get("e2eventduration", "0"))
|
||||
|
||||
start = int(event.get("e2eventstart", "0"))
|
||||
start_time = datetime.fromtimestamp(start)
|
||||
end_time = datetime.fromtimestamp(start + int(event.get("e2eventduration", "0")))
|
||||
ev_time = f"{start_time.strftime(t_str)} - {end_time.strftime('%H:%M')}"
|
||||
return EpgEvent(s_name, title, start, start + duration, duration, desc, event)
|
||||
|
||||
return EpgEvent(s_name, title, ev_time, desc, event)
|
||||
def start_data_func(self, column, renderer, model, itr, data):
|
||||
value = datetime.fromtimestamp(model.get_value(itr, Column.EPG_START))
|
||||
renderer.set_property("text", value.strftime(self._time_fmt))
|
||||
|
||||
def end_data_func(self, column, renderer, model, itr, data):
|
||||
value = datetime.fromtimestamp(model.get_value(itr, Column.EPG_END))
|
||||
renderer.set_property("text", value.strftime(self._time_fmt))
|
||||
|
||||
def duration_data_func(self, column, renderer, model, itr, data):
|
||||
value = datetime.utcfromtimestamp(model.get_value(itr, Column.EPG_LENGTH))
|
||||
renderer.set_property("text", value.strftime(self._duration_fmt))
|
||||
|
||||
def on_epg_filter_changed(self, entry):
|
||||
self._filter_model.refilter()
|
||||
@@ -312,14 +338,17 @@ class EpgTool(Gtk.Box):
|
||||
|
||||
def epg_filter_function(self, model, itr, data):
|
||||
txt = self._filter_entry.get_text().upper()
|
||||
return next((s for s in model.get(itr, 0, 1, 2, 3) if txt in s.upper()), False)
|
||||
return next((s for s in model.get(itr,
|
||||
Column.EPG_SERVICE,
|
||||
Column.EPG_TITLE,
|
||||
Column.EPG_DESC) if txt in s.upper()), False)
|
||||
|
||||
def time_sort_func(self, model, iter1, iter2, column):
|
||||
""" Custom sort function for time column. """
|
||||
event1 = model.get_value(iter1, 4)
|
||||
event2 = model.get_value(iter2, 4)
|
||||
|
||||
return int(event1.get("e2eventstart", "0")) - int(event2.get("e2eventstart", "0"))
|
||||
def on_filter_toggled(self, app, value):
|
||||
if self._app.page is Page.EPG:
|
||||
active = not self._filter_button.get_active()
|
||||
self._filter_button.set_active(active)
|
||||
if active:
|
||||
self._filter_entry.grab_focus()
|
||||
|
||||
def on_view_query_tooltip(self, view, x, y, keyboard_mode, tooltip):
|
||||
dst = view.get_dest_row_at_pos(x, y)
|
||||
@@ -365,7 +394,7 @@ class EpgTool(Gtk.Box):
|
||||
|
||||
class EpgDialog:
|
||||
|
||||
def __init__(self, app, bouquet, bouquet_name):
|
||||
def __init__(self, app, bouquet_name):
|
||||
|
||||
handlers = {"on_close_dialog": self.on_close_dialog,
|
||||
"on_apply": self.on_apply,
|
||||
@@ -373,6 +402,7 @@ class EpgDialog:
|
||||
"on_save_to_xml": self.on_save_to_xml,
|
||||
"on_auto_configuration": self.on_auto_configuration,
|
||||
"on_filter_toggled": self.on_filter_toggled,
|
||||
"on_filter_satellite_toggled": self.on_filter_satellite_toggled,
|
||||
"on_filter_changed": self.on_filter_changed,
|
||||
"on_info_bar_close": self.on_info_bar_close,
|
||||
"on_popup_menu": on_popup_menu,
|
||||
@@ -395,11 +425,9 @@ class EpgDialog:
|
||||
"on_bq_cursor_changed": self.on_bq_cursor_changed}
|
||||
|
||||
self._app = app
|
||||
self._services = {}
|
||||
self._ex_services = self._app.current_services
|
||||
self._ex_fav_model = self._app.fav_view.get_model()
|
||||
self._settings = self._app.app_settings
|
||||
self._bouquet = bouquet
|
||||
self._bouquet_name = bouquet_name
|
||||
self._current_ref = []
|
||||
self._enable_dat_filter = False
|
||||
@@ -407,6 +435,7 @@ class EpgDialog:
|
||||
self._update_epg_data_on_start = False
|
||||
self._refs_source = RefsSource.SERVICES
|
||||
self._download_xml_is_active = False
|
||||
self._sat_positions = None
|
||||
|
||||
builder = get_builder(f"{UI_RESOURCES_PATH}epg{SEP}dialog.glade", handlers)
|
||||
|
||||
@@ -421,12 +450,14 @@ class EpgDialog:
|
||||
self._assign_ref_popup_item = builder.get_object("bouquet_assign_ref_popup_item")
|
||||
self._left_action_box = builder.get_object("left_action_box")
|
||||
self._xml_download_progress_bar = builder.get_object("xml_download_progress_bar")
|
||||
self._src_load_spinner = builder.get_object("src_load_spinner")
|
||||
# Filter
|
||||
self._filter_bar = builder.get_object("filter_bar")
|
||||
self._filter_entry = builder.get_object("filter_entry")
|
||||
self._filter_auto_switch = builder.get_object("filter_auto_switch")
|
||||
self._services_filter_model = builder.get_object("services_filter_model")
|
||||
self._services_filter_model.set_visible_func(self.services_filter_function)
|
||||
self._sat_pos_filter_model = builder.get_object("sat_pos_filter_model")
|
||||
# Info
|
||||
self._source_count_label = builder.get_object("source_count_label")
|
||||
self._source_info_label = builder.get_object("source_info_label")
|
||||
@@ -445,9 +476,8 @@ class EpgDialog:
|
||||
self._update_on_start_switch = builder.get_object("update_on_start_switch")
|
||||
self._epg_dat_source_box = builder.get_object("epg_dat_source_box")
|
||||
|
||||
if IS_GNOME_SESSION:
|
||||
header_bar = Gtk.HeaderBar(visible=True, show_close_button=True, title="EPG",
|
||||
subtitle=get_message("List configuration"))
|
||||
if IS_GNOME_SESSION or IS_DARWIN:
|
||||
header_bar = HeaderBar(title="EPG", subtitle=get_message("List configuration"))
|
||||
self._dialog.set_titlebar(header_bar)
|
||||
builder.get_object("left_action_box").reparent(header_bar)
|
||||
right_box = builder.get_object("right_action_box")
|
||||
@@ -473,21 +503,29 @@ class EpgDialog:
|
||||
|
||||
@run_idle
|
||||
def on_apply(self, item):
|
||||
if show_dialog(DialogType.QUESTION, self._dialog) == Gtk.ResponseType.CANCEL:
|
||||
if show_dialog(DialogType.QUESTION, self._dialog) != Gtk.ResponseType.OK:
|
||||
return
|
||||
|
||||
self._bouquet.clear()
|
||||
list(map(self._bouquet.append, [r[Column.FAV_ID] for r in self._bouquet_model]))
|
||||
p_ids = {r[Column.FAV_ID]: r[Column.FAV_POS] for r in self._bouquet_model}
|
||||
for index, row in enumerate(self._ex_fav_model):
|
||||
fav_id = self._bouquet[index]
|
||||
row[Column.FAV_ID] = fav_id
|
||||
if row[Column.FAV_TYPE] == BqServiceType.IPTV.name:
|
||||
old_fav_id = self._services[fav_id]
|
||||
srv = self._ex_services.pop(old_fav_id, None)
|
||||
p = re.compile(r"\d+")
|
||||
updated = {}
|
||||
|
||||
for i, row in enumerate(self._bouquet_model):
|
||||
if row[Column.FAV_LOCKED]:
|
||||
fav_id = self._ex_fav_model[row.path][Column.FAV_ID]
|
||||
srv = self._ex_services.pop(fav_id, None)
|
||||
if srv:
|
||||
picon_id = p_ids.get(fav_id) or srv.picon_id
|
||||
self._ex_services[fav_id] = srv._replace(fav_id=fav_id, picon_id=picon_id)
|
||||
new_fav_id, picon_id = row[Column.FAV_ID], row[Column.FAV_POS]
|
||||
if picon_id:
|
||||
picon_id = re.sub(p, re.search(p, srv.picon_id).group(), picon_id, count=1)
|
||||
else:
|
||||
picon_id = srv.picon_id
|
||||
new = srv._replace(fav_id=new_fav_id, data_id=new_fav_id.strip(), picon_id=picon_id)
|
||||
self._ex_services[new_fav_id] = new
|
||||
updated[fav_id] = (srv, new)
|
||||
|
||||
if updated:
|
||||
self._app.emit("iptv-service-edited", updated)
|
||||
|
||||
self._dialog.destroy()
|
||||
|
||||
@run_idle
|
||||
@@ -503,7 +541,6 @@ class EpgDialog:
|
||||
def clear_data(self):
|
||||
self._services_model.clear()
|
||||
self._bouquet_model.clear()
|
||||
self._services.clear()
|
||||
self._source_info_label.set_text("")
|
||||
self._bouquet_epg_count_label.set_text("")
|
||||
self.on_info_bar_close()
|
||||
@@ -523,6 +560,8 @@ class EpgDialog:
|
||||
return
|
||||
yield True
|
||||
|
||||
self._src_load_spinner.start()
|
||||
|
||||
if self._refs_source is RefsSource.SERVICES:
|
||||
yield from self.init_lamedb_source(refs)
|
||||
elif self._refs_source is RefsSource.XML:
|
||||
@@ -533,13 +572,13 @@ class EpgDialog:
|
||||
self.show_info_message(str(e), Gtk.MessageType.ERROR)
|
||||
else:
|
||||
self.show_info_message("Unknown names source!", Gtk.MessageType.ERROR)
|
||||
|
||||
self._src_load_spinner.stop()
|
||||
yield True
|
||||
|
||||
def init_bouquet_data(self):
|
||||
for r in self._ex_fav_model:
|
||||
row = [*r[:]]
|
||||
fav_id = r[Column.FAV_ID]
|
||||
self._services[fav_id] = self._ex_services[fav_id].fav_id
|
||||
yield self._bouquet_model.append(row)
|
||||
self._bouquet_count_label.set_text(str(len(self._bouquet_model)))
|
||||
yield True
|
||||
@@ -689,7 +728,7 @@ class EpgDialog:
|
||||
tr = {ord(k): ord(v) for k, v in zip(*symbols)}
|
||||
|
||||
source = {}
|
||||
for row in self._services_model:
|
||||
for row in self._source_view.get_model():
|
||||
name = re.sub("\\W+", "", str(row[0])).upper()
|
||||
name = name.translate(tr) if use_cyrillic else name
|
||||
source[name] = row
|
||||
@@ -735,33 +774,45 @@ class EpgDialog:
|
||||
fav_id = row[Column.FAV_ID]
|
||||
fav_id_data = fav_id.split(":")
|
||||
fav_id_data[3:7] = data[-2].split(":")
|
||||
|
||||
if data[-1]:
|
||||
row[Column.FAV_POS] = data[-1]
|
||||
p_data = data[-1].split("_")
|
||||
if p_data:
|
||||
fav_id_data[2] = p_data[2]
|
||||
|
||||
new_fav_id = ":".join(fav_id_data)
|
||||
service = self._services.pop(fav_id, None)
|
||||
if service:
|
||||
self._services[new_fav_id] = service
|
||||
row[Column.FAV_ID] = new_fav_id
|
||||
row[Column.FAV_LOCKED] = EPG_ICON
|
||||
if data[-1]:
|
||||
row[Column.FAV_POS] = data[-1]
|
||||
p_data = data[-1].split("_")
|
||||
if p_data:
|
||||
fav_id_data[2] = p_data[2]
|
||||
pos = f"({data[1] if self._refs_source is RefsSource.SERVICES else 'XML'})"
|
||||
src = f"{get_message('EPG source')}: {(GLib.markup_escape_text(data[0] or ''))} {pos}"
|
||||
row[Column.FAV_TOOLTIP] = f"{get_message('Service reference')}: {':'.join(fav_id_data[:10])}\n{src}"
|
||||
row[Column.FAV_ID] = new_fav_id
|
||||
row[Column.FAV_LOCKED] = EPG_ICON
|
||||
|
||||
pos = f"({data[1] if self._refs_source is RefsSource.SERVICES else 'XML'})"
|
||||
src = f"{get_message('EPG source')}: {(GLib.markup_escape_text(data[0] or ''))} {pos}"
|
||||
row[Column.FAV_TOOLTIP] = f"{get_message('Service reference')}: {':'.join(fav_id_data[:10])}\n{src}"
|
||||
|
||||
def on_filter_toggled(self, button):
|
||||
self._filter_bar.set_visible(button.get_active())
|
||||
if not button.get_active():
|
||||
self._filter_entry.set_text("")
|
||||
if button.get_active():
|
||||
self._sat_positions = {r[1] for r in self._services_model}
|
||||
update_filter_sat_positions(self._sat_pos_filter_model, self._sat_positions)
|
||||
else:
|
||||
self._sat_positions = None
|
||||
self._filter_entry.set_text("") if self._filter_entry.get_text() else self.on_filter_changed()
|
||||
|
||||
@run_with_delay(1)
|
||||
def on_filter_changed(self, entry):
|
||||
def on_filter_satellite_toggled(self, toggle, path):
|
||||
update_toggle_model(self._sat_pos_filter_model, path, toggle)
|
||||
self._sat_positions.clear()
|
||||
self._sat_positions.update({r[0] for r in self._sat_pos_filter_model if r[1]})
|
||||
self.on_filter_changed()
|
||||
|
||||
@run_with_delay(2)
|
||||
def on_filter_changed(self, entry=None):
|
||||
self._services_filter_model.refilter()
|
||||
|
||||
def services_filter_function(self, model, itr, data):
|
||||
txt = self._filter_entry.get_text().upper()
|
||||
return model is None or model == "None" or txt in model.get_value(itr, 0).upper()
|
||||
pos = model.get_value(itr, 1)
|
||||
pos = self._sat_positions is None or self._xml_radiobutton.get_active() or pos in self._sat_positions
|
||||
return model is None or model == "None" or (txt in model.get_value(itr, 0).upper() and pos)
|
||||
|
||||
def on_info_bar_close(self, bar=None, resp=None):
|
||||
self._info_bar.set_visible(False)
|
||||
@@ -791,10 +842,7 @@ class EpgDialog:
|
||||
self.update_epg_count()
|
||||
|
||||
def reset_row_data(self, row):
|
||||
default_fav_id = self._services.pop(row[Column.FAV_ID], None)
|
||||
if default_fav_id:
|
||||
self._services[default_fav_id] = default_fav_id
|
||||
row[Column.FAV_ID], row[Column.FAV_LOCKED], row[Column.FAV_TOOLTIP] = default_fav_id, None, None
|
||||
row[Column.FAV_LOCKED], row[Column.FAV_TOOLTIP], row[Column.FAV_POS] = None, None, None
|
||||
|
||||
@run_idle
|
||||
def show_info_message(self, text, message_type):
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.22.2
|
||||
<!-- Generated with glade 3.38.2
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018-2022 Dmitriy Yefremov
|
||||
Copyright (c) 2018-2023 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,12 +26,13 @@ THE SOFTWARE.
|
||||
Author: Dmitriy Yefremov
|
||||
|
||||
-->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.16"/>
|
||||
<interface domain="demon-editor">
|
||||
<requires lib="gtk+" version="3.22"/>
|
||||
<!-- 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-2022 Dmitriy Yefremov -->
|
||||
<!-- interface-copyright 2018-2023 Dmitriy Yefremov -->
|
||||
<!-- interface-authors Dmitriy Yefremov -->
|
||||
<object class="GtkListStore" id="epg_model">
|
||||
<columns>
|
||||
@@ -39,8 +40,12 @@ Author: Dmitriy Yefremov
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name title -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name time -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name start -->
|
||||
<column type="gint"/>
|
||||
<!-- column-name end -->
|
||||
<column type="gint"/>
|
||||
<!-- column-name length -->
|
||||
<column type="gint"/>
|
||||
<!-- column-name description -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name data -->
|
||||
@@ -48,49 +53,62 @@ Author: Dmitriy Yefremov
|
||||
</columns>
|
||||
</object>
|
||||
<object class="GtkTreeModelFilter" id="epg_filter_model">
|
||||
<property name="child_model">epg_model</property>
|
||||
<property name="child-model">epg_model</property>
|
||||
</object>
|
||||
<object class="GtkTreeModelSort" id="epg_sort_model">
|
||||
<property name="model">epg_filter_model</property>
|
||||
</object>
|
||||
<object class="GtkFrame" id="epg_frame">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label_xalign">0.49000000953674316</property>
|
||||
<property name="shadow_type">in</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label-xalign">0.49</property>
|
||||
<property name="shadow-type">in</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="epg_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">5</property>
|
||||
<property name="margin_right">5</property>
|
||||
<property name="margin_top">2</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">2</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="epg_action_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">5</property>
|
||||
<property name="margin_right">5</property>
|
||||
<property name="margin_top">5</property>
|
||||
<property name="margin_bottom">5</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="border-width">5</property>
|
||||
<property name="spacing">5</property>
|
||||
<child type="center">
|
||||
<object class="GtkToggleButton" id="multi_epg_button">
|
||||
<property name="label" translatable="yes">Multi EPG</property>
|
||||
<property name="name">header-button</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="receives-default">True</property>
|
||||
<signal name="toggled" handler="on_multi_epg_toggled" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="src_combo_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="tooltip_text" translatable="yes">EPG source</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="tooltip-text" translatable="yes">EPG source</property>
|
||||
<property name="active">0</property>
|
||||
<property name="has_entry">True</property>
|
||||
<property name="active_id">0</property>
|
||||
<property name="has-entry">True</property>
|
||||
<property name="active-id">0</property>
|
||||
<items>
|
||||
<item id="0" translatable="yes">Receiver</item>
|
||||
</items>
|
||||
<child internal-child="entry">
|
||||
<object class="GtkEntry">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="name">header-entry</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="editable">False</property>
|
||||
<property name="width_chars">10</property>
|
||||
<property name="width-chars">10</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
@@ -103,16 +121,16 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="epg_filter_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="focus_on_click">False</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Filter</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="focus-on-click">False</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="tooltip-text" translatable="yes">Filter</property>
|
||||
<signal name="toggled" handler="on_epg_filter_toggled" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="epg_filter_button_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">edit-find-replace-symbolic</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="icon-name">edit-find-replace-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
@@ -125,17 +143,17 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkButton" id="epg_add_timer_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="focus_on_click">False</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Add timer</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="focus-on-click">False</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="tooltip-text" translatable="yes">Add timer</property>
|
||||
<property name="always-show-image">True</property>
|
||||
<signal name="clicked" handler="on_timer_add" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="add_timer_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">alarm-symbolic</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="icon-name">alarm-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
@@ -145,20 +163,6 @@ Author: Dmitriy Yefremov
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child type="center">
|
||||
<object class="GtkToggleButton" id="multi_epg_button">
|
||||
<property name="label" translatable="yes">Multi EPG</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="receives_default">True</property>
|
||||
<signal name="toggled" handler="on_multi_epg_toggled" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
@@ -169,18 +173,18 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkBox" id="epg_fs_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">5</property>
|
||||
<property name="margin_right">5</property>
|
||||
<property name="margin_bottom">5</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkSearchEntry" id="epg_filter_entry">
|
||||
<property name="can_focus">True</property>
|
||||
<property name="primary_icon_name">edit-find-replace-symbolic</property>
|
||||
<property name="primary_icon_activatable">False</property>
|
||||
<property name="primary_icon_sensitive">False</property>
|
||||
<property name="visible" bind-source="epg_filter_button" bind-property="active"/>
|
||||
<property name="visible" bind-source="epg_filter_button" bind-property="active">False</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="primary-icon-name">edit-find-replace-symbolic</property>
|
||||
<property name="primary-icon-activatable">False</property>
|
||||
<property name="primary-icon-sensitive">False</property>
|
||||
<signal name="search-changed" handler="on_epg_filter_changed" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
@@ -191,15 +195,15 @@ Author: Dmitriy Yefremov
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="fav_search_box">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="valign">center</property>
|
||||
<child>
|
||||
<object class="GtkSearchEntry" id="epg_search_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="primary_icon_name">edit-find-symbolic</property>
|
||||
<property name="primary_icon_activatable">False</property>
|
||||
<property name="primary_icon_sensitive">False</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="primary-icon-name">edit-find-symbolic</property>
|
||||
<property name="primary-icon-activatable">False</property>
|
||||
<property name="primary-icon-sensitive">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
@@ -211,13 +215,13 @@ Author: Dmitriy Yefremov
|
||||
<object class="GtkButton" id="epg_search_down_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<child>
|
||||
<object class="GtkArrow" id="epg_down_arrow">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="arrow_type">down</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="arrow-type">down</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
@@ -231,13 +235,13 @@ Author: Dmitriy Yefremov
|
||||
<object class="GtkButton" id="epg_search_up_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<child>
|
||||
<object class="GtkArrow" id="epg_up_arrow">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="arrow_type">up</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="arrow-type">up</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
@@ -267,18 +271,17 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="epg_view_scrolled_window">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="shadow_type">in</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="shadow-type">in</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="epg_view">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="model">epg_sort_model</property>
|
||||
<property name="rules_hint">True</property>
|
||||
<property name="fixed_height_mode">True</property>
|
||||
<property name="rubber_banding">True</property>
|
||||
<property name="enable_grid_lines">both</property>
|
||||
<property name="tooltip_column">3</property>
|
||||
<property name="fixed-height-mode">True</property>
|
||||
<property name="rubber-banding">True</property>
|
||||
<property name="enable-grid-lines">both</property>
|
||||
<property name="tooltip-column">6</property>
|
||||
<signal name="button-press-event" handler="on_epg_press" swapped="no"/>
|
||||
<signal name="query-tooltip" handler="on_view_query_tooltip" swapped="no"/>
|
||||
<child internal-child="selection">
|
||||
@@ -288,15 +291,14 @@ Author: Dmitriy Yefremov
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="epg_service_column">
|
||||
<property name="visible">False</property>
|
||||
<property name="visible" bind-source="multi_epg_button" bind-property="active">False</property>
|
||||
<property name="resizable">True</property>
|
||||
<property name="sizing">fixed</property>
|
||||
<property name="fixed_width">100</property>
|
||||
<property name="min_width">40</property>
|
||||
<property name="fixed-width">100</property>
|
||||
<property name="min-width">40</property>
|
||||
<property name="title" translatable="yes">Service</property>
|
||||
<property name="alignment">0.49000000953674316</property>
|
||||
<property name="sort_column_id">0</property>
|
||||
<property name="visible" bind-source="multi_epg_button" bind-property="active"/>
|
||||
<property name="alignment">0.49</property>
|
||||
<property name="sort-column-id">0</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="epg_service_renderer">
|
||||
<property name="xpad">5</property>
|
||||
@@ -311,11 +313,10 @@ Author: Dmitriy Yefremov
|
||||
<object class="GtkTreeViewColumn" id="epg_title_column">
|
||||
<property name="resizable">True</property>
|
||||
<property name="sizing">fixed</property>
|
||||
<property name="fixed_width">170</property>
|
||||
<property name="min_width">50</property>
|
||||
<property name="min-width">150</property>
|
||||
<property name="title" translatable="yes">Title</property>
|
||||
<property name="alignment">0.49000000953674316</property>
|
||||
<property name="sort_column_id">1</property>
|
||||
<property name="alignment">0.49</property>
|
||||
<property name="sort-column-id">1</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="epg_title_renderer">
|
||||
<property name="xpad">5</property>
|
||||
@@ -327,18 +328,18 @@ Author: Dmitriy Yefremov
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="epg_time_column">
|
||||
<object class="GtkTreeViewColumn" id="epg_start_column">
|
||||
<property name="resizable">True</property>
|
||||
<property name="sizing">fixed</property>
|
||||
<property name="fixed_width">210</property>
|
||||
<property name="min_width">50</property>
|
||||
<property name="title" translatable="yes">Time</property>
|
||||
<property name="alignment">0.49000000953674316</property>
|
||||
<property name="sort_column_id">2</property>
|
||||
<property name="min-width">50</property>
|
||||
<property name="title" translatable="yes">Start time</property>
|
||||
<property name="alignment">0.49</property>
|
||||
<property name="sort-column-id">2</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="epg_time_renderer">
|
||||
<object class="GtkCellRendererText" id="epg_start_renderer">
|
||||
<property name="xpad">5</property>
|
||||
<property name="xalign">0.49000000953674316</property>
|
||||
<property name="xalign">0.49</property>
|
||||
<property name="width-chars">27</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="text">2</attribute>
|
||||
@@ -346,21 +347,60 @@ Author: Dmitriy Yefremov
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="epg_end_column">
|
||||
<property name="resizable">True</property>
|
||||
<property name="sizing">fixed</property>
|
||||
<property name="min-width">50</property>
|
||||
<property name="title" translatable="yes">End time</property>
|
||||
<property name="alignment">0.49</property>
|
||||
<property name="sort-column-id">3</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="epg_end_renderer">
|
||||
<property name="xpad">5</property>
|
||||
<property name="xalign">0.49</property>
|
||||
<property name="width-chars">27</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="text">3</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="epg_length_column">
|
||||
<property name="resizable">True</property>
|
||||
<property name="sizing">fixed</property>
|
||||
<property name="fixed-width">100</property>
|
||||
<property name="min-width">50</property>
|
||||
<property name="title" translatable="yes">Length</property>
|
||||
<property name="alignment">0.49</property>
|
||||
<property name="sort-column-id">4</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="epg_length_renderer">
|
||||
<property name="xpad">5</property>
|
||||
<property name="xalign">0.49</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="text">4</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="epg_desc_column">
|
||||
<property name="sizing">fixed</property>
|
||||
<property name="fixed_width">100</property>
|
||||
<property name="min_width">50</property>
|
||||
<property name="min-width">100</property>
|
||||
<property name="title" translatable="yes">Description</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="alignment">0.49000000953674316</property>
|
||||
<property name="sort_column_id">3</property>
|
||||
<property name="alignment">0.49</property>
|
||||
<property name="sort-column-id">5</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="epg_desc_renderer">
|
||||
<property name="ellipsize">end</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="text">3</attribute>
|
||||
<attribute name="text">5</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
@@ -376,17 +416,17 @@ Author: Dmitriy Yefremov
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="status_box">
|
||||
<property name="height_request">26</property>
|
||||
<property name="height-request">26</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">5</property>
|
||||
<property name="margin_right">5</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="spacing">5</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="event_count_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">document-properties</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="icon-name">document-properties</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
@@ -397,9 +437,9 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkLabel" id="event_count_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">0</property>
|
||||
<property name="width_chars">4</property>
|
||||
<property name="width-chars">4</property>
|
||||
<property name="xalign">0</property>
|
||||
</object>
|
||||
<packing>
|
||||
@@ -420,7 +460,7 @@ Author: Dmitriy Yefremov
|
||||
<child type="label">
|
||||
<object class="GtkLabel" id="epg_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">EPG</property>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018-2022 Dmitriy Yefremov
|
||||
Copyright (c) 2018-2023 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
|
||||
@@ -27,11 +27,12 @@ Author: Dmitriy Yefremov
|
||||
|
||||
-->
|
||||
<interface domain="demon-editor">
|
||||
<requires lib="gtk+" version="3.20"/>
|
||||
<requires lib="gtk+" version="3.22"/>
|
||||
<!-- interface-css-provider-path style.css -->
|
||||
<!-- interface-license-type mit -->
|
||||
<!-- interface-name DemonEditor -->
|
||||
<!-- interface-description Enigma2 channel and satellite list editor. -->
|
||||
<!-- interface-copyright 2018-2022 Dmitriy Yefremov -->
|
||||
<!-- interface-copyright 2018-2023 Dmitriy Yefremov -->
|
||||
<!-- interface-authors Dmitriy Yefremov -->
|
||||
<object class="GtkListStore" id="bq_list_store">
|
||||
<columns>
|
||||
@@ -83,6 +84,35 @@ Author: Dmitriy Yefremov
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkImage" id="remove_selection_image1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="icon-name">edit-undo</property>
|
||||
</object>
|
||||
<object class="GtkMenu" id="sat_popup_menu">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="sat_select_all_popup_item">
|
||||
<property name="label">gtk-select-all</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_select_all" object="sat_view" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="sat_unselect_all_popup_item">
|
||||
<property name="label" translatable="yes">Remove selection</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="image">remove_selection_image1</property>
|
||||
<property name="use-stock">False</property>
|
||||
<signal name="activate" handler="on_unselect_all" object="sat_view" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkImage" id="remove_services_selection_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
@@ -112,6 +142,16 @@ Author: Dmitriy Yefremov
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkListStore" id="sat_list_store">
|
||||
<columns>
|
||||
<!-- column-name position -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name type -->
|
||||
<column type="gchararray"/>
|
||||
<!-- column-name selected -->
|
||||
<column type="gboolean"/>
|
||||
</columns>
|
||||
</object>
|
||||
<object class="GtkListStore" id="services_list_store">
|
||||
<columns>
|
||||
<!-- column-name name -->
|
||||
@@ -149,15 +189,28 @@ Author: Dmitriy Yefremov
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<child>
|
||||
<object class="GtkButtonBox" id="actions_box">
|
||||
<object class="GtkBox" id="actions_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="margin-left">15</property>
|
||||
<property name="margin-right">15</property>
|
||||
<property name="margin-start">15</property>
|
||||
<property name="margin-end">15</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<property name="layout-style">start</property>
|
||||
<property name="spacing">5</property>
|
||||
<child type="center">
|
||||
<object class="GtkStackSwitcher" id="stack_switcher">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="tooltip-text" translatable="yes">Group by</property>
|
||||
<property name="stack">stack</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="import_button">
|
||||
<property name="label" translatable="yes">Import</property>
|
||||
@@ -165,33 +218,69 @@ Author: Dmitriy Yefremov
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="tooltip-text" translatable="yes">Bouquets and services</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="image">import_image</property>
|
||||
<property name="always-show-image">True</property>
|
||||
<signal name="clicked" handler="on_import" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="details_button">
|
||||
<property name="label" translatable="yes">Details</property>
|
||||
<object class="GtkBox" id="extra_header_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="focus-on-click">False</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="image">details_image</property>
|
||||
<property name="always-show-image">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="spacing">5</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="replace_existing_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">Replace existing</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="replace_existing_switch">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="valign">center</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="details_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="focus-on-click">False</property>
|
||||
<property name="receives-default">True</property>
|
||||
<property name="tooltip-text" translatable="yes">Details</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="image">details_image</property>
|
||||
<property name="always-show-image">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="pack-type">end</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="pack-type">end</property>
|
||||
<property name="position">1</property>
|
||||
<property name="secondary">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
@@ -212,125 +301,140 @@ Author: Dmitriy Yefremov
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkPaned" id="main_paned">
|
||||
<object class="GtkPaned" id="paned">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<property name="wide-handle">True</property>
|
||||
<signal name="realize" handler="on_main_paned_realize" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkFrame" id="bouquets_box_frame">
|
||||
<object class="GtkStack" id="stack">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label-xalign">0.49000000953674316</property>
|
||||
<property name="shadow-type">in</property>
|
||||
<signal name="notify::visible-child-name" handler="on_visible_page" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkBox" id="bouquets_box">
|
||||
<property name="width-request">100</property>
|
||||
<object class="GtkFrame" id="bouquets_box_frame">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="label-xalign">0.49000000953674316</property>
|
||||
<property name="shadow-type">in</property>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="bouquets_screlled_window">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="shadow-type">in</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="bq_view">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="model">bq_list_store</property>
|
||||
<property name="headers-clickable">False</property>
|
||||
<property name="search-column">0</property>
|
||||
<signal name="button-press-event" handler="on_popup_menu" object="bq_popup_menu" swapped="no"/>
|
||||
<signal name="cursor-changed" handler="on_cursor_changed" swapped="no"/>
|
||||
<signal name="key-press-event" handler="on_key_press" swapped="no"/>
|
||||
<signal name="select-all" handler="on_select_all" swapped="no"/>
|
||||
<child internal-child="selection">
|
||||
<object class="GtkTreeSelection">
|
||||
<property name="mode">multiple</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="bouquet_name_column">
|
||||
<property name="title" translatable="yes">Name</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="alignment">0.5</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="bq_name_renderer">
|
||||
<property name="xalign">0.019999999552965164</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="text">0</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="bouquet_type_column">
|
||||
<property name="title" translatable="yes">Type</property>
|
||||
<property name="alignment">0.5</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="bq_type_renderer">
|
||||
<property name="xalign">0.5099999904632568</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="text">1</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="bouquet_selected_column">
|
||||
<property name="title" translatable="yes">Selected</property>
|
||||
<property name="alignment">0.5</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererToggle" id="bq_selected_renderer">
|
||||
<signal name="toggled" handler="on_bq_selected_toggled" swapped="no"/>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="active">2</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="bouquets_status_box">
|
||||
<property name="height-request">26</property>
|
||||
<object class="GtkBox" id="bouquets_box">
|
||||
<property name="width-request">100</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="spacing">5</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="bouquets_count_image">
|
||||
<object class="GtkScrolledWindow" id="bouquets_screlled_window">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="icon-name">document-properties</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="shadow-type">in</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="bq_view">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="model">bq_list_store</property>
|
||||
<property name="headers-clickable">False</property>
|
||||
<property name="search-column">0</property>
|
||||
<signal name="button-press-event" handler="on_popup_menu" object="bq_popup_menu" swapped="no"/>
|
||||
<signal name="cursor-changed" handler="on_cursor_changed" swapped="no"/>
|
||||
<signal name="key-press-event" handler="on_key_press" swapped="no"/>
|
||||
<signal name="select-all" handler="on_select_all" swapped="no"/>
|
||||
<child internal-child="selection">
|
||||
<object class="GtkTreeSelection"/>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="bouquet_name_column">
|
||||
<property name="title" translatable="yes">Name</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="alignment">0.5</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="bq_name_renderer">
|
||||
<property name="xalign">0.019999999552965164</property>
|
||||
<property name="ellipsize">end</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="text">0</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="bouquet_type_column">
|
||||
<property name="title" translatable="yes">Type</property>
|
||||
<property name="alignment">0.5</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="bq_type_renderer">
|
||||
<property name="xalign">0.5099999904632568</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="text">1</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="bouquet_selected_column">
|
||||
<property name="title" translatable="yes">Selected</property>
|
||||
<property name="alignment">0.5</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererToggle" id="bq_selected_renderer">
|
||||
<signal name="toggled" handler="on_bq_selected_toggled" swapped="no"/>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="active">2</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="bouquets_count_label">
|
||||
<object class="GtkBox" id="bouquets_status_box">
|
||||
<property name="height-request">26</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label">0</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="spacing">5</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="bouquets_count_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="icon-name">document-properties</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="bouquets_count_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label">0</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
@@ -338,35 +442,163 @@ Author: Dmitriy Yefremov
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child type="label">
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<property name="label" translatable="yes">Bouquets</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="name">services</property>
|
||||
<property name="title" translatable="yes">Bouquets</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child type="label">
|
||||
<object class="GtkLabel">
|
||||
<child>
|
||||
<object class="GtkFrame" id="sat_box_frame">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<property name="label" translatable="yes">Bouquets</property>
|
||||
<property name="label-xalign">0.49000000953674316</property>
|
||||
<property name="shadow-type">in</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="satellites_box">
|
||||
<property name="width-request">100</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="satellites_screlled_window">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="shadow-type">in</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="sat_view">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="model">sat_list_store</property>
|
||||
<property name="headers-clickable">False</property>
|
||||
<property name="search-column">0</property>
|
||||
<signal name="button-press-event" handler="on_popup_menu" object="sat_popup_menu" swapped="no"/>
|
||||
<signal name="cursor-changed" handler="on_cursor_changed" swapped="no"/>
|
||||
<signal name="key-press-event" handler="on_key_press" swapped="no"/>
|
||||
<signal name="realize" handler="on_sat_view_realize" swapped="no"/>
|
||||
<signal name="select-all" handler="on_select_all" swapped="no"/>
|
||||
<child internal-child="selection">
|
||||
<object class="GtkTreeSelection"/>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="sat_position_column">
|
||||
<property name="title" translatable="yes">Position</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="alignment">0.5</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="sat_position_renderer">
|
||||
<property name="xalign">0.019999999552965164</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="text">0</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="sat_selected_column">
|
||||
<property name="title" translatable="yes">Selected</property>
|
||||
<property name="alignment">0.5</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererToggle" id="sat_selected_renderer">
|
||||
<signal name="toggled" handler="on_sat_selected_toggled" swapped="no"/>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="active">2</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="sat_status_box">
|
||||
<property name="height-request">26</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="spacing">5</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="sat_count_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="icon-name">document-properties</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="sat_count_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label">0</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label">
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<property name="label" translatable="yes">Satellites</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="name">satellite</property>
|
||||
<property name="title" translatable="yes">Satellites</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="resize">True</property>
|
||||
<property name="shrink">True</property>
|
||||
<property name="resize">False</property>
|
||||
<property name="shrink">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkFrame" id="services_box_frame">
|
||||
<object class="GtkFrame" id="bq_services_box_frame">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label-xalign">0.49000000953674316</property>
|
||||
@@ -401,7 +633,9 @@ Author: Dmitriy Yefremov
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="service_name_column">
|
||||
<property name="title" translatable="yes">Service</property>
|
||||
<property name="sizing">fixed</property>
|
||||
<property name="min-width">50</property>
|
||||
<property name="title" translatable="yes">Name</property>
|
||||
<property name="expand">True</property>
|
||||
<property name="alignment">0.5</property>
|
||||
<child>
|
||||
@@ -418,10 +652,13 @@ Author: Dmitriy Yefremov
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="service_type_column">
|
||||
<property name="sizing">fixed</property>
|
||||
<property name="min-width">75</property>
|
||||
<property name="title" translatable="yes">Type</property>
|
||||
<property name="alignment">0.5</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="info_type_renderer">
|
||||
<property name="xpad">5</property>
|
||||
<property name="xalign">0.5099999904632568</property>
|
||||
</object>
|
||||
<attributes>
|
||||
@@ -433,10 +670,13 @@ Author: Dmitriy Yefremov
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="service_selected_column">
|
||||
<property name="sizing">fixed</property>
|
||||
<property name="min-width">75</property>
|
||||
<property name="title" translatable="yes">Selected</property>
|
||||
<property name="alignment">0.5</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererToggle" id="service_selected_renderer">
|
||||
<property name="xpad">5</property>
|
||||
<signal name="toggled" handler="on_service_selected_toggled" swapped="no"/>
|
||||
</object>
|
||||
<attributes>
|
||||
@@ -579,7 +819,7 @@ Author: Dmitriy Yefremov
|
||||
<property name="can-focus">False</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<property name="label" translatable="yes">Bouquet details</property>
|
||||
<property name="label" translatable="yes">Services</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2018-2022 Dmitriy Yefremov
|
||||
# Copyright (c) 2018-2023 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
|
||||
@@ -37,7 +37,7 @@ from app.eparser.neutrino.bouquets import parse_webtv, parse_bouquets as get_neu
|
||||
from app.settings import SettingsType, IS_DARWIN, SEP
|
||||
from app.ui.dialogs import show_dialog, DialogType, get_chooser_dialog, get_message, get_builder
|
||||
from app.ui.main_helper import on_popup_menu, get_iptv_data
|
||||
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, KeyboardKey, Column
|
||||
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, KeyboardKey, Column, IS_GNOME_SESSION, Page, HeaderBar
|
||||
|
||||
|
||||
def import_bouquet(app, model, path, appender, file_path=None):
|
||||
@@ -109,21 +109,26 @@ class ImportDialog:
|
||||
"on_cursor_changed": self.on_cursor_changed,
|
||||
"on_service_changed": self.on_service_changed,
|
||||
"on_bq_selected_toggled": self.on_bq_selected_toggled,
|
||||
"on_sat_selected_toggled": self.on_sat_selected_toggled,
|
||||
"on_service_selected_toggled": self.on_service_selected_toggled,
|
||||
"on_services_model_changed": self.on_services_model_changed,
|
||||
"on_info_bar_close": self.on_info_bar_close,
|
||||
"on_select_all": self.on_select_all,
|
||||
"on_unselect_all": self.on_unselect_all,
|
||||
"on_sat_view_realize": self.on_sat_view_realize,
|
||||
"on_services_view_realize": self.on_services_view_realize,
|
||||
"on_popup_menu": on_popup_menu,
|
||||
"on_resize": self.on_resize,
|
||||
"on_main_paned_realize": self.on_main_paned_realize,
|
||||
"on_visible_page": self.on_visible_page,
|
||||
"on_key_press": self.on_key_press}
|
||||
|
||||
builder = get_builder(f"{UI_RESOURCES_PATH}imports.glade", handlers)
|
||||
|
||||
self._app = app
|
||||
self._bq_services = {}
|
||||
self._services = {}
|
||||
self._bq_services = {}
|
||||
self._sat_services = defaultdict(list)
|
||||
self._ids = self._app.current_services.keys()
|
||||
self._skip_import = defaultdict(set)
|
||||
self._append = appender
|
||||
@@ -131,20 +136,44 @@ class ImportDialog:
|
||||
self._settings = app.app_settings
|
||||
self._bouquets = bouquets
|
||||
self._current_bq = None
|
||||
self._current_sat = None
|
||||
self._existing_srv_background = None
|
||||
self._page = Page.SERVICES
|
||||
|
||||
self._dialog_window = builder.get_object("dialog_window")
|
||||
self._dialog_window.set_transient_for(app.app_window)
|
||||
self._info_bar = builder.get_object("info_bar")
|
||||
self._message_label = builder.get_object("message_label")
|
||||
self._replace_existing_switch = builder.get_object("replace_existing_switch")
|
||||
# Bouquets page.
|
||||
self._bq_model = builder.get_object("bq_list_store")
|
||||
self._bq_view = builder.get_object("bq_view")
|
||||
self._services_view = builder.get_object("services_view")
|
||||
self._services_model = builder.get_object("services_list_store")
|
||||
self._info_bar = builder.get_object("info_bar")
|
||||
self._message_label = builder.get_object("message_label")
|
||||
self._bouquets_count_label = builder.get_object("bouquets_count_label")
|
||||
self._services_count_label = builder.get_object("services_count_label")
|
||||
self._service_info_label = builder.get_object("service_info_label")
|
||||
self._service_exists_frame = builder.get_object("service_exists_frame")
|
||||
# Satellites page.
|
||||
self._sat_view = builder.get_object("sat_view")
|
||||
self._sat_model = builder.get_object("sat_list_store")
|
||||
self._sat_count_label = builder.get_object("sat_count_label")
|
||||
|
||||
if IS_GNOME_SESSION or IS_DARWIN:
|
||||
actions_box = builder.get_object("actions_box")
|
||||
builder.get_object("toolbar_box").set_visible(False)
|
||||
header_bar = HeaderBar()
|
||||
stack_switcher = builder.get_object("stack_switcher")
|
||||
actions_box.remove(stack_switcher)
|
||||
header_bar.set_custom_title(stack_switcher)
|
||||
button = builder.get_object("import_button")
|
||||
actions_box.remove(button)
|
||||
header_bar.pack_start(button)
|
||||
extra_box = builder.get_object("extra_header_box")
|
||||
actions_box.remove(extra_box)
|
||||
header_bar.pack_end(extra_box)
|
||||
|
||||
self._dialog_window.set_titlebar(header_bar)
|
||||
|
||||
window_size = self._settings.get("import_dialog_window_size")
|
||||
if window_size:
|
||||
@@ -184,17 +213,20 @@ class ImportDialog:
|
||||
self.show_info_message(str(e), Gtk.MessageType.ERROR)
|
||||
|
||||
def on_import(self, item):
|
||||
if not any(r[-1] for r in self._bq_model):
|
||||
self.show_info_message(get_message("No selected item!"), Gtk.MessageType.ERROR)
|
||||
return
|
||||
if self._page is Page.SERVICES:
|
||||
if not any(r[-1] for r in self._bq_model):
|
||||
self.show_info_message(get_message("No selected item!"), Gtk.MessageType.ERROR)
|
||||
return
|
||||
|
||||
if not self._bouquets or show_dialog(DialogType.QUESTION, self._dialog_window) == Gtk.ResponseType.CANCEL:
|
||||
return
|
||||
if not self._bouquets or show_dialog(DialogType.QUESTION, self._dialog_window) != Gtk.ResponseType.OK:
|
||||
return
|
||||
|
||||
self.import_data()
|
||||
self.import_bouquets_data()
|
||||
else:
|
||||
self.import_satellites_data()
|
||||
|
||||
@run_idle
|
||||
def import_data(self):
|
||||
def import_bouquets_data(self):
|
||||
""" Importing data into models. """
|
||||
if not self._bouquets:
|
||||
return
|
||||
@@ -228,8 +260,37 @@ class ImportDialog:
|
||||
with suppress(ValueError):
|
||||
bq.remove(b)
|
||||
|
||||
services = list(filter(lambda s: s.fav_id not in self._ids, services))
|
||||
self._append(self._bouquets, services)
|
||||
self._append(self._bouquets, list(filter(lambda s: s.fav_id not in self._ids, services)))
|
||||
|
||||
if self._replace_existing_switch.get_active():
|
||||
self._app.emit("services_update", {s.fav_id: s for s in filter(lambda s: s.fav_id in self._ids, services)})
|
||||
|
||||
self._dialog_window.destroy()
|
||||
|
||||
def import_satellites_data(self):
|
||||
if show_dialog(DialogType.QUESTION, self._dialog_window) != Gtk.ResponseType.OK:
|
||||
return
|
||||
|
||||
replace_existing = self._replace_existing_switch.get_active()
|
||||
services = []
|
||||
current_services = self._app.current_services
|
||||
to_replace = {}
|
||||
|
||||
for row in self._sat_model:
|
||||
if row[-1]:
|
||||
sat = (row[0], row[1])
|
||||
skip = self._skip_import[sat]
|
||||
for s in filter(lambda srv: srv.fav_id not in skip, self._sat_services.get(sat[0], ())):
|
||||
if replace_existing and s.fav_id in self._ids:
|
||||
current_services[s.fav_id] = s
|
||||
to_replace[s.fav_id] = s
|
||||
elif s.fav_id not in self._ids:
|
||||
services.append(s)
|
||||
|
||||
self._append((), services)
|
||||
if to_replace:
|
||||
self._app.emit("services_update", to_replace)
|
||||
|
||||
self._dialog_window.destroy()
|
||||
|
||||
@run_idle
|
||||
@@ -240,7 +301,16 @@ class ImportDialog:
|
||||
if not paths:
|
||||
return
|
||||
|
||||
self._current_bq = model.get(model.get_iter(paths[0]), 0, 1)
|
||||
if self._page is Page.SERVICES:
|
||||
self._current_bq = model.get(model.get_iter(paths[0]), 0, 1)
|
||||
self.update_bq_services()
|
||||
else:
|
||||
self._current_sat = model.get(model.get_iter(paths[0]), 0, 1)
|
||||
self.update_sat_services()
|
||||
|
||||
self._services_count_label.set_text(str(len(self._services_model)))
|
||||
|
||||
def update_bq_services(self):
|
||||
bq_services = self._bq_services.get(self._current_bq)
|
||||
skip = self._skip_import[self._current_bq]
|
||||
|
||||
@@ -249,14 +319,17 @@ class ImportDialog:
|
||||
srv = self._services.get(bq_srv.data, None)
|
||||
if srv:
|
||||
bg = self._existing_srv_background if srv.fav_id in self._ids else None
|
||||
srv = (srv.service, srv.service_type, srv.fav_id not in skip, bg, srv.fav_id)
|
||||
self._services_model.append(srv)
|
||||
self._services_model.append((srv.service, srv.service_type, srv.fav_id not in skip, bg, srv.fav_id))
|
||||
else:
|
||||
bg = self._existing_srv_background if bq_srv.data in self._ids else None
|
||||
srv = (bq_srv.name, bq_srv.type.value, bq_srv.data not in skip, bg, bq_srv.data)
|
||||
self._services_model.append(srv)
|
||||
self._services_model.append((bq_srv.name, bq_srv.type.value, bq_srv.data not in skip, bg, bq_srv.data))
|
||||
|
||||
self._services_count_label.set_text(str(len(self._services_model)))
|
||||
def update_sat_services(self):
|
||||
sat_services = self._sat_services.get(self._current_sat[0])
|
||||
skip = self._skip_import[self._current_sat]
|
||||
for srv in sat_services:
|
||||
bg = self._existing_srv_background if srv.fav_id in self._ids else None
|
||||
self._services_model.append((srv.service, srv.service_type, srv.fav_id not in skip, bg, srv.fav_id))
|
||||
|
||||
def on_service_changed(self, view):
|
||||
path, column = view.get_cursor()
|
||||
@@ -274,13 +347,16 @@ class ImportDialog:
|
||||
def on_bq_selected_toggled(self, toggle, path):
|
||||
self._bq_model.set_value(self._bq_model.get_iter(path), 2, not toggle.get_active())
|
||||
|
||||
def on_sat_selected_toggled(self, toggle, path):
|
||||
self._sat_model.set_value(self._sat_model.get_iter(path), 2, not toggle.get_active())
|
||||
|
||||
def on_service_selected_toggled(self, toggle, path):
|
||||
self._services_model.set_value(self._services_model.get_iter(path), 2, not toggle.get_active())
|
||||
|
||||
def on_services_model_changed(self, model, path, itr):
|
||||
row = model[itr][:]
|
||||
fav_id = row[-1]
|
||||
skip = self._skip_import[self._current_bq]
|
||||
skip = self._skip_import[self._current_bq if self._page is Page.SERVICES else self._current_sat]
|
||||
if row[2]:
|
||||
if fav_id in skip:
|
||||
skip.remove(fav_id)
|
||||
@@ -306,6 +382,16 @@ class ImportDialog:
|
||||
def update_selection(self, view, select):
|
||||
view.get_model().foreach(lambda mod, path, itr: mod.set_value(itr, 2, select))
|
||||
|
||||
def on_sat_view_realize(self, view):
|
||||
if not self._services:
|
||||
return True
|
||||
|
||||
for srv in self._services.values():
|
||||
self._sat_services[srv.pos].append(srv)
|
||||
|
||||
list(map(lambda s: self._sat_model.append((s, None, True)), self._sat_services))
|
||||
self._sat_count_label.set_text(str(len(self._sat_model)))
|
||||
|
||||
def on_services_view_realize(self, view):
|
||||
if self._settings.use_colors:
|
||||
background = Gdk.RGBA()
|
||||
@@ -316,6 +402,13 @@ class ImportDialog:
|
||||
if self._settings:
|
||||
self._settings.add("import_dialog_window_size", window.get_size())
|
||||
|
||||
def on_main_paned_realize(self, paned):
|
||||
width = paned.get_allocated_width()
|
||||
paned.set_position(width * 0.35)
|
||||
|
||||
def on_visible_page(self, stack, param):
|
||||
self._page = Page(stack.get_visible_child_name())
|
||||
|
||||
def on_key_press(self, view, event):
|
||||
""" Handling keystrokes """
|
||||
key_code = event.hardware_keycode
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018-2022 Dmitriy Yefremov
|
||||
Copyright (c) 2018-2023 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
|
||||
@@ -27,11 +27,11 @@ Author: Dmitriy Yefremov
|
||||
|
||||
-->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.16"/>
|
||||
<requires lib="gtk+" version="3.22"/>
|
||||
<!-- interface-license-type mit -->
|
||||
<!-- interface-name DemonEditor -->
|
||||
<!-- interface-description Enigma2 channel and satellites list editor for GNU/Linux. -->
|
||||
<!-- interface-copyright 2018-2022 Dmitriy Yefremov -->
|
||||
<!-- interface-copyright 2018-2023 Dmitriy Yefremov -->
|
||||
<!-- interface-authors Dmitriy Yefremov -->
|
||||
<object class="GtkImage" id="remove_selection_image">
|
||||
<property name="visible">True</property>
|
||||
@@ -1435,7 +1435,7 @@ Author: Dmitriy Yefremov
|
||||
<property name="image">yt_receive_image</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="clicked" handler="on_receive" swapped="no"/>
|
||||
<accelerator key="d" signal="clicked"/>
|
||||
<accelerator key="d" signal="clicked" modifiers="Primary"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
@@ -1456,7 +1456,7 @@ Author: Dmitriy Yefremov
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButtonBox" id="yt_impotr_box">
|
||||
<object class="GtkButtonBox" id="yt_import_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="layout_style">expand</property>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2018-2022 Dmitriy Yefremov
|
||||
# Copyright (c) 2018-2023 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
|
||||
@@ -40,18 +40,18 @@ from gi.repository import GLib, Gio, GdkPixbuf
|
||||
from app.commons import run_idle, run_task, log
|
||||
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,
|
||||
parse_m3u)
|
||||
from app.settings import SettingsType
|
||||
parse_m3u, PICON_FORMAT)
|
||||
from app.settings import SettingsType, IS_DARWIN
|
||||
from app.tools.yt import YouTubeException, YouTube
|
||||
from app.ui.dialogs import Action, show_dialog, DialogType, get_message, get_builder
|
||||
from app.ui.main_helper import get_iptv_url, on_popup_menu, get_picon_pixbuf
|
||||
from app.ui.uicommons import (Gtk, Gdk, UI_RESOURCES_PATH, IPTV_ICON, Column, KeyboardKey, get_yt_icon)
|
||||
from app.ui.uicommons import (Gtk, Gdk, UI_RESOURCES_PATH, IPTV_ICON, Column, KeyboardKey, get_yt_icon,
|
||||
IS_GNOME_SESSION, HeaderBar)
|
||||
|
||||
_DIGIT_ENTRY_NAME = "digit-entry"
|
||||
_ENIGMA2_REFERENCE = "{}:{}:{}:{:X}:{:X}:{:X}:{:X}:0:0:0"
|
||||
_PATTERN = re.compile("(?:^[\\s]*$|\\D)")
|
||||
_UI_PATH = UI_RESOURCES_PATH + "iptv.glade"
|
||||
_PICON_FORMAT = "1_{}_{:X}_{:X}_{:X}_{:X}_{:X}_0_0_0.png"
|
||||
|
||||
|
||||
def is_data_correct(elems):
|
||||
@@ -322,14 +322,14 @@ class IptvDialog:
|
||||
self._dialog.destroy()
|
||||
|
||||
def update_bouquet_data(self, name, fav_id):
|
||||
picon_id = f"1_{'_'.join(self._reference_entry.get_text().split(':')[1:])}.png"
|
||||
picon_id = f"{self._reference_entry.get_text().replace(':', '_')}.png"
|
||||
|
||||
if self._action is Action.EDIT:
|
||||
services = self._app.current_services
|
||||
old_srv = services.pop(self._current_srv.fav_id)
|
||||
new_service = old_srv._replace(service=name, fav_id=fav_id, picon_id=picon_id)
|
||||
services[fav_id] = new_service
|
||||
self._app.emit("iptv-service-edited", (old_srv, new_service))
|
||||
self._app.emit("iptv-service-edited", {self._current_srv.fav_id: (old_srv, new_service)})
|
||||
else:
|
||||
aggr = [None] * 8
|
||||
s_type = BqServiceType.IPTV.name
|
||||
@@ -622,7 +622,7 @@ class IptvListConfigurationDialog(IptvListDialog):
|
||||
data[3] = f"{index:X}" if sid_auto else sid
|
||||
if sid_auto:
|
||||
params[0] = index
|
||||
picon_id = _PICON_FORMAT.format(int(s_id), int(srv_type), *params)
|
||||
picon_id = PICON_FORMAT.format(st_type, int(s_id), int(srv_type), *params)
|
||||
data = ":".join(data)
|
||||
new_fav_id = f"{data}{sep}{desc}"
|
||||
row[Column.FAV_ID] = new_fav_id
|
||||
@@ -725,7 +725,7 @@ class M3uImportDialog(IptvListDialog):
|
||||
continue
|
||||
|
||||
params[0] = i if sid_auto else sid
|
||||
picon_id = _PICON_FORMAT.format(s_id, s_type, *params)
|
||||
picon_id = PICON_FORMAT.format(st_type, s_id, s_type, *params)
|
||||
fav_id = get_fav_id(s.data_id, s.service, self._s_type, params, st_type, s_id, s_type)
|
||||
if s.picon:
|
||||
picons[s.picon] = picon_id
|
||||
@@ -860,7 +860,6 @@ class YtListImportDialog:
|
||||
"on_key_press": self.on_key_press,
|
||||
"on_close": self.on_close}
|
||||
|
||||
# self._main_window, self._settings, self.append_imported_services
|
||||
self.appender = app.append_imported_services
|
||||
self._settings = app.app_settings
|
||||
self._s_type = self._settings.setting_type
|
||||
@@ -892,6 +891,17 @@ class YtListImportDialog:
|
||||
self._import_button.bind_property("sensitive", self._quality_box, "sensitive")
|
||||
self._receive_button.bind_property("sensitive", self._import_button, "sensitive")
|
||||
|
||||
if IS_GNOME_SESSION or IS_DARWIN:
|
||||
header_bar = HeaderBar(title="YouTube", subtitle=get_message("Playlist import"))
|
||||
self._dialog.set_titlebar(header_bar)
|
||||
actions_box = builder.get_object("yt_actions_box")
|
||||
import_box = builder.get_object("yt_import_box")
|
||||
actions_box.remove(import_box)
|
||||
header_bar.pack_end(import_box)
|
||||
actions_box.remove(self._receive_button)
|
||||
header_bar.pack_start(self._receive_button)
|
||||
actions_box.set_visible(False)
|
||||
|
||||
window_size = self._settings.get("yt_import_dialog_size")
|
||||
if window_size:
|
||||
self._dialog.resize(*window_size)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -3,7 +3,7 @@
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018-2022 Dmitriy Yefremov
|
||||
Copyright (c) 2018-2023 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
|
||||
@@ -27,12 +27,12 @@ Author: Dmitriy Yefremov
|
||||
|
||||
-->
|
||||
<interface domain="demon-editor">
|
||||
<requires lib="gtk+" version="3.18"/>
|
||||
<requires lib="gtk+" version="3.22"/>
|
||||
<!-- interface-css-provider-path style.css -->
|
||||
<!-- interface-license-type mit -->
|
||||
<!-- interface-name DemonEditor -->
|
||||
<!-- interface-description Enigma2 channel and satellite list editor. -->
|
||||
<!-- interface-copyright 2018-2021 Dmitriy Yefremov -->
|
||||
<!-- interface-copyright 2018-2023 Dmitriy Yefremov -->
|
||||
<!-- interface-authors Dmitriy Yefremov -->
|
||||
<object class="GtkImage" id="alt_image">
|
||||
<property name="visible">True</property>
|
||||
@@ -106,6 +106,11 @@ Author: Dmitriy Yefremov
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-clear</property>
|
||||
</object>
|
||||
<object class="GtkImage" id="clear_new_flag_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">edit-undo</property>
|
||||
</object>
|
||||
<object class="GtkImage" id="copy_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
@@ -255,10 +260,7 @@ Author: Dmitriy Yefremov
|
||||
<property name="width_request">170</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="margin_left">5</property>
|
||||
<property name="margin_right">5</property>
|
||||
<property name="margin_top">5</property>
|
||||
<property name="margin_bottom">5</property>
|
||||
<property name="border_width">5</property>
|
||||
<property name="hscrollbar_policy">never</property>
|
||||
<property name="max_content_height">350</property>
|
||||
<property name="propagate_natural_height">True</property>
|
||||
@@ -323,10 +325,7 @@ Author: Dmitriy Yefremov
|
||||
<property name="width_request">135</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">5</property>
|
||||
<property name="margin_right">5</property>
|
||||
<property name="margin_top">5</property>
|
||||
<property name="margin_bottom">5</property>
|
||||
<property name="border_width">5</property>
|
||||
<property name="hscrollbar_policy">never</property>
|
||||
<property name="max_content_height">350</property>
|
||||
<property name="propagate_natural_height">True</property>
|
||||
@@ -406,39 +405,49 @@ Author: Dmitriy Yefremov
|
||||
<object class="GtkPopover" id="filter_type_popover">
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="filter_type_view">
|
||||
<property name="width_request">135</property>
|
||||
<object class="GtkBox" id="filter_type_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">5</property>
|
||||
<property name="margin_right">5</property>
|
||||
<property name="margin_top">5</property>
|
||||
<property name="margin_bottom">5</property>
|
||||
<property name="model">filter_types_list_store</property>
|
||||
<property name="headers_visible">False</property>
|
||||
<property name="enable_search">False</property>
|
||||
<child internal-child="selection">
|
||||
<object class="GtkTreeSelection"/>
|
||||
</child>
|
||||
<property name="border_width">5</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="fiter_type_column">
|
||||
<property name="title" translatable="yes">Type</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="filter_type_renderer_text"/>
|
||||
<attributes>
|
||||
<attribute name="text">0</attribute>
|
||||
</attributes>
|
||||
<object class="GtkTreeView" id="filter_type_view">
|
||||
<property name="width_request">135</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="border_width">5</property>
|
||||
<property name="model">filter_types_list_store</property>
|
||||
<property name="headers_visible">False</property>
|
||||
<property name="enable_search">False</property>
|
||||
<child internal-child="selection">
|
||||
<object class="GtkTreeSelection"/>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCellRendererToggle" id="filter_type_renderer_toggle">
|
||||
<property name="xalign">0.98000001907348633</property>
|
||||
<signal name="toggled" handler="on_filter_type_toggled" swapped="no"/>
|
||||
<object class="GtkTreeViewColumn" id="fiter_type_column">
|
||||
<property name="title" translatable="yes">Type</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="filter_type_renderer_text"/>
|
||||
<attributes>
|
||||
<attribute name="text">0</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCellRendererToggle" id="filter_type_renderer_toggle">
|
||||
<property name="xalign">0.98000001907348633</property>
|
||||
<signal name="toggled" handler="on_filter_type_toggled" swapped="no"/>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="active">1</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="active">1</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
@@ -1402,6 +1411,15 @@ Author: Dmitriy Yefremov
|
||||
<signal name="activate" handler="on_services_clear_marked" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="services_clear_new_flag_item">
|
||||
<property name="label" translatable="yes">Clear "New" flag</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="image">clear_new_flag_image</property>
|
||||
<property name="use_stock">False</property>
|
||||
<signal name="activate" handler="on_services_clear_new_marked" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparatorMenuItem" id="services_separatormenuitem_1">
|
||||
<property name="visible">True</property>
|
||||
@@ -1633,7 +1651,7 @@ Author: Dmitriy Yefremov
|
||||
<object class="GtkLabel" id="app_ver_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label">3.1.0 Alpha</property>
|
||||
<property name="label">3.3.1 Beta</property>
|
||||
<attributes>
|
||||
<attribute name="weight" value="bold"/>
|
||||
</attributes>
|
||||
@@ -1759,12 +1777,12 @@ Author: Dmitriy Yefremov
|
||||
<child type="center">
|
||||
<object class="GtkButtonBox" id="services_button_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="name">header-stack-switcher</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="layout_style">expand</property>
|
||||
<child>
|
||||
<object class="GtkRadioButton" id="dvb_button">
|
||||
<property name="label" translatable="yes">DVB</property>
|
||||
<property name="name">stack-switch-button</property>
|
||||
<property name="width_request">80</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
@@ -1782,7 +1800,6 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkRadioButton" id="iptv_button">
|
||||
<property name="label" translatable="yes">IPTV</property>
|
||||
<property name="name">stack-switch-button</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="receives_default">False</property>
|
||||
@@ -2179,7 +2196,7 @@ Author: Dmitriy Yefremov
|
||||
<object class="GtkCellRendererText" id="service_renderer">
|
||||
<property name="xpad">5</property>
|
||||
<property name="ellipsize">end</property>
|
||||
<property name="width_chars">25</property>
|
||||
<property name="width_chars">50</property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="cell-background-rgba">21</attribute>
|
||||
@@ -3409,7 +3426,6 @@ Author: Dmitriy Yefremov
|
||||
<property name="model">fav_list_store</property>
|
||||
<property name="enable_search">False</property>
|
||||
<property name="search_column">2</property>
|
||||
<property name="fixed_height_mode">True</property>
|
||||
<property name="rubber_banding">True</property>
|
||||
<property name="enable_grid_lines">both</property>
|
||||
<property name="tooltip_column">9</property>
|
||||
@@ -4155,7 +4171,7 @@ Author: Dmitriy Yefremov
|
||||
</object>
|
||||
<packing>
|
||||
<property name="resize">True</property>
|
||||
<property name="shrink">False</property>
|
||||
<property name="shrink">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
|
||||
231
app/ui/main.py
231
app/ui/main.py
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2018-2022 Dmitriy Yefremov
|
||||
# Copyright (c) 2018-2023 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
|
||||
@@ -69,7 +69,7 @@ from .search import SearchProvider
|
||||
from .service_details_dialog import ServiceDetailsDialog, Action
|
||||
from .settings_dialog import SettingsDialog
|
||||
from .uicommons import (Gtk, Gdk, UI_RESOURCES_PATH, LOCKED_ICON, HIDE_ICON, IPTV_ICON, MOVE_KEYS, KeyboardKey, Column,
|
||||
FavClickMode, MOD_MASK, APP_FONT, Page, IS_GNOME_SESSION)
|
||||
FavClickMode, MOD_MASK, APP_FONT, Page, IS_GNOME_SESSION, HeaderBar)
|
||||
from .xml.dialogs import ServicesUpdateDialog
|
||||
from .xml.edit import SatellitesTool
|
||||
|
||||
@@ -178,6 +178,7 @@ class Application(Gtk.Application):
|
||||
"on_mark_duplicates": self.on_mark_duplicates,
|
||||
"on_services_mark_not_in_bouquets": self.on_services_mark_not_in_bouquets,
|
||||
"on_services_clear_marked": self.on_services_clear_marked,
|
||||
"on_services_clear_new_marked": self.on_services_clear_new_marked,
|
||||
"on_filter_changed": self.on_filter_changed,
|
||||
"on_iptv_filter_changed": self.on_iptv_filter_changed,
|
||||
"on_filter_type_toggled": self.on_filter_type_toggled,
|
||||
@@ -228,7 +229,6 @@ class Application(Gtk.Application):
|
||||
# Clearing only after the insertion!
|
||||
self._rows_buffer = []
|
||||
self._bouquets_buffer = []
|
||||
self._picons_buffer = []
|
||||
self._services = {}
|
||||
self._bouquets = {}
|
||||
self._bq_file = {}
|
||||
@@ -240,11 +240,13 @@ class Application(Gtk.Application):
|
||||
self._in_bouquets = set()
|
||||
# For bouquets with different names of services in bouquet and main list
|
||||
self._extra_bouquets = {}
|
||||
self._picons = DefaultDict(self.get_picon)
|
||||
self._blacklist = set()
|
||||
self._current_bq_name = None
|
||||
self._bq_selected = "" # Current selected bouquet
|
||||
self._select_enabled = True # Multiple selection
|
||||
# Picons
|
||||
self._picons_buffer = []
|
||||
self._picons = DefaultDict(self.get_picon)
|
||||
# Current satellite positions in the services list
|
||||
self._sat_positions = set()
|
||||
self._service_types = set()
|
||||
@@ -306,6 +308,8 @@ class Application(Gtk.Application):
|
||||
GObject.TYPE_PYOBJECT, (GObject.TYPE_PYOBJECT,))
|
||||
GObject.signal_new("epg-dat-downloaded", self, GObject.SIGNAL_RUN_LAST,
|
||||
GObject.TYPE_PYOBJECT, (GObject.TYPE_PYOBJECT,))
|
||||
GObject.signal_new("services-update", self, GObject.SIGNAL_RUN_LAST,
|
||||
GObject.TYPE_PYOBJECT, (GObject.TYPE_PYOBJECT,))
|
||||
GObject.signal_new("iptv-service-edited", self, GObject.SIGNAL_RUN_LAST,
|
||||
GObject.TYPE_PYOBJECT, (GObject.TYPE_PYOBJECT,))
|
||||
GObject.signal_new("iptv-service-added", self, GObject.SIGNAL_RUN_LAST,
|
||||
@@ -416,7 +420,6 @@ class Application(Gtk.Application):
|
||||
self._filter_only_free_button = builder.get_object("filter_only_free_button")
|
||||
self._filter_not_in_bq_button = builder.get_object("filter_not_in_bq_button")
|
||||
self._services_load_spinner.bind_property("active", self._filter_services_button, "sensitive", 4)
|
||||
self._services_load_spinner.bind_property("active", self._filter_box, "sensitive", 4)
|
||||
self._filter_iptv_services_button = builder.get_object("filter_iptv_services_button")
|
||||
# Search.
|
||||
services_search_provider = SearchProvider(self._services_view,
|
||||
@@ -461,6 +464,8 @@ class Application(Gtk.Application):
|
||||
# Lock, Hide.
|
||||
self.bind_property("is-enigma", self._tool_elements.get(self._LOCK_HIDE_ELEMENTS[0]), "visible")
|
||||
self.bind_property("is-enigma", self._tool_elements.get(self._LOCK_HIDE_ELEMENTS[1]), "visible", 4)
|
||||
# Clear "New" menu item
|
||||
self.bind_property("is-enigma", builder.get_object("services_clear_new_flag_item"), "visible")
|
||||
# Sub-bouquets menu item.
|
||||
self.bind_property("is-enigma", builder.get_object("bouquets_new_sub_popup_item"), "visible")
|
||||
# Export bouquet to m3u menu items.
|
||||
@@ -485,6 +490,7 @@ class Application(Gtk.Application):
|
||||
self._logs_box = builder.get_object("logs_box")
|
||||
self._logs_box.pack_start(LogsClient(self), True, True, 0)
|
||||
self._bottom_paned = builder.get_object("bottom_paned")
|
||||
self.connect("services-update", self.on_services_update)
|
||||
# Send/Receive.
|
||||
self.connect("data-receive", self.on_download)
|
||||
self.connect("data-send", self.on_upload)
|
||||
@@ -500,9 +506,11 @@ class Application(Gtk.Application):
|
||||
# Header bar.
|
||||
profile_box = builder.get_object("profile_combo_box")
|
||||
toolbar_box = builder.get_object("toolbar_main_box")
|
||||
if IS_GNOME_SESSION:
|
||||
header_bar = Gtk.HeaderBar(visible=True, show_close_button=True)
|
||||
header_bar.pack_start(builder.get_object("file_header_button"))
|
||||
if IS_GNOME_SESSION or IS_DARWIN:
|
||||
header_bar = HeaderBar()
|
||||
if not IS_DARWIN:
|
||||
header_bar.pack_start(builder.get_object("file_header_button"))
|
||||
|
||||
header_bar.pack_start(profile_box)
|
||||
header_bar.pack_start(toolbar_box)
|
||||
header_bar.set_custom_title(builder.get_object("stack_switcher"))
|
||||
@@ -564,12 +572,16 @@ class Application(Gtk.Application):
|
||||
self._epg_menu_button = builder.get_object("epg_menu_button")
|
||||
self._epg_menu_button.connect("realize", lambda b: b.set_popover(EpgSettingsPopover(self)))
|
||||
self.bind_property("is_enigma", self._epg_menu_button, "sensitive")
|
||||
self._epg_start_time_fmt = "%a, %H:%M"
|
||||
self._epg_end_time_fmt = "%H:%M"
|
||||
# Hiding for Neutrino.
|
||||
self.bind_property("is_enigma", builder.get_object("services_button_box"), "visible")
|
||||
# Setting the last size of the window if it was saved.
|
||||
main_window_size = self._settings.get("window_size")
|
||||
if main_window_size:
|
||||
self._main_window.resize(*main_window_size)
|
||||
# Layout.
|
||||
self.init_layout()
|
||||
# Style.
|
||||
style_provider = Gtk.CssProvider()
|
||||
style_provider.load_from_path(UI_RESOURCES_PATH + "style.css")
|
||||
@@ -614,7 +626,6 @@ class Application(Gtk.Application):
|
||||
|
||||
self.init_actions()
|
||||
self.set_accels()
|
||||
self.init_layout()
|
||||
|
||||
self.init_drag_and_drop()
|
||||
self.init_appearance()
|
||||
@@ -866,12 +877,12 @@ class Application(Gtk.Application):
|
||||
def init_layout(self):
|
||||
""" Initializes an alternate layout, if enabled. """
|
||||
if self._settings.alternate_layout:
|
||||
self._main_paned.pack2(self._player_box, True, False)
|
||||
self._main_paned.pack2(self._player_box, True, True)
|
||||
self.reverse_main_elements(True)
|
||||
else:
|
||||
self._main_paned.remove(self._data_paned)
|
||||
self._main_paned.pack1(self._player_box, True, False)
|
||||
self._main_paned.pack2(self._data_paned, True, False)
|
||||
self._main_paned.pack1(self._player_box, True, True)
|
||||
self._main_paned.pack2(self._data_paned, True, True)
|
||||
|
||||
def init_bq_position(self):
|
||||
self._fav_paned.remove(self._fav_frame)
|
||||
@@ -888,7 +899,7 @@ class Application(Gtk.Application):
|
||||
""" Initializes starting positions of main paned widgets. """
|
||||
width = paned.get_allocated_width()
|
||||
main_position = self._settings.get("data_paned_position", width * 0.5)
|
||||
fav_position = self._settings.get("fav_paned_position", width * 0.27)
|
||||
fav_position = self._settings.get("fav_paned_position", width * 0.25)
|
||||
paned.set_position(main_position)
|
||||
self._fav_paned.set_position(fav_position)
|
||||
|
||||
@@ -1093,10 +1104,8 @@ class Application(Gtk.Application):
|
||||
renderer.set_property("text", f"{StreamType(f_data[0].strip() if f_data else '0').name}")
|
||||
|
||||
def iptv_picon_data_func(self, column, renderer, model, itr, data):
|
||||
picon = self._picons.get(model.get_value(itr, Column.IPTV_PICON_ID))
|
||||
if not picon:
|
||||
picon = self._picons.get(get_picon_file_name(model.get_value(itr, Column.IPTV_SERVICE)))
|
||||
renderer.set_property("pixbuf", picon)
|
||||
picon_id, name = model.get_value(itr, Column.IPTV_PICON_ID), model.get_value(itr, Column.IPTV_SERVICE)
|
||||
renderer.set_property("pixbuf", self.get_picon_pixbuf(picon_id, name))
|
||||
|
||||
def picon_data_func(self, column, renderer, model, itr, data):
|
||||
picon = self._picons.get(model.get_value(itr, Column.SRV_PICON_ID))
|
||||
@@ -1109,7 +1118,7 @@ class Application(Gtk.Application):
|
||||
if not srv:
|
||||
return True
|
||||
|
||||
picon = self._picons.get(srv.picon_id, None)
|
||||
picon = self.get_picon_pixbuf(srv.picon_id, srv.service)
|
||||
# Alternatives.
|
||||
if srv.service_type == BqServiceType.ALT.name:
|
||||
alt_servs = srv.transponder
|
||||
@@ -1118,11 +1127,23 @@ class Application(Gtk.Application):
|
||||
if alt_srv:
|
||||
picon = self._picons.get(alt_srv.picon_id, None) if srv else None
|
||||
|
||||
if not picon:
|
||||
picon = self._picons.get(get_picon_file_name(model.get_value(itr, Column.FAV_SERVICE)))
|
||||
|
||||
renderer.set_property("pixbuf", picon)
|
||||
|
||||
def get_picon_pixbuf(self, picon_id, srv_name):
|
||||
""" Returns a picon pixbuf by id or service name.
|
||||
|
||||
Used for models with IPTV services.
|
||||
"""
|
||||
picon = self._picons.get(picon_id)
|
||||
# Trying to get a satellite service piсon.
|
||||
if not picon and picon_id:
|
||||
picon = self._picons.get(picon_id.replace(picon_id[:picon_id.find("_")], "1", 1))
|
||||
# Getting picon by service name.
|
||||
if not picon:
|
||||
picon = self._picons.get(get_picon_file_name(srv_name))
|
||||
|
||||
return picon
|
||||
|
||||
def fav_service_data_func(self, column, renderer, model, itr, data):
|
||||
if self._display_epg and self._s_type is SettingsType.ENIGMA_2:
|
||||
srv_name = model.get_value(itr, Column.FAV_SERVICE)
|
||||
@@ -1131,10 +1152,16 @@ class Application(Gtk.Application):
|
||||
|
||||
event = self._epg_cache.get_current_event(srv_name)
|
||||
if event:
|
||||
if event.start:
|
||||
start = datetime.fromtimestamp(event.start).strftime(self._epg_start_time_fmt)
|
||||
end = datetime.fromtimestamp(event.end).strftime(self._epg_end_time_fmt)
|
||||
sep = "-"
|
||||
else:
|
||||
start, end, sep = "", "", ""
|
||||
# https://docs.gtk.org/Pango/pango_markup.html
|
||||
renderer.set_property("markup", (f'{escape(srv_name)}\n\n'
|
||||
f'<span size="small" weight="bold">{escape(event.title)}</span>\n'
|
||||
f'<span size="small" style="italic">{event.time}</span>'))
|
||||
f'<span size="small" style="italic">{start} {sep} {end}</span>'))
|
||||
return False
|
||||
return True
|
||||
|
||||
@@ -1160,6 +1187,9 @@ class Application(Gtk.Application):
|
||||
self.on_copy(view, target=ViewTarget.BOUQUET)
|
||||
|
||||
def on_copy(self, view, target):
|
||||
if not self._settings.unlimited_copy_buffer:
|
||||
self._bouquets_buffer.clear() if target is ViewTarget.BOUQUET else self._rows_buffer.clear()
|
||||
|
||||
model, paths = view.get_selection().get_selected_rows()
|
||||
|
||||
if target is ViewTarget.FAV:
|
||||
@@ -1188,6 +1218,9 @@ class Application(Gtk.Application):
|
||||
self.on_cut(view, ViewTarget.BOUQUET)
|
||||
|
||||
def on_cut(self, view, target=None):
|
||||
if not self._settings.unlimited_copy_buffer:
|
||||
self._bouquets_buffer.clear() if target is ViewTarget.BOUQUET else self._rows_buffer.clear()
|
||||
|
||||
if target is ViewTarget.FAV:
|
||||
for row in tuple(self.on_delete(view)):
|
||||
self._rows_buffer.append(row)
|
||||
@@ -1255,6 +1288,20 @@ class Application(Gtk.Application):
|
||||
self._bouquets_buffer.clear()
|
||||
self.update_bouquets_type()
|
||||
|
||||
def on_services_update(self, app, services):
|
||||
""" Updates services in the main model. """
|
||||
for r in self._fav_model:
|
||||
fav_id = r[Column.FAV_ID]
|
||||
if fav_id in services:
|
||||
service = services[fav_id]
|
||||
r[Column.FAV_SERVICE] = service.service
|
||||
|
||||
for r in self._services_model:
|
||||
fav_id = r[Column.SRV_FAV_ID]
|
||||
if fav_id in services:
|
||||
service = services[fav_id]
|
||||
r[Column.SRV_SERVICE] = service.service
|
||||
|
||||
# ***************** Deletion ********************* #
|
||||
|
||||
def on_delete(self, view):
|
||||
@@ -1546,7 +1593,7 @@ class Application(Gtk.Application):
|
||||
|
||||
for s_row, row in zip(sorted(map(
|
||||
lambda r: r[:], rows),
|
||||
key=lambda r: r[c_num] or nv if c_num != Column.FAV_POS else self.get_pos_num(r[c_num]),
|
||||
key=lambda r: r[c_num] or nv if c_num != Column.FAV_POS else get_pos_num(r[c_num]),
|
||||
reverse=rev), rows):
|
||||
self._fav_model.set(row.iter, columns, s_row)
|
||||
bq[index] = s_row[Column.FAV_ID]
|
||||
@@ -1562,18 +1609,7 @@ class Application(Gtk.Application):
|
||||
|
||||
def position_sort_func(self, model, iter1, iter2, column):
|
||||
""" Custom sort function for position column. """
|
||||
return self.get_pos_num(model.get_value(iter1, column)) - self.get_pos_num(model.get_value(iter2, column))
|
||||
|
||||
def get_pos_num(self, pos):
|
||||
""" Returns num [float] representation of satellite position. """
|
||||
if not pos:
|
||||
return -183.0
|
||||
|
||||
if len(pos) > 1:
|
||||
m = -1 if pos[-1] == "W" else 1
|
||||
return float(pos[:-1]) * m
|
||||
|
||||
return -181.0 if pos == "T" else -182.0
|
||||
return get_pos_num(model.get_value(iter1, column)) - get_pos_num(model.get_value(iter2, column))
|
||||
|
||||
# ********************* Hints ************************* #
|
||||
|
||||
@@ -2283,7 +2319,7 @@ class Application(Gtk.Application):
|
||||
fav_id_data = fav_id.lstrip().split(":")
|
||||
if len(fav_id_data) > 10:
|
||||
data_id = ":".join(fav_id_data[:11])
|
||||
picon_id = "1_{}_{}_{}_{}_{}_{}_{}_{}_{}.png".format(*fav_id_data[1:10])
|
||||
picon_id = "{}_{}_{}_{}_{}_{}_{}_{}_{}_{}.png".format(*fav_id_data[:10])
|
||||
locked = LOCKED_ICON if data_id in self._blacklist else None
|
||||
srv = Service(None, None, icon, srv.name, locked, None, None, s_type.name,
|
||||
self._picons.get(picon_id, None), picon_id, *agr, data_id, fav_id, None)
|
||||
@@ -2704,6 +2740,8 @@ class Application(Gtk.Application):
|
||||
|
||||
if changed:
|
||||
self.open_data()
|
||||
if self._settings.display_epg:
|
||||
self.change_action_state("display_epg", GLib.Variant.new_boolean(self._settings.display_epg))
|
||||
self.emit("profile-changed", None)
|
||||
|
||||
def set_profile(self, active):
|
||||
@@ -2937,24 +2975,29 @@ class Application(Gtk.Application):
|
||||
log(f"Error. Service with id '{fav_id}' not found!")
|
||||
|
||||
@run_idle
|
||||
def on_iptv_service_edited(self, app, services):
|
||||
old, new = services
|
||||
fav_id = old.fav_id
|
||||
name, new_fav_id = new.service, new.fav_id
|
||||
def on_iptv_service_edited(self, app, services: dict):
|
||||
for srvs in self._bouquets.values():
|
||||
for i, s in enumerate(srvs):
|
||||
if s == fav_id:
|
||||
if s in services:
|
||||
old, new = services[s]
|
||||
srvs[i] = new.fav_id
|
||||
|
||||
for r in self._fav_model:
|
||||
if r[Column.FAV_ID] == fav_id:
|
||||
fav_id = r[Column.FAV_ID]
|
||||
if fav_id in services:
|
||||
old, new = services[fav_id]
|
||||
name, new_fav_id = new.service, new.fav_id
|
||||
r[Column.FAV_SERVICE] = name
|
||||
r[Column.FAV_ID] = new_fav_id
|
||||
|
||||
for r in self._iptv_model:
|
||||
if r[Column.IPTV_FAV_ID] == fav_id:
|
||||
fav_id = r[Column.IPTV_FAV_ID]
|
||||
if fav_id in services:
|
||||
old, new = services[fav_id]
|
||||
name, new_fav_id = new.service, new.fav_id
|
||||
ref, url = get_iptv_data(new_fav_id)
|
||||
r[Column.IPTV_SERVICE] = name
|
||||
r[Column.IPTV_PICON_ID] = new.picon_id
|
||||
r[Column.IPTV_REF] = ref
|
||||
r[Column.IPTV_URL] = url
|
||||
r[Column.IPTV_FAV_ID] = new_fav_id
|
||||
@@ -3005,9 +3048,11 @@ class Application(Gtk.Application):
|
||||
return
|
||||
|
||||
ref = self._clipboard.wait_for_text()
|
||||
if ref and re.match(r"\d+_\d+_\d+_\w+_\w+_\w+_\d+_0_0_0", ref):
|
||||
if ref and re.match(r"\d+_\d+_\w+_\w+_\w+_\w+_\w+_0_0_0", ref):
|
||||
[self.assign_reference(model, p, ref) for p in iptv_paths]
|
||||
self._clipboard.clear()
|
||||
else:
|
||||
log(f"Error parsing reference [{ref}].")
|
||||
|
||||
self.emit("clipboard-changed", self._clipboard.wait_is_text_available())
|
||||
|
||||
@@ -3016,7 +3061,7 @@ class Application(Gtk.Application):
|
||||
row = model[path]
|
||||
fav_id = row[Column.FAV_ID]
|
||||
fav_id_data = fav_id.split(":")
|
||||
fav_id_data[3:7] = ref_data[3:7]
|
||||
fav_id_data[2:7] = ref_data[2:7]
|
||||
new_fav_id = ":".join(fav_id_data)
|
||||
new_data_id = ":".join(fav_id_data[:11]).strip()
|
||||
old_srv = self._services.pop(fav_id, None)
|
||||
@@ -3025,7 +3070,7 @@ class Application(Gtk.Application):
|
||||
picon_id_data[2:7] = ref_data[2:7]
|
||||
new_service = old_srv._replace(data_id=new_data_id, fav_id=new_fav_id, picon_id="_".join(picon_id_data))
|
||||
self._services[new_fav_id] = new_service
|
||||
self.emit("iptv-service-edited", (old_srv, new_service))
|
||||
self.emit("iptv-service-edited", {fav_id: (old_srv, new_service)})
|
||||
|
||||
# ****************** EPG ********************** #
|
||||
|
||||
@@ -3046,8 +3091,7 @@ class Application(Gtk.Application):
|
||||
self.show_error_message("This list does not contains IPTV streams!")
|
||||
return
|
||||
|
||||
bq = self._bouquets.get(self._bq_selected)
|
||||
EpgDialog(self, bq, self._current_bq_name).show()
|
||||
EpgDialog(self, self._current_bq_name).show()
|
||||
|
||||
# ***************** Import ******************** #
|
||||
|
||||
@@ -3128,7 +3172,7 @@ class Application(Gtk.Application):
|
||||
GLib.idle_add(lambda: next(gen, False))
|
||||
|
||||
dialog = ImportDialog(self, path, append)
|
||||
dialog.import_data() if force else dialog.show()
|
||||
dialog.import_bouquets_data() if force else dialog.show()
|
||||
|
||||
def append_imported_data(self, bouquets, services, callback=None):
|
||||
try:
|
||||
@@ -3481,7 +3525,7 @@ class Application(Gtk.Application):
|
||||
elif self._s_type is SettingsType.NEUTRINO_MP:
|
||||
# It may require some correction for cable and terrestrial channels!
|
||||
try:
|
||||
pos, freq = int(self.get_pos_num(srv.pos)) * 10, int(srv.freq)
|
||||
pos, freq = int(get_pos_num(srv.pos)) * 10, int(srv.freq)
|
||||
tid, nid, sid = int(ref[: -8], 16), int(ref[-8: -4], 16), int(srv.ssid, 16)
|
||||
except ValueError:
|
||||
log(f"Error getting reference for: {srv}")
|
||||
@@ -3683,16 +3727,7 @@ class Application(Gtk.Application):
|
||||
elif self._s_type is SettingsType.NEUTRINO_MP:
|
||||
list(map(lambda s: self._sat_positions.add(s.pos), filter(lambda s: s.pos, self._services.values())))
|
||||
|
||||
self.update_filter_sat_positions()
|
||||
|
||||
def update_filter_sat_positions(self):
|
||||
""" Updates the values for the satellite positions button model. """
|
||||
first = self._filter_sat_pos_model[self._filter_sat_pos_model.get_iter_first()][:]
|
||||
self._filter_sat_pos_model.clear()
|
||||
self._filter_sat_pos_model.append((first[0], True))
|
||||
self._sat_positions.discard(first[0])
|
||||
list(map(lambda pos: self._filter_sat_pos_model.append((pos, True)),
|
||||
sorted(self._sat_positions, key=self.get_pos_num, reverse=True)))
|
||||
update_filter_sat_positions(self._filter_sat_pos_model, self._sat_positions)
|
||||
|
||||
@run_with_delay(2)
|
||||
def on_filter_changed(self, item=None):
|
||||
@@ -3702,7 +3737,6 @@ class Application(Gtk.Application):
|
||||
|
||||
@run_with_delay(2)
|
||||
def on_iptv_filter_changed(self, item=None):
|
||||
self._iptv_filter_box.set_sensitive(False)
|
||||
self.update_iptv_filter_cache()
|
||||
self.update_iptv_filter_state()
|
||||
|
||||
@@ -3714,7 +3748,6 @@ class Application(Gtk.Application):
|
||||
@run_idle
|
||||
def update_iptv_filter_state(self):
|
||||
self._iptv_services_model_filter.refilter()
|
||||
GLib.idle_add(self._iptv_filter_box.set_sensitive, True)
|
||||
|
||||
def update_filter_cache(self):
|
||||
self._filter_cache.clear()
|
||||
@@ -3777,16 +3810,7 @@ class Application(Gtk.Application):
|
||||
self.on_filter_changed()
|
||||
|
||||
def update_filter_toggle_model(self, model, toggle, path, values_set):
|
||||
active = not toggle.get_active()
|
||||
if path == "0":
|
||||
model.foreach(lambda m, p, i: m.set_value(i, 1, active))
|
||||
else:
|
||||
model.set_value(model.get_iter(path), 1, active)
|
||||
if active:
|
||||
model.set_value(model.get_iter_first(), 1, len({r[0] for r in model if r[1]}) == len(model) - 1)
|
||||
else:
|
||||
model.set_value(model.get_iter_first(), 1, False)
|
||||
|
||||
update_toggle_model(model, path, toggle)
|
||||
values_set.clear()
|
||||
values_set.update({r[0] for r in model if r[1]})
|
||||
self.on_iptv_filter_changed() if self._iptv_button.get_active() else self.on_filter_changed()
|
||||
@@ -3984,6 +4008,54 @@ class Application(Gtk.Application):
|
||||
self._services_load_spinner.stop()
|
||||
yield True
|
||||
|
||||
def on_services_clear_new_marked(self, item):
|
||||
if self.is_data_loading():
|
||||
self.show_error_message("Data loading in progress!")
|
||||
return
|
||||
|
||||
model, paths = self._services_view.get_selection().get_selected_rows()
|
||||
if not paths:
|
||||
self.show_error_message("No selected item!")
|
||||
return
|
||||
|
||||
gen = self.clear_new_marked(model, paths)
|
||||
GLib.idle_add(lambda: next(gen, False), priority=GLib.PRIORITY_LOW)
|
||||
|
||||
def clear_new_marked(self, model, paths):
|
||||
self._services_load_spinner.start()
|
||||
|
||||
paths = get_base_paths(paths, model)
|
||||
model = get_base_model(model)
|
||||
for index, p in enumerate(paths):
|
||||
flags = model[p][Column.SRV_CAS_FLAGS]
|
||||
if flags:
|
||||
flags_data = flags.split(",")
|
||||
for i, f in enumerate(flags_data):
|
||||
if f.startswith("f:"):
|
||||
flag = Flag.parse(f)
|
||||
if Flag.is_new(flag):
|
||||
flag -= Flag.NEW.value
|
||||
if flag:
|
||||
flags_data[i] = f"f:{flag:02d}"
|
||||
else:
|
||||
flags_data.remove(f)
|
||||
|
||||
flags = ",".join(flags_data)
|
||||
model[p][Column.SRV_BACKGROUND] = None
|
||||
model[p][Column.SRV_CAS_FLAGS] = flags
|
||||
fav_id = model[p][Column.SRV_FAV_ID]
|
||||
srv = self._services.get(fav_id, None)
|
||||
if srv:
|
||||
self._services[fav_id] = srv._replace(flags_cas=flags)
|
||||
break
|
||||
|
||||
if index % self.FAV_FACTOR == 0:
|
||||
yield True
|
||||
|
||||
self.show_info_message("Done!", Gtk.MessageType.INFO)
|
||||
self._services_load_spinner.stop()
|
||||
yield True
|
||||
|
||||
# ***************** Picons ********************* #
|
||||
|
||||
@run_idle
|
||||
@@ -4016,8 +4088,11 @@ class Application(Gtk.Application):
|
||||
return get_picon_pixbuf(f"{self._settings.profile_picons_path}{p_id}", self._picons_size)
|
||||
|
||||
def get_tooltip_picon(self, srv):
|
||||
size, path = self._settings.tooltip_logo_size, self._settings.profile_picons_path
|
||||
pix = get_picon_pixbuf(f"{path}{srv.picon_id}", size=size)
|
||||
size, path, picon_id = self._settings.tooltip_logo_size, self._settings.profile_picons_path, srv.picon_id
|
||||
pix = get_picon_pixbuf(f"{path}{picon_id}", size=size)
|
||||
if not pix:
|
||||
picon_id = picon_id.replace(picon_id[:picon_id.find("_")], "1", 1)
|
||||
pix = get_picon_pixbuf(f"{path}{picon_id}", size=size)
|
||||
if not pix:
|
||||
pix = get_picon_pixbuf(f"{path}{get_picon_file_name(srv.service)}", size=size)
|
||||
return pix
|
||||
@@ -4227,11 +4302,15 @@ class Application(Gtk.Application):
|
||||
return True
|
||||
|
||||
def on_alt_selection(self, model, path, column):
|
||||
if self._control_tool and self._control_tool.update_epg:
|
||||
if self._page is Page.EPG:
|
||||
row = model[path][:]
|
||||
srv = self._services.get(row[Column.ALT_FAV_ID], None)
|
||||
if srv and srv.transponder or row[Column.ALT_TYPE] == BqServiceType.IPTV.name:
|
||||
self._control_tool.on_service_changed(srv.picon_id.rstrip(".png").replace("_", ":"))
|
||||
ref = self.get_service_ref_data(srv)
|
||||
if not ref:
|
||||
return
|
||||
|
||||
self.emit("fav-changed", ref)
|
||||
|
||||
# ***************** Profile label ********************* #
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2018-2022 Dmitriy Yefremov
|
||||
# Copyright (c) 2018-2023 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
|
||||
@@ -29,10 +29,11 @@
|
||||
""" Helper module for the GUI. """
|
||||
|
||||
__all__ = ("insert_marker", "move_items", "rename", "ViewTarget", "set_flags", "locate_in_services",
|
||||
"scroll_to", "get_base_model", "copy_reference", "assign_picons", "remove_picon",
|
||||
"scroll_to", "get_base_model", "get_base_paths", "copy_reference", "assign_picons", "remove_picon",
|
||||
"is_only_one_item_selected", "gen_bouquets", "BqGenType", "get_selection", "get_service_reference",
|
||||
"get_model_data", "remove_all_unused_picons", "get_picon_pixbuf", "get_base_itrs", "get_iptv_url",
|
||||
"get_iptv_data", "update_entry_data", "append_text_to_tview", "on_popup_menu", "get_picon_file_name")
|
||||
"get_iptv_data", "update_entry_data", "append_text_to_tview", "on_popup_menu", "get_picon_file_name",
|
||||
"update_toggle_model", "update_filter_sat_positions", "get_pos_num")
|
||||
|
||||
import os
|
||||
import re
|
||||
@@ -655,11 +656,7 @@ def copy_reference(view, app):
|
||||
|
||||
|
||||
def get_service_reference(srv):
|
||||
ref = srv.picon_id.rstrip(".png")
|
||||
if srv.service_type == BqServiceType.IPTV.name:
|
||||
p = re.compile(r"\d+")
|
||||
return re.sub(p, re.search(p, srv.fav_id).group(), ref, 1)
|
||||
return ref
|
||||
return srv.picon_id.rstrip(".png")
|
||||
|
||||
|
||||
def update_entry_data(entry, dialog, settings):
|
||||
@@ -701,6 +698,40 @@ def get_model_data(view):
|
||||
return model_name, model
|
||||
|
||||
|
||||
def update_toggle_model(model, path, toggle):
|
||||
""" Updates the toggle state for the model. """
|
||||
active = not toggle.get_active()
|
||||
if path == "0":
|
||||
model.foreach(lambda m, p, i: m.set_value(i, 1, active))
|
||||
else:
|
||||
model.set_value(model.get_iter(path), 1, active)
|
||||
if active:
|
||||
model.set_value(model.get_iter_first(), 1, len({r[0] for r in model if r[1]}) == len(model) - 1)
|
||||
else:
|
||||
model.set_value(model.get_iter_first(), 1, False)
|
||||
|
||||
|
||||
def update_filter_sat_positions(model, sat_positions):
|
||||
""" Updates the values for the satellite positions button model. """
|
||||
first = model[model.get_iter_first()][:]
|
||||
model.clear()
|
||||
model.append((first[0], True))
|
||||
sat_positions.discard(first[0])
|
||||
list(map(lambda pos: model.append((pos, True)), sorted(sat_positions, key=get_pos_num, reverse=True)))
|
||||
|
||||
|
||||
def get_pos_num(pos):
|
||||
""" Returns num [float] representation of satellite position. """
|
||||
if not pos:
|
||||
return -183.0
|
||||
|
||||
if len(pos) > 1:
|
||||
m = -1 if pos[-1] == "W" else 1
|
||||
return float(pos[:-1]) * m
|
||||
|
||||
return -181.0 if pos == "T" else -182.0
|
||||
|
||||
|
||||
def append_text_to_tview(char, view):
|
||||
""" Appending text and scrolling to a given line in the text view. """
|
||||
buf = view.get_buffer()
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018-2022 Dmitriy Yefremov
|
||||
Copyright (c) 2018-2023 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
|
||||
@@ -31,7 +31,7 @@ Author: Dmitriy Yefremov
|
||||
<!-- interface-css-provider-path style.css -->
|
||||
<!-- interface-license-type mit -->
|
||||
<!-- interface-name DemonEditor -->
|
||||
<!-- interface-copyright 2018-2021 Dmitriy Yefremov -->
|
||||
<!-- interface-copyright 2018-2023 Dmitriy Yefremov -->
|
||||
<!-- interface-authors Dmitriy Yefremov -->
|
||||
<object class="GtkMenu" id="add_menu">
|
||||
<property name="visible">True</property>
|
||||
@@ -379,6 +379,7 @@ Author: Dmitriy Yefremov
|
||||
<child type="center">
|
||||
<object class="GtkButtonBox" id="header_button_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="name">header-stack-switcher</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="layout_style">expand</property>
|
||||
@@ -640,7 +641,6 @@ Author: Dmitriy Yefremov
|
||||
<property name="can_focus">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Drag the services to the desired picon or picon to the list of selected services.</property>
|
||||
<property name="model">picons_src_sort_model</property>
|
||||
<property name="fixed_height_mode">True</property>
|
||||
<property name="rubber_banding">True</property>
|
||||
<property name="enable_grid_lines">horizontal</property>
|
||||
<property name="tooltip_column">0</property>
|
||||
@@ -665,7 +665,6 @@ Author: Dmitriy Yefremov
|
||||
<property name="alignment">0.49000000953674316</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererPixbuf" id="picons_src_renderer">
|
||||
<property name="height">50</property>
|
||||
<property name="ypad">5</property>
|
||||
</object>
|
||||
<attributes>
|
||||
@@ -778,7 +777,6 @@ Author: Dmitriy Yefremov
|
||||
<property name="can_focus">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Drag the services to the desired picon or picon to the list of selected services.</property>
|
||||
<property name="model">picons_dst_sort_model</property>
|
||||
<property name="fixed_height_mode">True</property>
|
||||
<property name="rubber_banding">True</property>
|
||||
<property name="enable_grid_lines">horizontal</property>
|
||||
<property name="tooltip_column">0</property>
|
||||
@@ -804,7 +802,6 @@ Author: Dmitriy Yefremov
|
||||
<property name="alignment">0.49000000953674316</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererPixbuf" id="picons_dest_renderer">
|
||||
<property name="height">50</property>
|
||||
<property name="ypad">5</property>
|
||||
</object>
|
||||
<attributes>
|
||||
|
||||
@@ -42,7 +42,8 @@ from app.tools.picons import (PiconsParser, parse_providers, Provider, convert_t
|
||||
PiconsError)
|
||||
from app.tools.satellites import SatellitesParser, SatelliteSource
|
||||
from .dialogs import show_dialog, DialogType, get_message, get_builder, get_chooser_dialog
|
||||
from .main_helper import scroll_to, on_popup_menu, get_base_model, set_picon, get_picon_pixbuf, get_picon_dialog
|
||||
from .main_helper import (scroll_to, on_popup_menu, get_base_model, set_picon, get_picon_pixbuf, get_picon_dialog,
|
||||
get_picon_file_name)
|
||||
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, TV_ICON, Column, KeyboardKey, Page, ViewTarget
|
||||
|
||||
|
||||
@@ -814,7 +815,12 @@ class PiconManager(Gtk.Box):
|
||||
|
||||
fav_bouquet = self._app.current_bouquets[bq_selected]
|
||||
services = self._app.current_services
|
||||
return {services.get(fav_id).picon_id for fav_id in fav_bouquet}
|
||||
|
||||
ids = set()
|
||||
for s in (services.get(fav_id) for fav_id in fav_bouquet):
|
||||
ids.add(s.picon_id)
|
||||
ids.add(get_picon_file_name(s.service))
|
||||
return ids
|
||||
|
||||
def process_provider(self, prv, picons_path):
|
||||
log(f"Getting links to picons for: {prv.name}.\n")
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2018-2022 Dmitriy Yefremov
|
||||
# Copyright (c) 2018-2023 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
|
||||
@@ -54,6 +54,8 @@ class PlayerBox(Gtk.Box):
|
||||
GObject.TYPE_PYOBJECT, (GObject.TYPE_PYOBJECT,))
|
||||
GObject.signal_new("stop", self, GObject.SIGNAL_RUN_LAST,
|
||||
GObject.TYPE_PYOBJECT, (GObject.TYPE_PYOBJECT,))
|
||||
GObject.signal_new("pause", self, GObject.SIGNAL_RUN_LAST,
|
||||
GObject.TYPE_PYOBJECT, (GObject.TYPE_PYOBJECT,))
|
||||
|
||||
self._app = app
|
||||
self._app.connect("fav-clicked", self.on_fav_clicked)
|
||||
@@ -284,7 +286,9 @@ class PlayerBox(Gtk.Box):
|
||||
|
||||
def on_press(self, area, event):
|
||||
if event.button == Gdk.BUTTON_PRIMARY:
|
||||
if event.type == Gdk.EventType.DOUBLE_BUTTON_PRESS:
|
||||
if event.type == Gdk.EventType.BUTTON_PRESS:
|
||||
self.emit("pause", None)
|
||||
elif event.type == Gdk.EventType.DOUBLE_BUTTON_PRESS:
|
||||
self.on_full_screen()
|
||||
|
||||
def on_key_press(self, widget, event):
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.38.2
|
||||
|
||||
Copyright (C) 2018-2022 Dmitriy Yefremov
|
||||
Copyright (C) 2018-2023 Dmitriy Yefremov
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
@@ -12,12 +12,12 @@ Author: Dmitriy Yefremov
|
||||
|
||||
-->
|
||||
<interface domain="demon-editor">
|
||||
<requires lib="gtk+" version="3.20"/>
|
||||
<requires lib="gtk+" version="3.22"/>
|
||||
<!-- interface-css-provider-path style.css -->
|
||||
<!-- interface-license-type all_permissive -->
|
||||
<!-- interface-name DemonEditor -->
|
||||
<!-- interface-description Enigma2 channel and satellites list editor. -->
|
||||
<!-- interface-copyright 2018-2022 Dmitriy Yefremov -->
|
||||
<!-- interface-copyright 2018-2023 Dmitriy Yefremov -->
|
||||
<!-- interface-authors Dmitriy Yefremov -->
|
||||
<object class="GtkAdjustment" id="font_size_adjustment">
|
||||
<property name="lower">8</property>
|
||||
@@ -79,7 +79,7 @@ Author: Dmitriy Yefremov
|
||||
<property name="image">set_default_image</property>
|
||||
<property name="use-stock">False</property>
|
||||
<signal name="activate" handler="on_profile_set_default" swapped="no"/>
|
||||
<accelerator key="d" signal="activate"/>
|
||||
<accelerator key="d" signal="activate" modifiers="Primary"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
@@ -291,7 +291,7 @@ Author: Dmitriy Yefremov
|
||||
<property name="receives-default">True</property>
|
||||
<property name="tooltip-text" translatable="yes">Save</property>
|
||||
<property name="valign">center</property>
|
||||
<accelerator key="s" signal="clicked"/>
|
||||
<accelerator key="s" signal="clicked" modifiers="Primary"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
@@ -508,7 +508,7 @@ Author: Dmitriy Yefremov
|
||||
<property name="icon-name">emblem-default</property>
|
||||
</object>
|
||||
</child>
|
||||
<accelerator key="d" signal="clicked"/>
|
||||
<accelerator key="d" signal="clicked" modifiers="Primary"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
@@ -2737,10 +2737,7 @@ Author: Dmitriy Yefremov
|
||||
<object class="GtkGrid" id="bq_naming_grid">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<property name="border-width">5</property>
|
||||
<property name="row-spacing">5</property>
|
||||
<property name="column-spacing">5</property>
|
||||
<child>
|
||||
@@ -2950,16 +2947,13 @@ Author: Dmitriy Yefremov
|
||||
<object class="GtkBox" id="experimental_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="margin-start">5</property>
|
||||
<property name="margin-end">5</property>
|
||||
<property name="margin-top">5</property>
|
||||
<property name="margin-bottom">5</property>
|
||||
<property name="border-width">5</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">5</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="v5_support_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="sensitive" bind-source="enable_experimental_switch" bind-property="active">False</property>
|
||||
<property name="can-focus">False</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
@@ -2989,6 +2983,46 @@ Author: Dmitriy Yefremov
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="unlimited_buffer_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive" bind-source="enable_experimental_switch" bind-property="active">False</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="tooltip-text" translatable="yes">Enables unlimited copy buffer for the bouquets tab.</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="unlimited_buffer_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="label" translatable="yes">Enable unlimited copy buffer</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="unlimited_buffer_switch">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="halign">end</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="pack-type">end</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
@@ -2998,7 +3032,7 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkBox" id="yt_dl_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="sensitive" bind-source="enable_experimental_switch" bind-property="active">False</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
@@ -3064,7 +3098,7 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkBox" id="yt_dl_update_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="sensitive" bind-source="enable_yt_dl_switch" bind-property="active">False</property>
|
||||
<property name="can-focus">False</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="auto_update_yt_dl_label">
|
||||
@@ -3110,7 +3144,7 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkBox" id="enable_direct_playback_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="sensitive" bind-source="enable_experimental_switch" bind-property="active">False</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="tooltip-text" translatable="yes">Enables direct sending and playback of media links on the receiver</property>
|
||||
<child>
|
||||
@@ -3729,7 +3763,7 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkLabel" id="epg_dat_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive" bind-source="enigma_radio_button" bind-property="active">False</property>
|
||||
<property name="sensitive" bind-source="enigma_radio_button" bind-property="active">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">EPG *.dat file:</property>
|
||||
<property name="xalign">0.019999999552965164</property>
|
||||
@@ -3742,7 +3776,7 @@ Author: Dmitriy Yefremov
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="epg_dat_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive" bind-source="enigma_radio_button" bind-property="active">False</property>
|
||||
<property name="sensitive" bind-source="enigma_radio_button" bind-property="active">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="active">0</property>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2018-2022 Dmitriy Yefremov
|
||||
# Copyright (c) 2018-2023 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
|
||||
@@ -32,10 +32,10 @@ from collections import Counter
|
||||
|
||||
from app.commons import run_task, run_idle, log
|
||||
from app.connections import test_telnet, test_ftp, TestException, test_http, HttpApiException
|
||||
from app.settings import SettingsType, Settings, PlayStreamsMode, IS_LINUX, SEP, IS_WIN
|
||||
from app.settings import SettingsType, Settings, PlayStreamsMode, IS_LINUX, SEP, IS_WIN, IS_DARWIN
|
||||
from app.ui.dialogs import show_dialog, DialogType, get_message, get_chooser_dialog, get_builder
|
||||
from .main_helper import update_entry_data, scroll_to, get_picon_pixbuf
|
||||
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, FavClickMode, DEFAULT_ICON, APP_FONT, IS_GNOME_SESSION
|
||||
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, FavClickMode, DEFAULT_ICON, APP_FONT, IS_GNOME_SESSION, HeaderBar
|
||||
|
||||
|
||||
class SettingsDialog:
|
||||
@@ -180,16 +180,12 @@ class SettingsDialog:
|
||||
self._compress_picons_switch = builder.get_object("compress_picons_switch")
|
||||
self._force_bq_name_switch = builder.get_object("force_bq_name_switch")
|
||||
self._support_ver5_switch = builder.get_object("support_ver5_switch")
|
||||
self._unlimited_buffer_switch = builder.get_object("unlimited_buffer_switch")
|
||||
self._support_http_api_switch = builder.get_object("support_http_api_switch")
|
||||
self._enable_yt_dl_switch = builder.get_object("enable_yt_dl_switch")
|
||||
self._enable_update_yt_dl_switch = builder.get_object("enable_update_yt_dl_switch")
|
||||
self._enable_send_to_switch = builder.get_object("enable_send_to_switch")
|
||||
# EXPERIMENTAL.
|
||||
self._enable_exp_switch = builder.get_object("enable_experimental_switch")
|
||||
self._enable_exp_switch.bind_property("active", builder.get_object("yt_dl_box"), "sensitive")
|
||||
self._enable_yt_dl_switch.bind_property("active", builder.get_object("yt_dl_update_box"), "sensitive")
|
||||
self._enable_exp_switch.bind_property("active", builder.get_object("v5_support_box"), "sensitive")
|
||||
self._enable_exp_switch.bind_property("active", builder.get_object("enable_direct_playback_box"), "sensitive")
|
||||
# Enigma2 only.
|
||||
self._enigma_radio_button.bind_property("active", builder.get_object("bq_naming_grid"), "sensitive")
|
||||
self._enigma_radio_button.bind_property("active", builder.get_object("program_frame"), "sensitive")
|
||||
@@ -211,13 +207,14 @@ class SettingsDialog:
|
||||
[self.init_element_style(el, screen, style_provider) for el in self._digit_elems]
|
||||
self.init_element_style(self._host_field, screen, style_provider)
|
||||
|
||||
if IS_GNOME_SESSION:
|
||||
if IS_GNOME_SESSION or IS_DARWIN:
|
||||
switcher = builder.get_object("main_stack_switcher")
|
||||
switcher.set_margin_top(0)
|
||||
switcher.set_margin_bottom(0)
|
||||
builder.get_object("main_box").remove(switcher)
|
||||
header_bar = Gtk.HeaderBar(visible=True, show_close_button=True)
|
||||
header_bar = HeaderBar()
|
||||
header_bar.set_custom_title(switcher)
|
||||
|
||||
self._dialog.set_titlebar(header_bar)
|
||||
|
||||
self.init_ui_elements()
|
||||
@@ -347,6 +344,7 @@ class SettingsDialog:
|
||||
if self._s_type is SettingsType.ENIGMA_2:
|
||||
self._enable_exp_switch.set_active(self._settings.is_enable_experimental)
|
||||
self._support_ver5_switch.set_active(self._settings.v5_support)
|
||||
self._unlimited_buffer_switch.set_active(self._settings.unlimited_copy_buffer)
|
||||
self._use_http_switch.set_active(self._settings.use_http)
|
||||
self._remove_unused_bq_switch.set_active(self._settings.remove_unused_bouquets)
|
||||
self._keep_power_mode_switch.set_active(self._settings.keep_power_mode)
|
||||
@@ -430,6 +428,7 @@ class SettingsDialog:
|
||||
self._ext_settings.new_color = self._new_color_button.get_rgba().to_string()
|
||||
self._ext_settings.extra_color = self._extra_color_button.get_rgba().to_string()
|
||||
self._ext_settings.v5_support = self._support_ver5_switch.get_active()
|
||||
self._ext_settings.unlimited_copy_buffer = self._unlimited_buffer_switch.get_active()
|
||||
self._ext_settings.use_http = self._use_http_switch.get_active()
|
||||
self._ext_settings.remove_unused_bouquets = self._remove_unused_bq_switch.get_active()
|
||||
self._ext_settings.keep_power_mode = self._keep_power_mode_switch.get_active()
|
||||
@@ -516,6 +515,7 @@ class SettingsDialog:
|
||||
def on_experimental_switch(self, switch, state):
|
||||
if not state:
|
||||
self._support_ver5_switch.set_active(state)
|
||||
self._unlimited_buffer_switch.set_active(state)
|
||||
self._enable_send_to_switch.set_active(state)
|
||||
self._enable_yt_dl_switch.set_active(state)
|
||||
|
||||
|
||||
@@ -18,11 +18,24 @@
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#stack-switch-button {
|
||||
#header-button {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
#header-entry {
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
#header-stack-switcher > button {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
buttonbox {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
paned > separator {
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
@@ -36,10 +49,6 @@ paned.vertical > separator {
|
||||
background-size: 24px 2px;
|
||||
}
|
||||
|
||||
popover .view {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.red-button {
|
||||
background-image: none;
|
||||
background-color: red;
|
||||
|
||||
@@ -162,6 +162,17 @@ def show_notification(message, timeout=10000, urgency=1):
|
||||
notify.show()
|
||||
|
||||
|
||||
class HeaderBar(Gtk.HeaderBar):
|
||||
""" Custom header bar widget. """
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.set_visible(True)
|
||||
self.set_show_close_button(True)
|
||||
|
||||
if IS_DARWIN:
|
||||
self.set_decoration_layout("close,minimize,maximize")
|
||||
|
||||
|
||||
class Page(Enum):
|
||||
""" Main stack widget page. """
|
||||
INFO = "info"
|
||||
@@ -269,6 +280,14 @@ class Column(IntEnum):
|
||||
IPTV_FAV_ID = 5
|
||||
IPTV_PICON_ID = 6
|
||||
IPTV_TOOLTIP = 7
|
||||
# EPG view
|
||||
EPG_SERVICE = 0
|
||||
EPG_TITLE = 1
|
||||
EPG_START = 2
|
||||
EPG_END = 3
|
||||
EPG_LENGTH = 4
|
||||
EPG_DESC = 5
|
||||
EPG_DATA = 6
|
||||
|
||||
def __index__(self):
|
||||
""" Overridden to get the index in slices directly """
|
||||
|
||||
@@ -18,3 +18,7 @@ grid > button {
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
popover .view {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2018-2022 Dmitriy Yefremov
|
||||
# Copyright (c) 2018-2023 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
|
||||
@@ -39,11 +39,12 @@ from app.eparser import Satellite, Transponder
|
||||
from app.eparser.ecommons import (PLS_MODE, get_key_by_value, POLARIZATION, FEC, SYSTEM, MODULATION, Terrestrial, Cable,
|
||||
T_SYSTEM, BANDWIDTH, CONSTELLATION, T_FEC, GUARD_INTERVAL, TRANSMISSION_MODE,
|
||||
HIERARCHY, Inversion, C_MODULATION, FEC_DEFAULT, TerTransponder, CableTransponder)
|
||||
from app.settings import IS_DARWIN
|
||||
from app.tools.satellites import SatellitesParser, SatelliteSource, ServicesParser
|
||||
from ..dialogs import show_dialog, DialogType, get_message, get_builder
|
||||
from ..main_helper import append_text_to_tview, get_base_model, on_popup_menu
|
||||
from ..search import SearchProvider
|
||||
from ..uicommons import Gtk, Gdk, UI_RESOURCES_PATH, IS_GNOME_SESSION
|
||||
from ..uicommons import Gtk, Gdk, UI_RESOURCES_PATH, IS_GNOME_SESSION, HeaderBar
|
||||
|
||||
_DIALOGS_UI_PATH = f"{UI_RESOURCES_PATH}xml{os.sep}dialogs.glade"
|
||||
|
||||
@@ -432,7 +433,6 @@ class UpdateDialog:
|
||||
update_button = builder.get_object("sat_update_button")
|
||||
self._sat_view.bind_property("sensitive", update_button, "sensitive")
|
||||
self._sat_view.bind_property("sensitive", self._source_box, "sensitive")
|
||||
self._sat_view.bind_property("sensitive", self._source_box, "sensitive")
|
||||
self._sat_view.bind_property("sensitive", self._receive_button, "sensitive")
|
||||
self._receive_button.bind_property("visible", update_button, "visible")
|
||||
# Filter
|
||||
@@ -457,6 +457,20 @@ class UpdateDialog:
|
||||
builder.get_object("sat_update_search_up_button"))
|
||||
builder.get_object("sat_update_find_button").connect("toggled", search_provider.on_search_toggled)
|
||||
|
||||
if IS_GNOME_SESSION or IS_DARWIN:
|
||||
header_bar = HeaderBar()
|
||||
builder.get_object("sat_update_header").set_visible(False)
|
||||
header_box = builder.get_object("satellites_update_header_box")
|
||||
header_box.remove(self._source_box)
|
||||
header_bar.pack_start(self._source_box)
|
||||
action_box = builder.get_object("sat_update_left_action_box")
|
||||
header_box.remove(action_box)
|
||||
header_bar.pack_start(action_box)
|
||||
action_box = builder.get_object("sat_update_right_action_box")
|
||||
header_box.remove(action_box)
|
||||
header_bar.pack_end(action_box)
|
||||
self._window.set_titlebar(header_bar)
|
||||
|
||||
window_size = self._settings.get(self._size_name)
|
||||
if window_size:
|
||||
self._window.resize(*window_size)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018-2022 Dmitriy Yefremov
|
||||
Copyright (c) 2018-2023 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
|
||||
@@ -27,11 +27,11 @@ Author: Dmitriy Yefremov
|
||||
|
||||
-->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.20"/>
|
||||
<requires lib="gtk+" version="3.22"/>
|
||||
<!-- interface-css-provider-path style.css -->
|
||||
<!-- interface-license-type mit -->
|
||||
<!-- interface-name DemonEditor -->
|
||||
<!-- interface-copyright 2018-2022 Dmitriy Yefremov -->
|
||||
<!-- interface-copyright 2018-2023 Dmitriy Yefremov -->
|
||||
<!-- interface-authors Dmitriy Yefremov -->
|
||||
<object class="GtkListStore" id="cable_model">
|
||||
<columns>
|
||||
@@ -327,6 +327,7 @@ Author: Dmitriy Yefremov
|
||||
<child type="center">
|
||||
<object class="GtkStackSwitcher" id="stack_switcher">
|
||||
<property name="visible">True</property>
|
||||
<property name="name">header-stack-switcher</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stack">sat_stack</property>
|
||||
</object>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018-2022 Dmitriy Yefremov
|
||||
Copyright (c) 2018-2023 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
|
||||
@@ -27,11 +27,11 @@ Author: Dmitriy Yefremov
|
||||
|
||||
-->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.20"/>
|
||||
<requires lib="gtk+" version="3.22"/>
|
||||
<!-- interface-css-provider-path style.css -->
|
||||
<!-- interface-license-type mit -->
|
||||
<!-- interface-name DemonEditor -->
|
||||
<!-- interface-copyright 2018-2022 Dmitriy Yefremov -->
|
||||
<!-- interface-copyright 2018-2023 Dmitriy Yefremov -->
|
||||
<!-- interface-authors Dmitriy Yefremov -->
|
||||
<object class="GtkAdjustment" id="pos_adjustment">
|
||||
<property name="upper">180</property>
|
||||
@@ -199,7 +199,7 @@ Author: Dmitriy Yefremov
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButtonBox" id="sat_update_right_action_box">
|
||||
<object class="GtkButtonBox" id="sat_update_left_action_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="layout_style">expand</property>
|
||||
@@ -262,7 +262,7 @@ Author: Dmitriy Yefremov
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButtonBox" id="sat_update_left_action_box">
|
||||
<object class="GtkButtonBox" id="sat_update_right_action_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="layout_style">expand</property>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/bin/bash
|
||||
VER="3.1.0_Alpha"
|
||||
VER="3.3.1_Beta"
|
||||
B_PATH="dist/DemonEditor"
|
||||
DEB_PATH="$B_PATH/usr/share/demoneditor"
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
Package: demon-editor
|
||||
Version: 3.1.0-Alpha
|
||||
Version: 3.3.1-Beta
|
||||
Section: utils
|
||||
Priority: optional
|
||||
Architecture: all
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -80,8 +80,8 @@ app = BUNDLE(coll,
|
||||
'CFBundleGetInfoString': "Enigma2 channel and satellite editor",
|
||||
'LSApplicationCategoryType': 'public.app-category.utilities',
|
||||
'LSMinimumSystemVersion': '10.13',
|
||||
'CFBundleShortVersionString': f"3.1.0.{BUILD_DATE} Alpha",
|
||||
'NSHumanReadableCopyright': u"Copyright © 2022, Dmitriy Yefremov",
|
||||
'CFBundleShortVersionString': f"3.3.1.{BUILD_DATE} Beta",
|
||||
'NSHumanReadableCopyright': u"Copyright © 2023, Dmitriy Yefremov",
|
||||
'NSRequiresAquaSystemAppearance': 'false',
|
||||
'NSHighResolutionCapable': 'true'
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (C) 2018-2021 Dmitriy Yefremov
|
||||
# Copyright (C) 2018-2023 Dmitriy Yefremov
|
||||
# This file is distributed under the MIT license.
|
||||
#
|
||||
#
|
||||
@@ -1387,3 +1387,50 @@ msgstr "Штодня"
|
||||
|
||||
msgid "Assign reference"
|
||||
msgstr "Прысвоіць спасылку"
|
||||
|
||||
msgid "Specify hostname or IP address"
|
||||
msgstr "Задайце імя хоста або IP-адрас"
|
||||
|
||||
msgid "Default selection"
|
||||
msgstr "Выбар па змаўчанні"
|
||||
|
||||
msgid "Don't change power state"
|
||||
msgstr "Не змяняць стан сілкавання"
|
||||
|
||||
msgid "Don't toggle standby mode when updating bouquets and services."
|
||||
msgstr "Не перамыкаць у рэжым чакання пры абнаўленні букетаў і сэрвісаў."
|
||||
|
||||
msgid "Region"
|
||||
msgstr "Рэгіён"
|
||||
|
||||
msgid "Provider"
|
||||
msgstr "Правайдар"
|
||||
|
||||
msgid "Enables upload as an archive if a large number of picon (> 1000) is selected.\n"
|
||||
" Recommended only if you have external storage."
|
||||
msgstr "Улучае загрузку ў выглядзе архіва, калі абрана вялікая колькасць пiконаў (> 1000).\n"
|
||||
" Рэкамендуецца, толькі калі ў вас ёсць вонкавае сховішча."
|
||||
|
||||
msgid "Clear \"New\" flag"
|
||||
msgstr "Здаліць сцяжок \"New\""
|
||||
|
||||
msgid "Group by"
|
||||
msgstr "Групаваць па"
|
||||
|
||||
msgid "Replace existing"
|
||||
msgstr "Замяніць існуючыя"
|
||||
|
||||
msgid "Already exists"
|
||||
msgstr "Ужо існуе"
|
||||
|
||||
msgid "Enable unlimited copy buffer"
|
||||
msgstr "Уключыць неабмежаваны буфер капіявання"
|
||||
|
||||
msgid "Enables unlimited copy buffer for the bouquets tab."
|
||||
msgstr "Улучае неабмежаваны буфер капіявання для ўкладкі букетаў."
|
||||
|
||||
msgid "Start time"
|
||||
msgstr "Пачатак"
|
||||
|
||||
msgid "End time"
|
||||
msgstr "Сканчэнне"
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
# This file is distributed under the MIT license.
|
||||
#
|
||||
# Charly, 2019.
|
||||
# Dmitriy Yefremov, 2020-2021.
|
||||
# Thomas Schmidt, 2021
|
||||
# Dmitriy Yefremov, 2020-2023.
|
||||
# Thomas Schmidt, 2021.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Last-Translator: Dmitriy Yefremov\n"
|
||||
@@ -1401,3 +1401,50 @@ msgstr "Täglich"
|
||||
|
||||
msgid "Assign reference"
|
||||
msgstr "Referenz zuweisen"
|
||||
|
||||
msgid "Specify hostname or IP address"
|
||||
msgstr "Hostname oder IP-Adresse angeben"
|
||||
|
||||
msgid "Default selection"
|
||||
msgstr "Standardauswahl"
|
||||
|
||||
msgid "Don't change power state"
|
||||
msgstr "Energiezustand nicht ändern"
|
||||
|
||||
msgid "Don't toggle standby mode when updating bouquets and services."
|
||||
msgstr "Schalten beim Aktualisieren von Bouquets und Services nicht in den Standby-Modus um."
|
||||
|
||||
msgid "Region"
|
||||
msgstr "Region"
|
||||
|
||||
msgid "Provider"
|
||||
msgstr "Provider"
|
||||
|
||||
msgid "Enables upload as an archive if a large number of picon (> 1000) is selected.\n"
|
||||
" Recommended only if you have external storage."
|
||||
msgstr "Ermöglicht das Hochladen als Archiv, wenn eine große Anzahl von Picons (> 1000)"
|
||||
" ausgewählt ist. Empfohlen nur, wenn einen externen Speicher verfügt wird."
|
||||
|
||||
msgid "Clear \"New\" flag"
|
||||
msgstr "Das \"Neu\"-Flag entfernen"
|
||||
|
||||
msgid "Group by"
|
||||
msgstr "Gruppieren nach"
|
||||
|
||||
msgid "Replace existing"
|
||||
msgstr "Vorhandene ersetzen"
|
||||
|
||||
msgid "Already exists"
|
||||
msgstr "Bereits vorhanden"
|
||||
|
||||
msgid "Enable unlimited copy buffer"
|
||||
msgstr "Unbegrenzte Zwischenablage aktivieren"
|
||||
|
||||
msgid "Enables unlimited copy buffer for the bouquets tab."
|
||||
msgstr "Aktiviert unbegrenzte Zwischenablage für die Bouquets-Tab."
|
||||
|
||||
msgid "Start time"
|
||||
msgstr "Anfangszeit"
|
||||
|
||||
msgid "End time"
|
||||
msgstr "Endzeit"
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"POT-Creation-Date: \n"
|
||||
"PO-Revision-Date: \n"
|
||||
"Last-Translator: Víctor Pont\n"
|
||||
"Last-Translator: Frank Neirynck\n"
|
||||
"Language-Team: \n"
|
||||
"Language: es\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@@ -1382,3 +1382,62 @@ msgstr "Añadir marcador"
|
||||
|
||||
msgid "All bouquets"
|
||||
msgstr "Todos los bouquets"
|
||||
|
||||
msgid "Playback from the main list"
|
||||
msgstr "Reproducción desde la lista principal"
|
||||
|
||||
msgid "Enables URL parsing using youtube-dl to get direct links to media."
|
||||
msgstr "Habilita el análisis de URL usando youtube-dl para obtener enlaces directos a los medios."
|
||||
|
||||
msgid "Permissions..."
|
||||
msgstr "Permisos..."
|
||||
|
||||
msgid "Display EPG in bouquet list"
|
||||
msgstr "Mostrar EPG en la lista de bouquet"
|
||||
|
||||
msgid "EPG *.dat file:"
|
||||
msgstr "Archivo EPG *.dat:"
|
||||
|
||||
msgid "Use HTTP to reload data in the receiver"
|
||||
msgstr "Use HTTP para recargar datos en el receptor"
|
||||
|
||||
msgid "Enable picons compression"
|
||||
msgstr "Habilitar la compresión de picons"
|
||||
|
||||
msgid "Update interval (sec):"
|
||||
msgstr "Intervalo de actualización (sec):"
|
||||
|
||||
msgid "Update:"
|
||||
msgstr "Actualización:"
|
||||
|
||||
msgid "Daily"
|
||||
msgstr "Diariamente"
|
||||
|
||||
msgid "Assign reference"
|
||||
msgstr "Asignar referencia"
|
||||
|
||||
msgid "Specify hostname or IP address"
|
||||
msgstr "Especifique el nombre de host o la dirección IP"
|
||||
|
||||
msgid "Default selection"
|
||||
msgstr "Selección predeterminada"
|
||||
|
||||
msgid "Don't change power state"
|
||||
msgstr "No apagues el dispositivo"
|
||||
|
||||
msgid "Don't toggle standby mode when updating bouquets and services."
|
||||
msgstr "No cambie el modo de espera al actualizar bouquets y servicios."
|
||||
|
||||
msgid "Region"
|
||||
msgstr "Región"
|
||||
|
||||
msgid "Provider"
|
||||
msgstr "Proveedor"
|
||||
|
||||
msgid "Enables upload as an archive if a large number of picon (> 1000) is selected.\n"
|
||||
" Recommended only if you have external storage."
|
||||
msgstr "Habilita la carga como un archivo si se selecciona una gran cantidad de picon (> 1000).\n"
|
||||
" Recomendado solo si tienes almacenamiento externo."
|
||||
|
||||
msgid "Clear \"New\" flag"
|
||||
msgstr "Limpiar \"Nuevo\" flag"
|
||||
|
||||
@@ -2,19 +2,19 @@
|
||||
# This file is distributed under the MIT license.
|
||||
#
|
||||
#
|
||||
# Massimo Pissarello <mapi68@gmail.com>, 2022.
|
||||
# Massimo Pissarello <mapi68@gmail.com>, 2022, 2023.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"PO-Revision-Date: 2023-01-27 19:45+0100\n"
|
||||
"Last-Translator: Massimo Pissarello <mapi68@gmail.com>\n"
|
||||
"Language-Team: Italian <>\n"
|
||||
"Language: it\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"PO-Revision-Date: 2022-10-27 03:28+0200\n"
|
||||
"Project-Id-Version: \n"
|
||||
"Language-Team: Italian <>\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Generator: Lokalize 22.08.2\n"
|
||||
"X-Generator: Lokalize 22.12.1\n"
|
||||
|
||||
msgid "translator-credits"
|
||||
msgstr "Massimo Pissarello"
|
||||
@@ -42,7 +42,7 @@ msgid "Pol"
|
||||
msgstr "Pol"
|
||||
|
||||
msgid "System"
|
||||
msgstr "System"
|
||||
msgstr "Sistema"
|
||||
|
||||
msgid "Pos"
|
||||
msgstr "Pos"
|
||||
@@ -51,7 +51,7 @@ msgid "Num"
|
||||
msgstr "Num"
|
||||
|
||||
msgid "Current IP:"
|
||||
msgstr "IP/Host attuale:"
|
||||
msgstr "IP/Host connesso:"
|
||||
|
||||
msgid "Assign"
|
||||
msgstr "Assegna"
|
||||
@@ -156,7 +156,7 @@ msgid "Open"
|
||||
msgstr "Apri"
|
||||
|
||||
msgid "Parent lock On/Off Ctrl + L"
|
||||
msgstr "Blocco Genitori On/Off Ctrl + L"
|
||||
msgstr "Blocco genitori On/Off Ctrl + L"
|
||||
|
||||
msgid "Picons"
|
||||
msgstr "Picon"
|
||||
@@ -212,8 +212,8 @@ msgstr "Percorso dati corrente:"
|
||||
msgid "Data:"
|
||||
msgstr "Dati:"
|
||||
|
||||
msgid "Enigma2 channel and satellite list editor for GNU/Linux."
|
||||
msgstr "Editor di liste canali e satelliti per Enigma2 su GNU/Linux."
|
||||
msgid "Enigma2 channel and satellite list editor."
|
||||
msgstr "Editor di elenchi di canali e satelliti per Enigma2."
|
||||
|
||||
msgid "Host:"
|
||||
msgstr "Host:"
|
||||
@@ -287,7 +287,7 @@ msgid "Next stream in the list"
|
||||
msgstr "Stream successivo nell'elenco"
|
||||
|
||||
msgid "Toggle in fullscreen"
|
||||
msgstr "Attiva/disattiva lo schermo intero"
|
||||
msgstr "Attiva/disattiva schermo intero"
|
||||
|
||||
msgid "Close"
|
||||
msgstr "Chiudi"
|
||||
@@ -308,8 +308,8 @@ msgstr "Formato nome picon:"
|
||||
msgid "Resize:"
|
||||
msgstr "Ridimensiona:"
|
||||
|
||||
msgid "Current picons path:"
|
||||
msgstr "Percorso attuale picon:"
|
||||
msgid "Current picons path"
|
||||
msgstr "Percorso picon attuale"
|
||||
|
||||
msgid "Receiver picons path:"
|
||||
msgstr "Percorso picon sul ricevitore:"
|
||||
@@ -324,7 +324,7 @@ msgid "Downloader"
|
||||
msgstr "Scarica"
|
||||
|
||||
msgid "Converter"
|
||||
msgstr "Convertitore"
|
||||
msgstr "Converti"
|
||||
|
||||
msgid "Convert"
|
||||
msgstr "Converti"
|
||||
@@ -348,11 +348,11 @@ msgid "Load satellite providers."
|
||||
msgstr "Carica provider satellitari"
|
||||
|
||||
msgid ""
|
||||
"To automatically set the identifiers for picons,\nfirst load the required"
|
||||
" services list into the main application window."
|
||||
"To automatically set the identifiers for picons,\n"
|
||||
"first load the required services list into the main application window."
|
||||
msgstr ""
|
||||
"Per impostare automaticamente gli identificatori per i picon,\nprima carica"
|
||||
" il file richiesto dell' elenco dei servizi nella finestra principale"
|
||||
" il file richiesto dell'elenco dei servizi nella finestra principale"
|
||||
" dell'applicazione."
|
||||
|
||||
# Satellites editor
|
||||
@@ -400,7 +400,9 @@ msgstr "Dati servizio"
|
||||
msgid "Transponder details"
|
||||
msgstr "Dettagli transponder"
|
||||
|
||||
msgid "Changes will be applied to all services of this transponder!\nContinue?"
|
||||
msgid ""
|
||||
"Changes will be applied to all services of this transponder!\n"
|
||||
"Continue?"
|
||||
msgstr ""
|
||||
"Le modifiche verranno applicate a tutti i servizi di questo"
|
||||
" transponder!\nContinuare?"
|
||||
@@ -412,7 +414,7 @@ msgid "Namespace"
|
||||
msgstr "Spazio dei nomi"
|
||||
|
||||
msgid "Flags:"
|
||||
msgstr "Flags:"
|
||||
msgstr "Flag:"
|
||||
|
||||
msgid "Delays (ms):"
|
||||
msgstr "Ritardo (ms)"
|
||||
@@ -450,9 +452,9 @@ msgid "Reset to default"
|
||||
msgstr "Torna alle impostazioni predefinite"
|
||||
|
||||
msgid "IPTV streams list configuration"
|
||||
msgstr "Lista configurazione stream IPTV"
|
||||
msgstr "Configurazione elenchi stream IPTV"
|
||||
|
||||
#Settings dialog
|
||||
# Settings dialog
|
||||
msgid "Preferences"
|
||||
msgstr "Preferenze"
|
||||
|
||||
@@ -497,7 +499,7 @@ msgstr "Percorso file locali:"
|
||||
|
||||
# Dialogs messages
|
||||
msgid "Error. No bouquet is selected!"
|
||||
msgstr "Errore, nessun bouquet selezionato"
|
||||
msgstr "Errore. Nessun bouquet selezionato!"
|
||||
|
||||
msgid "This item is not allowed to be removed!"
|
||||
msgstr "Questo elemento non può essere rimosso!"
|
||||
@@ -510,7 +512,7 @@ msgstr "Non consentito in questo contesto!"
|
||||
|
||||
msgid "Please, download files from receiver or setup your path for read data!"
|
||||
msgstr ""
|
||||
"Per favore, scarica i file dal ricevitore o imposta il tuo percorso per"
|
||||
"Per favore, scarica i file dal ricevitore o imposta il percorso da cui"
|
||||
" leggere i dati!"
|
||||
|
||||
msgid "Reading data error!"
|
||||
@@ -523,10 +525,10 @@ msgid "Not implemented yet!"
|
||||
msgstr "Funzionalità non ancora sviluppata!"
|
||||
|
||||
msgid "The text of marker is empty, please try again!"
|
||||
msgstr "Il testo del marcatore é vuoto, riprova di nuovo!"
|
||||
msgstr "Il testo del marcatore è vuoto, riprova!"
|
||||
|
||||
msgid "Please, select only one item!"
|
||||
msgstr "Per favore, seleziona un solo elemento!"
|
||||
msgstr "Per favore, seleziona solo un elemento!"
|
||||
|
||||
msgid "No png file is selected!"
|
||||
msgstr "Nessun file png selezionato!"
|
||||
@@ -535,7 +537,7 @@ msgid "No profile selected!"
|
||||
msgstr "Nessun profilo selezionato!"
|
||||
|
||||
msgid "No reference is present!"
|
||||
msgstr "Riferimento mancante!"
|
||||
msgstr "Nessun riferimento presente!"
|
||||
|
||||
msgid "No selected item!"
|
||||
msgstr "Nessun elemento selezionato!"
|
||||
@@ -559,7 +561,7 @@ msgid "No satellite is selected!"
|
||||
msgstr "Nessun satellite selezionato!"
|
||||
|
||||
msgid "Please, select only one satellite!"
|
||||
msgstr "Per favore, seleziona un solo satellite!"
|
||||
msgstr "Per favore, seleziona solo un satellite!"
|
||||
|
||||
msgid "Please check your parameters and try again."
|
||||
msgstr "Per favore, controlla i tuoi parametri e riprova di nuovo."
|
||||
@@ -590,7 +592,7 @@ msgid "No changes required!"
|
||||
msgstr "Non sono richiesti cambiamenti!"
|
||||
|
||||
msgid "This list does not contains IPTV streams!"
|
||||
msgstr "La lista non contiene stream IPTV!"
|
||||
msgstr "L'elenco non contiene stream IPTV!"
|
||||
|
||||
msgid "New empty configuration"
|
||||
msgstr "Nuova configurazione vuota"
|
||||
@@ -617,7 +619,7 @@ msgid "Backups"
|
||||
msgstr "Backup"
|
||||
|
||||
msgid "Backup path:"
|
||||
msgstr "Percorso dei backup:"
|
||||
msgstr "Percorso backup:"
|
||||
|
||||
msgid "Restore bouquets"
|
||||
msgstr "Ripristina bouquet"
|
||||
@@ -632,7 +634,7 @@ msgid "Before downloading from the receiver"
|
||||
msgstr "Prima di scaricare dal ricevitore"
|
||||
|
||||
msgid "Set background color for the services"
|
||||
msgstr "Imposta il colore di sfondo per i servizi"
|
||||
msgstr "Imposta colore di sfondo per i servizi"
|
||||
|
||||
msgid "Marked as new:"
|
||||
msgstr "Contrassegnato come nuovo:"
|
||||
@@ -644,7 +646,7 @@ msgid "Select"
|
||||
msgstr "Seleziona"
|
||||
|
||||
msgid "About"
|
||||
msgstr "A proposito"
|
||||
msgstr "Informazioni su"
|
||||
|
||||
msgid "Exit"
|
||||
msgstr "Esci"
|
||||
@@ -652,7 +654,7 @@ msgstr "Esci"
|
||||
msgid "Tools"
|
||||
msgstr "Strumenti"
|
||||
|
||||
#Import
|
||||
# Import
|
||||
msgid "Import"
|
||||
msgstr "Importa"
|
||||
|
||||
@@ -663,7 +665,7 @@ msgid "Bouquets and services"
|
||||
msgstr "Bouquet e servizi"
|
||||
|
||||
msgid "The main list does not contain services for this bouquet!"
|
||||
msgstr "La lista principale non contiene servizi per questo bouquet!"
|
||||
msgstr "L'elenco principale non contiene servizi per questo bouquet!"
|
||||
|
||||
msgid "No bouquet file is selected!"
|
||||
msgstr "Nessun file bouquet selezionato!"
|
||||
@@ -690,10 +692,10 @@ msgid "Disabled"
|
||||
msgstr "Disabilitato"
|
||||
|
||||
msgid "Enable lamedb ver. 5 support"
|
||||
msgstr "Abilita il supporto a lamedb v5"
|
||||
msgstr "Abilita supporto a lamedb v5"
|
||||
|
||||
msgid "Enable HTTP API"
|
||||
msgstr "Abilita le API HTTP"
|
||||
msgstr "Abilita API HTTP"
|
||||
|
||||
msgid "Switch(zap) the channel(Ctrl + Z)"
|
||||
msgstr "Cambia (zap) canale (Ctrl + Z)"
|
||||
@@ -720,19 +722,19 @@ msgid "Service names source:"
|
||||
msgstr "Sorgente nomi dei servizi:"
|
||||
|
||||
msgid "Main service list"
|
||||
msgstr "Lista servizi principali:"
|
||||
msgstr "Elenco servizi principali:"
|
||||
|
||||
msgid "XML file"
|
||||
msgstr "File XML"
|
||||
|
||||
msgid "Use web source"
|
||||
msgstr "Usa la fonte web"
|
||||
msgstr "Utilizza fonte web"
|
||||
|
||||
msgid "Url to *.xml.gz file:"
|
||||
msgstr "Da URL a file *.xml.gz:"
|
||||
|
||||
msgid "Enable filtering"
|
||||
msgstr "Abilita filtraggio"
|
||||
msgstr "Abilita filtro"
|
||||
|
||||
msgid "Filter by presence in the epg.dat file."
|
||||
msgstr "Filtra per presenza nel file epg.dat."
|
||||
@@ -771,14 +773,14 @@ msgid "Count of successfully configured services:"
|
||||
msgstr "Conteggio servizi configurato correttamente:"
|
||||
|
||||
msgid ""
|
||||
"Current epg.dat file does not contains references for the services of this"
|
||||
" bouquet!"
|
||||
"Current epg.dat file does not contains references for the services of this "
|
||||
"bouquet!"
|
||||
msgstr ""
|
||||
"L'attuale file epg.dat non contiene riferimenti per i servizi di questo"
|
||||
" bouquet!"
|
||||
|
||||
msgid "Use HTTP"
|
||||
msgstr "Usa HTTP"
|
||||
msgstr "Utilizza HTTP"
|
||||
|
||||
msgid "Close playback"
|
||||
msgstr "Ferma riproduzione"
|
||||
@@ -787,7 +789,8 @@ msgid "Import YouTube playlist"
|
||||
msgstr "Importa playlist YouTube"
|
||||
|
||||
msgid ""
|
||||
"Found a link to the YouTube resource!\nTry to get a direct link to the video?"
|
||||
"Found a link to the YouTube resource!\n"
|
||||
"Try to get a direct link to the video?"
|
||||
msgstr ""
|
||||
"Trovato un link verso una risorsa YouTube!\nProvo ad ottenere un link diretto"
|
||||
" per questo video?"
|
||||
@@ -852,7 +855,7 @@ msgid "File"
|
||||
msgstr "File"
|
||||
|
||||
msgid "Picons manager"
|
||||
msgstr "Gestore Picons"
|
||||
msgstr "Gestore picon"
|
||||
|
||||
msgid "Explorer"
|
||||
msgstr "Esplora"
|
||||
@@ -982,7 +985,7 @@ msgstr ""
|
||||
"Mostra informazioni dettagliate come suggerimenti nell'elenco dei bouquet"
|
||||
|
||||
msgid "Enable alternate bouquet file naming"
|
||||
msgstr "Abilita denominazione file bouquet alternativa"
|
||||
msgstr "Abilita denominazione alternativa file bouquet"
|
||||
|
||||
msgid "Allows you to name bouquet files using their names."
|
||||
msgstr "Ti permette di nominare i file del bouquet usando i loro nomi."
|
||||
@@ -1003,7 +1006,7 @@ msgid "Gtk3 Themes and Icons:"
|
||||
msgstr "Temi e icone Gtk3:"
|
||||
|
||||
msgid "Deleting data..."
|
||||
msgstr "Eliminazione dei dati..."
|
||||
msgstr "Eliminazione dati..."
|
||||
|
||||
msgid "Download from the receiver"
|
||||
msgstr "Scarica dal ricevitore"
|
||||
@@ -1024,7 +1027,7 @@ msgid "Filter services"
|
||||
msgstr "Filtro servizi"
|
||||
|
||||
msgid "Filter services in the main list."
|
||||
msgstr "Filtra i servizi nella lista principale."
|
||||
msgstr "Filtra i servizi nell'elenco principale."
|
||||
|
||||
msgid "Destination:"
|
||||
msgstr "Destinazione:"
|
||||
@@ -1035,11 +1038,15 @@ msgstr "SPERIMENTALE!"
|
||||
msgid "Sorting data..."
|
||||
msgstr "Ordinamento dati..."
|
||||
|
||||
msgid "There are unsaved changes.\n\n\t Save them now?"
|
||||
msgid ""
|
||||
"There are unsaved changes.\n"
|
||||
"\n"
|
||||
"\t Save them now?"
|
||||
msgstr "Sono presenti modifiche non salvate.\n\n\t Salvarle ora?"
|
||||
|
||||
msgid ""
|
||||
"Are you sure you want to change the order\n\t of services in this bouquet?"
|
||||
"Are you sure you want to change the order\n"
|
||||
"\t of services in this bouquet?"
|
||||
msgstr ""
|
||||
"Sei sicuro di voler cambiare l'ordine\n\t dei servizi in questo bouquet?"
|
||||
|
||||
@@ -1236,16 +1243,18 @@ msgid "DreamOS only!"
|
||||
msgstr "Solo DreamOS!"
|
||||
|
||||
msgid "A similar service is already in this list!"
|
||||
msgstr "Un servizio simile è già presente nella lista!"
|
||||
msgstr "Un servizio simile è già presente nell'elenco!"
|
||||
|
||||
msgid "Play mode has been changed!\nRestart the program to apply the settings."
|
||||
msgid ""
|
||||
"Play mode has been changed!\n"
|
||||
"Restart the program to apply the settings."
|
||||
msgstr ""
|
||||
"La modalità di riproduzione è stata modificata!\nRiavvia il programma per"
|
||||
" applicare le impostazioni."
|
||||
|
||||
msgid "Set values for TID, NID and Namespace for correct naming of the picon!"
|
||||
msgid "Set values for TID, NID and Namespace for correct naming of the picons!"
|
||||
msgstr ""
|
||||
"Imposta i valori per TID, NID e Namespace per la corretta denominazione del"
|
||||
"Imposta i valori per TID, NID e Namespace per la corretta denominazione dei"
|
||||
" picon!"
|
||||
|
||||
msgid "Streams detected:"
|
||||
@@ -1258,13 +1267,13 @@ msgid "Errors:"
|
||||
msgstr "Errori:"
|
||||
|
||||
msgid "Use to play streams:"
|
||||
msgstr "Riproduci gli stream con:"
|
||||
msgstr "Riproduci stream con:"
|
||||
|
||||
msgid "Font in the lists:"
|
||||
msgstr "Carattere nelle liste:"
|
||||
msgstr "Carattere negli elenchi:"
|
||||
|
||||
msgid "Picons size in the lists:"
|
||||
msgstr "Dimensione picon nelle liste:"
|
||||
msgstr "Dimensione picon negli elenchi:"
|
||||
|
||||
msgid "Logo size in tooltips:"
|
||||
msgstr "Dimensioni logo nelle descrizioni comandi:"
|
||||
@@ -1294,7 +1303,7 @@ msgid "Help"
|
||||
msgstr "Aiuto"
|
||||
|
||||
msgid "HTTP API is not activated. Check your settings!"
|
||||
msgstr "L'API HTTP non è attivata. Controlla le tue impostazioni!"
|
||||
msgstr "API HTTP non attivata. Controlla le tue impostazioni!"
|
||||
|
||||
msgid "Add picons"
|
||||
msgstr "Aggiungi picon"
|
||||
@@ -1306,7 +1315,7 @@ msgid "Title"
|
||||
msgstr "Titolo"
|
||||
|
||||
msgid "Time"
|
||||
msgstr "Time"
|
||||
msgstr "Orario"
|
||||
|
||||
msgid "Length"
|
||||
msgstr "Durata"
|
||||
@@ -1342,8 +1351,8 @@ msgid "This may change the settings of other profiles!"
|
||||
msgstr "Questo potrebbe modificare le impostazioni di altri profili!"
|
||||
|
||||
msgid ""
|
||||
"Drag the services to the desired picon or picon to the list of selected"
|
||||
" services."
|
||||
"Drag the services to the desired picon or picon to the list of selected "
|
||||
"services."
|
||||
msgstr ""
|
||||
"Trascina i servizi sul picon desiderato o il picon sull'elenco dei servizi"
|
||||
" selezionati."
|
||||
@@ -1357,7 +1366,7 @@ msgid "New sub-bouquet"
|
||||
msgstr "Nuovo sotto-bouquet"
|
||||
|
||||
msgid "Mark not presented in Bouquets"
|
||||
msgstr "Seleziona servizi non presenti nei bouquet"
|
||||
msgstr "Contrassegna non presenti nei bouquet"
|
||||
|
||||
msgid "Not in Bouquets"
|
||||
msgstr "Non nei bouquet"
|
||||
@@ -1396,7 +1405,7 @@ msgid "All bouquets"
|
||||
msgstr "Tutti i bouquet"
|
||||
|
||||
msgid "Playback from the main list"
|
||||
msgstr "Riproduci dalla lista principale"
|
||||
msgstr "Riproduci dall'elenco principale"
|
||||
|
||||
msgid "Enables URL parsing using youtube-dl to get direct links to media."
|
||||
msgstr ""
|
||||
@@ -1429,3 +1438,55 @@ msgstr "Quotidiano"
|
||||
|
||||
msgid "Assign reference"
|
||||
msgstr "Assegna riferimento"
|
||||
|
||||
msgid "Specify hostname or IP address"
|
||||
msgstr "Specifica il nome host o l'indirizzo IP"
|
||||
|
||||
msgid "Default selection"
|
||||
msgstr "Selezione predefinita"
|
||||
|
||||
msgid "Don't change power state"
|
||||
msgstr "Non modificare lo stato di alimentazione"
|
||||
|
||||
msgid "Don't toggle standby mode when updating bouquets and services."
|
||||
msgstr ""
|
||||
"Non attivare la modalità standby durante l'aggiornamento di bouquet e servizi."
|
||||
|
||||
msgid "Region"
|
||||
msgstr "Regione"
|
||||
|
||||
msgid "Provider"
|
||||
msgstr "Provider"
|
||||
|
||||
msgid ""
|
||||
"Enables upload as an archive if a large number of picon (> 1000) is"
|
||||
" selected.\n"
|
||||
" Recommended only if you have external storage."
|
||||
msgstr ""
|
||||
"Abilita il caricamento come archivio compresso se viene selezionato un numero"
|
||||
" elevato di picon (> 1000). Consigliato solo se si dispone di memoria esterna."
|
||||
|
||||
msgid "Clear \"New\" flag"
|
||||
msgstr "Rimuovi il flag \"Nuovo\""
|
||||
|
||||
msgid "Group by"
|
||||
msgstr "Raggruppa per"
|
||||
|
||||
msgid "Replace existing"
|
||||
msgstr "Sostituisci esistente"
|
||||
|
||||
msgid "Already exists"
|
||||
msgstr "Esiste già"
|
||||
|
||||
msgid "Enable unlimited copy buffer"
|
||||
msgstr "Abilita buffer di copia illimitato"
|
||||
|
||||
msgid "Enables unlimited copy buffer for the bouquets tab."
|
||||
msgstr "Abilita buffer di copia illimitato per la scheda bouquet."
|
||||
|
||||
msgid "Start time"
|
||||
msgstr "Ora di inizio"
|
||||
|
||||
msgid "End time"
|
||||
msgstr "Ora di fine"
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (C) 2018-2020 Frank Neirynck
|
||||
# This file is distributed under the MIT license.
|
||||
#
|
||||
# Frank Neirynck <frank@insink.be>, 2018-2020.
|
||||
# Frank Neirynck <frank@insink.be>, 2018-2022.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -25,7 +25,7 @@ msgid "Type"
|
||||
msgstr "Type"
|
||||
|
||||
msgid "Picon"
|
||||
msgstr "Picon"
|
||||
msgstr "Pict."
|
||||
|
||||
msgid "Freq"
|
||||
msgstr "Freq."
|
||||
@@ -148,10 +148,10 @@ msgid "Parent lock On/Off Ctrl + L"
|
||||
msgstr "Ouderlijk slot aan/uit Ctrl + L"
|
||||
|
||||
msgid "Picons"
|
||||
msgstr "Picons"
|
||||
msgstr "Pictogrammen"
|
||||
|
||||
msgid "Picons downloader"
|
||||
msgstr "Picons downloader"
|
||||
msgstr "Pictogrammen downloader"
|
||||
|
||||
msgid "Satellites downloader"
|
||||
msgstr "Satellieten downloader"
|
||||
@@ -286,22 +286,22 @@ msgid "Providers"
|
||||
msgstr "Leveranciers"
|
||||
|
||||
msgid "Receive picons"
|
||||
msgstr "Ontvang picons"
|
||||
msgstr "Ontvang pictogrammen"
|
||||
|
||||
msgid "Picons name format:"
|
||||
msgstr "Picons naam formaat:"
|
||||
msgstr "Pictogrammen naam formaat:"
|
||||
|
||||
msgid "Resize:"
|
||||
msgstr "Verklein/vergroot:"
|
||||
|
||||
msgid "Current picons path:"
|
||||
msgstr "Huidig pad picons:"
|
||||
msgstr "Huidig pad Pictogrammen:"
|
||||
|
||||
msgid "Receiver picons path:"
|
||||
msgstr "Ontvanger picons pad:"
|
||||
msgstr "Ontvanger Pictogrammen pad:"
|
||||
|
||||
msgid "Picons download tool"
|
||||
msgstr "Picons download gereedschap"
|
||||
msgstr "Pictogrammen download gereedschap"
|
||||
|
||||
msgid "Transfer to receiver"
|
||||
msgstr "Transfereren naar ontvanger"
|
||||
@@ -319,7 +319,7 @@ msgid "Path to save:"
|
||||
msgstr "Pad om op te slaan:"
|
||||
|
||||
msgid "Path to Enigma2 picons:"
|
||||
msgstr "Pad naar Enigma2 picons:"
|
||||
msgstr "Pad naar Enigma2 Pictogrammen:"
|
||||
|
||||
msgid "Specify the correct position value for the provider!"
|
||||
msgstr "Geeft de juiste positie waarde voor de provider!"
|
||||
@@ -328,16 +328,16 @@ msgid "Converter between name formats"
|
||||
msgstr "Omvormer tussen naam formaten"
|
||||
|
||||
msgid "Receive picons for providers"
|
||||
msgstr "Ontvang picons voor leveranciers"
|
||||
msgstr "Ontvang Pictogrammen voor providers"
|
||||
|
||||
msgid "Load satellite providers."
|
||||
msgstr "Laad satelliet leveranciers."
|
||||
msgstr "Laad satelliet providers."
|
||||
|
||||
msgid ""
|
||||
"To automatically set the identifiers for picons,\n"
|
||||
"first load the required services list into the main application window."
|
||||
msgstr ""
|
||||
"Om automatisch de ID in te stellen voor picons,\n"
|
||||
"Om automatisch de ID in te stellen voor pictogrammen,\n"
|
||||
"laad eerst de vereiste serviceslijst in via het hoofdvenster van het programma."
|
||||
|
||||
# Satellites editor
|
||||
@@ -462,7 +462,7 @@ msgid "Password:"
|
||||
msgstr "Paswoord:"
|
||||
|
||||
msgid "Picons:"
|
||||
msgstr "Picons:"
|
||||
msgstr "Pictogrammen:"
|
||||
|
||||
msgid "Port:"
|
||||
msgstr "Poort:"
|
||||
@@ -471,7 +471,7 @@ msgid "Data path:"
|
||||
msgstr "Gegevenspad:"
|
||||
|
||||
msgid "Picons path:"
|
||||
msgstr "Picons pad:"
|
||||
msgstr "Pictogrammen pad:"
|
||||
|
||||
msgid "Network settings:"
|
||||
msgstr "Netwerk instellingen:"
|
||||
@@ -825,7 +825,7 @@ msgid "File"
|
||||
msgstr "File"
|
||||
|
||||
msgid "Picons manager"
|
||||
msgstr "Picons manager"
|
||||
msgstr "Pictogrammen manager"
|
||||
|
||||
msgid "Explorer"
|
||||
msgstr "Explorer"
|
||||
@@ -1013,3 +1013,391 @@ msgstr "Schermafbeelding"
|
||||
msgid "Video"
|
||||
msgstr "Vidео"
|
||||
|
||||
msgid "The Neutrino has only experimental support. Not all features are supported!"
|
||||
msgstr "Neutrino heeft alleen experimentele ondersteuning. Niet alle functies worden ondersteund!"
|
||||
|
||||
msgid "Enable experimental features"
|
||||
msgstr "Schakel experimentele functies in"
|
||||
|
||||
msgid "Can't Playback!"
|
||||
msgstr "Kan niet afspelen!"
|
||||
|
||||
msgid "Enable Dark Mode"
|
||||
msgstr "Schakel de donkere modus in"
|
||||
|
||||
msgid "Extract..."
|
||||
msgstr "Extract..."
|
||||
|
||||
msgid "Unsupported format!"
|
||||
msgstr "Niet ondersteund formaat!"
|
||||
|
||||
msgid "Combine with the current data?"
|
||||
msgstr "Combineren met de huidige gegevens?"
|
||||
|
||||
msgid "Importing data done!"
|
||||
msgstr "Gegevens importeren klaar!"
|
||||
|
||||
msgid "Current service"
|
||||
msgstr "Huidige dienst"
|
||||
|
||||
msgid "Open folder"
|
||||
msgstr "Open Map"
|
||||
|
||||
msgid "Open archive"
|
||||
msgstr "Open Archief"
|
||||
|
||||
msgid "Import from Web"
|
||||
msgstr "Importeren van internet"
|
||||
|
||||
msgid "Control"
|
||||
msgstr "Controle"
|
||||
|
||||
msgid "Timers"
|
||||
msgstr "Timers"
|
||||
|
||||
msgid "Timer"
|
||||
msgstr "Timer"
|
||||
|
||||
msgid "Add timer"
|
||||
msgstr "Timer toevoegen"
|
||||
|
||||
msgid "Hr."
|
||||
msgstr "U."
|
||||
|
||||
msgid "Min."
|
||||
msgstr "мin."
|
||||
|
||||
msgid "Power"
|
||||
msgstr "Power"
|
||||
|
||||
msgid "Standby"
|
||||
msgstr "Standby"
|
||||
|
||||
msgid "Wake Up"
|
||||
msgstr "Wake Up"
|
||||
|
||||
msgid "Reboot"
|
||||
msgstr "Herstart"
|
||||
|
||||
msgid "Restart GUI"
|
||||
msgstr "Herstart GUI"
|
||||
|
||||
msgid "Shutdown"
|
||||
msgstr "Uitschakelen"
|
||||
|
||||
msgid "Shut down"
|
||||
msgstr "Uitschakelen"
|
||||
|
||||
msgid "Do Nothing"
|
||||
msgstr "Doe niets"
|
||||
|
||||
msgid "Auto"
|
||||
msgstr "Auto"
|
||||
|
||||
msgid "Grab screenshot"
|
||||
msgstr "Maak schermafbeelding"
|
||||
|
||||
msgid "Enabled:"
|
||||
msgstr "Ingeschakeld:"
|
||||
|
||||
msgid "Name:"
|
||||
msgstr "Naam:"
|
||||
|
||||
msgid "Description:"
|
||||
msgstr "Omschrijving:"
|
||||
|
||||
msgid "Service:"
|
||||
msgstr "Dienst:"
|
||||
|
||||
msgid "Service reference:"
|
||||
msgstr "Service referentie:"
|
||||
|
||||
msgid "Event ID:"
|
||||
msgstr "Event ID:"
|
||||
|
||||
msgid "Begins:"
|
||||
msgstr "Begint:"
|
||||
|
||||
msgid "Ends:"
|
||||
msgstr "Stopt:"
|
||||
|
||||
msgid "Repeated:"
|
||||
msgstr "Herhaald:"
|
||||
|
||||
msgid "Action:"
|
||||
msgstr "Actie:"
|
||||
|
||||
msgid "After event:"
|
||||
msgstr "Na Event:"
|
||||
|
||||
msgid "Location:"
|
||||
msgstr "Locatiе:"
|
||||
|
||||
msgid "Mo"
|
||||
msgstr "Ma"
|
||||
|
||||
msgid "Tu"
|
||||
msgstr "Di"
|
||||
|
||||
msgid "We"
|
||||
msgstr "Wo"
|
||||
|
||||
msgid "Th"
|
||||
msgstr "Do"
|
||||
|
||||
msgid "Fr"
|
||||
msgstr "Vr"
|
||||
|
||||
msgid "Sa"
|
||||
msgstr "Za"
|
||||
|
||||
msgid "Su"
|
||||
msgstr "Zo"
|
||||
|
||||
msgid "Set"
|
||||
msgstr "Set"
|
||||
|
||||
msgid "Services update"
|
||||
msgstr "Services-update"
|
||||
|
||||
msgid "Create folder"
|
||||
msgstr "Map aanmaken"
|
||||
|
||||
msgid "FTP client"
|
||||
msgstr "FTP client"
|
||||
|
||||
msgid "The file size is too large!"
|
||||
msgstr "De bestandsgrootte is te groot!"
|
||||
|
||||
msgid "Connect"
|
||||
msgstr "Verbind"
|
||||
|
||||
msgid "Disconnect"
|
||||
msgstr "Verbreek Verbinding"
|
||||
|
||||
msgid "Size"
|
||||
msgstr "Grootte"
|
||||
|
||||
msgid "Date"
|
||||
msgstr "Datum"
|
||||
|
||||
msgid "Toggle display position"
|
||||
msgstr "Weergavepositie wisselen"
|
||||
|
||||
msgid "Alternatives"
|
||||
msgstr "Alternatieven"
|
||||
|
||||
msgid "Add alternatives"
|
||||
msgstr "Alternatieven toevoegen"
|
||||
|
||||
msgid "DreamOS only!"
|
||||
msgstr "Enkel DreamOS!"
|
||||
|
||||
msgid "A similar service is already in this list!"
|
||||
msgstr "Een vergelijkbare service staat al in deze lijst!"
|
||||
|
||||
msgid "Play mode has been changed!\nRestart the program to apply the settings."
|
||||
msgstr "De afspeelmodus is gewijzigd!\nStart het programma opnieuw om de instellingen toe te passen."
|
||||
|
||||
msgid "Set values for TID, NID and Namespace for correct naming of the picons!"
|
||||
msgstr "Stel waarden in voor TID, NID en Namespace voor correcte naamgeving van de pictogrammen!"
|
||||
|
||||
msgid "Streams detected:"
|
||||
msgstr "Streams gedetecteerd:"
|
||||
|
||||
msgid "Download picons"
|
||||
msgstr "Pictogrammen downloaden"
|
||||
|
||||
msgid "Errors:"
|
||||
msgstr "Fouten:"
|
||||
|
||||
msgid "Use to play streams:"
|
||||
msgstr "Gebruik om streams af te spelen:"
|
||||
|
||||
msgid "Font in the lists:"
|
||||
msgstr "Lettertype in de lijsten:"
|
||||
|
||||
msgid "Picons size in the lists:"
|
||||
msgstr "Pictogramgrootte in de lijsten:"
|
||||
|
||||
msgid "Logo size in tooltips:"
|
||||
msgstr "Logogrootte in knopinfo:"
|
||||
|
||||
msgid "Save as"
|
||||
msgstr "Opslaan als"
|
||||
|
||||
msgid "Mark duplicates"
|
||||
msgstr "Markeer duplicaten"
|
||||
|
||||
msgid "Load only for selected bouquet"
|
||||
msgstr "Laad alleen voor geselecteerd boeket"
|
||||
|
||||
msgid "The task is canceled!"
|
||||
msgstr "De taak is geannuleerd!"
|
||||
|
||||
msgid "Data loading in progress!"
|
||||
msgstr "Gegevens worden geladen!"
|
||||
|
||||
msgid "Recordings"
|
||||
msgstr "Opnames"
|
||||
|
||||
msgid "Recordings:"
|
||||
msgstr "Opnames:"
|
||||
|
||||
msgid "Help"
|
||||
msgstr "Help"
|
||||
|
||||
msgid "HTTP API is not activated. Check your settings!"
|
||||
msgstr "HTTP-API is niet geactiveerd. Controleer uw instellingen!"
|
||||
|
||||
msgid "Add picons"
|
||||
msgstr "Pictogrammen toevoegen"
|
||||
|
||||
msgid "Logs"
|
||||
msgstr "Logs"
|
||||
|
||||
msgid "Title"
|
||||
msgstr "Titel"
|
||||
|
||||
msgid "Time"
|
||||
msgstr "Tijd"
|
||||
|
||||
msgid "Length"
|
||||
msgstr "Lengte"
|
||||
|
||||
msgid "Additional source"
|
||||
msgstr "Extra bron"
|
||||
|
||||
msgid "Automatically set the name selected in the favorites list."
|
||||
msgstr "Stel automatisch de geselecteerde naam in de favorietenlijst in."
|
||||
|
||||
msgid "Playback"
|
||||
msgstr "Weergave"
|
||||
|
||||
msgid "Playback:"
|
||||
msgstr "Weergave:"
|
||||
|
||||
msgid "Audio"
|
||||
msgstr "Audio"
|
||||
|
||||
msgid "Audio Track"
|
||||
msgstr "Audio Spoor"
|
||||
|
||||
msgid "Subtitle"
|
||||
msgstr "Ondertitel"
|
||||
|
||||
msgid "Subtitle Track"
|
||||
msgstr "Ondertitel Spoor"
|
||||
|
||||
msgid "Aspect ratio"
|
||||
msgstr "Beeldverhouding"
|
||||
|
||||
msgid "This may change the settings of other profiles!"
|
||||
msgstr "Hierdoor kunnen de instellingen van andere profielen veranderen!"
|
||||
|
||||
msgid "Drag the services to the desired picon or picon to the list of selected services."
|
||||
msgstr "Sleep de services naar het gewenste pictogram of het pictogram naar de lijst met geselecteerde services."
|
||||
|
||||
msgid "Sets the profile folder as default to store picons, backups, etc."
|
||||
msgstr "Stelt de profielmap in als standaard om pictogrammen, back-ups, etc. op te slaan."
|
||||
|
||||
msgid "New sub-bouquet"
|
||||
msgstr "Nieuw sub-boeket"
|
||||
|
||||
msgid "Mark not presented in Bouquets"
|
||||
msgstr "Stel in als niet in Boeketten"
|
||||
|
||||
msgid "Not in Bouquets"
|
||||
msgstr "Niet in Boeketten"
|
||||
|
||||
msgid "Do not show services present in Bouquets."
|
||||
msgstr "Laat geen services zien die aanwezig zijn in Boeketten."
|
||||
|
||||
msgid "IPTV services only"
|
||||
msgstr "Enkel IPTV diensten"
|
||||
|
||||
msgid "Display picons"
|
||||
msgstr "Toon pictogrammen"
|
||||
|
||||
msgid "Alternate layout"
|
||||
msgstr "Alternatieve indeling"
|
||||
|
||||
msgid "Layout of elements has been changed!"
|
||||
msgstr "Lay-out van elementen is gewijzigd!"
|
||||
|
||||
msgid "Restart the program to apply all changes."
|
||||
msgstr "Start het programma opnieuw om alle wijzigingen toe te passen."
|
||||
|
||||
msgid "New folder"
|
||||
msgstr "Nieuwe map"
|
||||
|
||||
msgid "Rename"
|
||||
msgstr "Hernoem"
|
||||
|
||||
msgid "Bookmarks"
|
||||
msgstr "Bladwijzers"
|
||||
|
||||
msgid "Add bookmark"
|
||||
msgstr "Bladwijzer toevoegen"
|
||||
|
||||
msgid "All bouquets"
|
||||
msgstr "Alle boeketten"
|
||||
|
||||
msgid "Playback from the main list"
|
||||
msgstr "Afspelen vanuit de hoofdlijst"
|
||||
|
||||
msgid "Enables URL parsing using youtube-dl to get direct links to media."
|
||||
msgstr "Schakelt URL-parsing met behulp van youtube-dl in, om directe links naar media te krijgen."
|
||||
|
||||
msgid "Permissions..."
|
||||
msgstr "Rechten..."
|
||||
|
||||
msgid "Display EPG in bouquet list"
|
||||
msgstr "Toon EPG in boeketlijst"
|
||||
|
||||
msgid "EPG *.dat file:"
|
||||
msgstr "EPG *.dat file:"
|
||||
|
||||
msgid "Use HTTP to reload data in the receiver"
|
||||
msgstr "Gebruik HTTP om gegevens opnieuw in de ontvanger te laden"
|
||||
|
||||
msgid "Enable picons compression"
|
||||
msgstr "Pictogrammen-compressie inschakelen"
|
||||
|
||||
msgid "Update interval (sec):"
|
||||
msgstr "Update-interval (sec):"
|
||||
|
||||
msgid "Update:"
|
||||
msgstr "Update:"
|
||||
|
||||
msgid "Daily"
|
||||
msgstr "Dagelijks"
|
||||
|
||||
msgid "Assign reference"
|
||||
msgstr "Referentie toewijzen"
|
||||
|
||||
msgid "Specify hostname or IP address"
|
||||
msgstr "Geef de hostnaam of het IP-adres op"
|
||||
|
||||
msgid "Default selection"
|
||||
msgstr "Standaard selectie"
|
||||
|
||||
msgid "Don't change power state"
|
||||
msgstr "Schakel het toestel niet uit"
|
||||
|
||||
msgid "Don't toggle standby mode when updating bouquets and services."
|
||||
msgstr "Schakel de stand-bymodus niet in bij het updaten van boeketten en services."
|
||||
|
||||
msgid "Region"
|
||||
msgstr "Regio"
|
||||
|
||||
msgid "Provider"
|
||||
msgstr "Provider"
|
||||
|
||||
msgid "Enables upload as an archive if a large number of picon (> 1000) is selected.\n"
|
||||
" Recommended only if you have external storage."
|
||||
msgstr "Maakt uploaden als archief mogelijk als een groot aantal pictogrammen (> 1000) is geselecteerd.\n"
|
||||
" Alleen aanbevolen als u externe opslag heeft."
|
||||
|
||||
msgid "Clear \"New\" flag"
|
||||
msgstr "Opruimen \"Niew\" flag"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (C) 2018-2022 Dmitriy Yefremov
|
||||
# Copyright (C) 2018-2023 Dmitriy Yefremov
|
||||
# This file is distributed under the MIT license.
|
||||
#
|
||||
#
|
||||
@@ -1384,3 +1384,50 @@ msgstr "Ежедневно"
|
||||
|
||||
msgid "Assign reference"
|
||||
msgstr "Присвоить ссылку"
|
||||
|
||||
msgid "Specify hostname or IP address"
|
||||
msgstr "Укажите имя хоста или IP-адрес"
|
||||
|
||||
msgid "Default selection"
|
||||
msgstr "Выбор по умолчанию"
|
||||
|
||||
msgid "Don't change power state"
|
||||
msgstr "Не изменять состояние питания"
|
||||
|
||||
msgid "Don't toggle standby mode when updating bouquets and services."
|
||||
msgstr "Не переключать в режим ожидания при обновлении букетов и сервисов."
|
||||
|
||||
msgid "Region"
|
||||
msgstr "Регион"
|
||||
|
||||
msgid "Provider"
|
||||
msgstr "Провайдер"
|
||||
|
||||
msgid "Enables upload as an archive if a large number of picon (> 1000) is selected.\n"
|
||||
" Recommended only if you have external storage."
|
||||
msgstr "Включает загрузку в виде архива, если выбрано большое количество пиконов (> 1000).\n"
|
||||
" Рекомендуется, только если у вас есть внешнее хранилище."
|
||||
|
||||
msgid "Clear \"New\" flag"
|
||||
msgstr "Очистить флаг \"New\""
|
||||
|
||||
msgid "Group by"
|
||||
msgstr "Группировать по"
|
||||
|
||||
msgid "Replace existing"
|
||||
msgstr "Заменить существующие"
|
||||
|
||||
msgid "Already exists"
|
||||
msgstr "Уже существует"
|
||||
|
||||
msgid "Enable unlimited copy buffer"
|
||||
msgstr "Включить неограниченный буфер копирования"
|
||||
|
||||
msgid "Enables unlimited copy buffer for the bouquets tab."
|
||||
msgstr "Включает неограниченный буфер копирования для вкладки букетов."
|
||||
|
||||
msgid "Start time"
|
||||
msgstr "Начало"
|
||||
|
||||
msgid "End time"
|
||||
msgstr "Окончание"
|
||||
|
||||
@@ -3,7 +3,7 @@ msgstr ""
|
||||
"Project-Id-Version: DemonEditor\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2020-04-16 15:59+0300\n"
|
||||
"PO-Revision-Date: 2022-08-27 23:17+0300\n"
|
||||
"PO-Revision-Date: 2023-01-13 21:54+0300\n"
|
||||
"Last-Translator: audi06_19 <info@dreamosat-forum.com>\n"
|
||||
"Language-Team: \n"
|
||||
"Language: tr\n"
|
||||
@@ -1416,3 +1416,34 @@ msgstr "Günlük"
|
||||
|
||||
msgid "Assign reference"
|
||||
msgstr "Referans ata"
|
||||
|
||||
msgid "Specify hostname or IP address"
|
||||
msgstr "Ana bilgisayar adını veya IP adresini belirtin"
|
||||
|
||||
msgid "Default selection"
|
||||
msgstr "Varsayılan seçim"
|
||||
|
||||
msgid "Don't change power state"
|
||||
msgstr "Güç durumunu değiştirme"
|
||||
|
||||
msgid "Don't toggle standby mode when updating bouquets and services."
|
||||
msgstr "Buketleri ve servisleri güncellerken bekleme moduna geçmeyin."
|
||||
|
||||
msgid "Region"
|
||||
msgstr "Bölge"
|
||||
|
||||
msgid "Provider"
|
||||
msgstr "Sağlayıcı"
|
||||
|
||||
msgid ""
|
||||
"Enables upload as an archive if a large number of picon (> 1000) is selected.\n"
|
||||
" Recommended only if you have external storage."
|
||||
msgstr ""
|
||||
"Çok sayıda picon (> 1000) seçilirse arşiv olarak yüklemeyi etkinleştirir.\n"
|
||||
" Yalnızca harici depolamanız varsa önerilir."
|
||||
|
||||
msgid "Clear \"New\" flag"
|
||||
msgstr "\"Yeni\" bayrağını temizleyin"
|
||||
|
||||
msgid "Group by"
|
||||
msgstr ""
|
||||
|
||||
Reference in New Issue
Block a user