Compare commits

...

35 Commits

Author SHA1 Message Date
DYefremov
2d2a90542c main icons initialization refactoring 2021-11-16 13:21:52 +03:00
DYefremov
535c9c9102 fix themes unpacking on Windows 2021-11-16 12:09:29 +03:00
DYefremov
866e18762d enabled http api setting for Neutrino 2021-11-14 23:37:56 +03:00
DYefremov
aef5027d23 bump version 2021-11-14 17:28:38 +03:00
DYefremov
3a142eca4a README update 2021-11-14 17:16:40 +03:00
DYefremov
606bad7716 fix getting youtube-dl for Windows 2021-11-13 13:13:52 +03:00
DYefremov
fa07f8bf85 fix picon path on profile change 2021-11-12 19:11:19 +03:00
DYefremov
92280162c6 added logging for transponder validation 2021-11-12 16:23:20 +03:00
DYefremov
5d285e88d8 copied tr *.mo file 2021-11-12 11:10:56 +03:00
audi06_19
0355714e92 Turkish translation update (#53) 2021-11-12 11:05:37 +03:00
DYefremov
b06e877a0c update of pl *.mo file 2021-11-11 22:37:58 +03:00
Wieslaw Weglowski
9b479b051d Polish translation update (#52) 2021-11-11 22:28:23 +03:00
DYefremov
b953ee8762 minor fix of playback window title 2021-11-08 11:06:31 +03:00
DYefremov
0e7d6bec69 fixed some configs loading with dvb-t 2021-11-07 23:34:47 +03:00
DYefremov
cb9824d404 changed audio menu icon 2021-11-07 21:47:11 +03:00
DYefremov
c87adb256f fix sid config for IPTV lists 2021-11-07 21:20:06 +03:00
DYefremov
899d05a186 added "Return" key support for FTP client 2021-11-07 00:10:15 +03:00
DYefremov
bd4f86e91e Russian, Belarusian and German translations update 2021-11-06 15:45:58 +03:00
DYefremov
42fb365b45 fix picon assignment by drag for mac 2021-11-06 14:42:13 +03:00
DYefremov
67d6ea861e minor playback fixes 2021-11-06 12:11:05 +03:00
DYefremov
d887a61636 fix settings saving for Ubuntu [18.04] 2021-11-05 23:01:07 +03:00
DYefremov
9d9efb7577 Russian, Belarusian and German translations update 2021-11-03 18:14:41 +03:00
DYefremov
b6d331a311 redesigned info output for download dialog 2021-11-03 18:09:46 +03:00
DYefremov
1060e169a1 minor refactoring 2021-11-03 12:30:23 +03:00
DYefremov
562c1a5955 modifiers correction 2021-11-01 11:09:45 +03:00
DYefremov
3c4dec323f minor mac style correction 2021-11-01 00:44:12 +03:00
DYefremov
3bafe08030 adapting dialogs for Gnome 2021-10-31 20:26:19 +03:00
DYefremov
722f8df813 header bar for Gnome in epg dialog 2021-10-31 16:09:07 +03:00
DYefremov
8f6984dbaf added src and pos display for epg (#51) 2021-10-31 13:34:48 +03:00
DYefremov
bf6e9617ec header bar changes in the backup dialog 2021-10-30 18:25:20 +03:00
DYefremov
ec27c32d35 bump version 2021-10-29 17:26:34 +03:00
DYefremov
bfa3b1aa66 added dialog call before reset of settings 2021-10-29 17:21:30 +03:00
DYefremov
a1e32abd07 minor settings dialog changes for Gnome 2021-10-29 15:57:28 +03:00
DYefremov
f93370293b Russian, Belarusian and German translations update 2021-10-29 11:31:59 +03:00
DYefremov
79a2a034eb fix app menu translation for Windows 2021-10-29 10:45:13 +03:00
49 changed files with 2300 additions and 1648 deletions

View File

@@ -5,6 +5,7 @@ Comment=Channel and satellite list editor for Enigma2
Comment[ru]=Редактор списка каналов и спутников для Enigma2
Comment[be]=Рэдактар спіса каналаў і спадарожнікаў для Enigma2
Comment[de]=Programm- und Satellitenlisten-Editor für Enigma2
Comment[tr]=Enigma2 için kanal ve uydu listesi editörü
Icon=demon-editor
Exec=bash -c 'cd $(dirname %k) && ./start.py'
Terminal=false

View File

@@ -1,33 +1,32 @@
# <img src="app/ui/icons/hicolor/96x96/apps/demon-editor.png" width="32" /> DemonEditor
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) ![platform](https://img.shields.io/badge/platform-linux%20|%20macos-lightgrey)
### Enigma2 channel and satellite list editor for GNU/Linux.
[<img src="https://user-images.githubusercontent.com/7511379/118884719-8277e980-b8ff-11eb-8621-c8c4afd6181b.png" width="560"/>](https://user-images.githubusercontent.com/7511379/118884719-8277e980-b8ff-11eb-8621-c8c4afd6181b.png)
Experimental support of Neutrino-MP or others on the same basis (BPanther, etc).
Focused on the convenience of working in lists from the keyboard. The mouse is also fully supported (Drag and Drop etc).
### Enigma2 channel and satellite list editor for GNU/Linux.
Experimental support of Neutrino-MP or others on the same basis (BPanther, etc).
## Main features of the program
* Editing bouquets, channels, satellites.
[<img src="https://user-images.githubusercontent.com/7511379/118884747-8ad02480-b8ff-11eb-9104-8cf8fb6e785d.png" width="480"/>](https://user-images.githubusercontent.com/7511379/118884747-8ad02480-b8ff-11eb-9104-8cf8fb6e785d.png)
[<img src="https://user-images.githubusercontent.com/7511379/141680963-9b8eb6cc-c712-46b2-aefe-19769e21a7d5.png" width="480"/>](https://user-images.githubusercontent.com/7511379/141680963-9b8eb6cc-c712-46b2-aefe-19769e21a7d5.png)
* Import function.
[<img src="https://user-images.githubusercontent.com/7511379/118526825-4dc23180-b749-11eb-8197-e9bbccbc3bdf.png" width="480"/>](https://user-images.githubusercontent.com/7511379/118526825-4dc23180-b749-11eb-8197-e9bbccbc3bdf.png)
[<img src="https://user-images.githubusercontent.com/7511379/141681059-68bc1b55-6fab-436c-aa73-ef24e2e5113b.png" width="480"/>](https://user-images.githubusercontent.com/7511379/141681059-68bc1b55-6fab-436c-aa73-ef24e2e5113b.png)
* Backup function.
[<img src="https://user-images.githubusercontent.com/7511379/118528402-f58c2f00-b74a-11eb-9b84-edf220526e6e.png" width="480"/>](https://user-images.githubusercontent.com/7511379/118528402-f58c2f00-b74a-11eb-9b84-edf220526e6e.png)
[<img src="https://user-images.githubusercontent.com/7511379/141681104-ed9b5d35-25de-426f-b9bb-2a6e4db022bb.png" width="480"/>](https://user-images.githubusercontent.com/7511379/141681104-ed9b5d35-25de-426f-b9bb-2a6e4db022bb.png)
* Support of picons.
[<img src="https://user-images.githubusercontent.com/7511379/118526864-5c104d80-b749-11eb-8497-6e8c78542ab1.png" width="480"/>](https://user-images.githubusercontent.com/7511379/118526864-5c104d80-b749-11eb-8497-6e8c78542ab1.png)
[<img src="https://user-images.githubusercontent.com/7511379/141681115-957c63a3-4113-422d-bb27-2d96b1463cd1.png" width="480"/>](https://user-images.githubusercontent.com/7511379/141681115-957c63a3-4113-422d-bb27-2d96b1463cd1.png)
* Importing services, downloading picons and updating satellites from the Web.
[<img src="https://user-images.githubusercontent.com/7511379/118530243-1a81a180-b74d-11eb-8e01-aea904d954af.png" width="250"/>](https://user-images.githubusercontent.com/7511379/118530243-1a81a180-b74d-11eb-8e01-aea904d954af.png)
[<img src="https://user-images.githubusercontent.com/7511379/118526706-31be9000-b749-11eb-9956-c4bf2e13f968.png" width="292"/>](https://user-images.githubusercontent.com/7511379/118526706-31be9000-b749-11eb-9956-c4bf2e13f968.png)
[<img src="https://user-images.githubusercontent.com/7511379/141681075-28f18ea5-e456-4e84-bf64-1b7d9a95324d.png" width="262"/>](https://user-images.githubusercontent.com/7511379/141681075-28f18ea5-e456-4e84-bf64-1b7d9a95324d.png)
[<img src="https://user-images.githubusercontent.com/7511379/141681040-b1ad190a-6bc2-4741-bb42-1fb219a0fcab.png" width="250"/>](https://user-images.githubusercontent.com/7511379/141681040-b1ad190a-6bc2-4741-bb42-1fb219a0fcab.png)
* Extended support of IPTV.
* Import to bouquet(Neutrino WEBTV) from m3u.
* Export of bouquets with IPTV services in m3u.
* Assignment of EPG from DVB or XML for IPTV services (only Enigma2, experimental).
* Preview (playback) of IPTV or other streams directly from the bouquet list.
[<img src="https://user-images.githubusercontent.com/7511379/118884891-b3f0b500-b8ff-11eb-8717-3588d6e089de.png" width="480"/>](https://user-images.githubusercontent.com/7511379/118884891-b3f0b500-b8ff-11eb-8717-3588d6e089de.png)
* Control panel with the ability to view EPG and manage timers (via HTTP API, experimental).
[<img src="https://user-images.githubusercontent.com/7511379/118886284-66754780-b901-11eb-9068-29b5a607ccaf.png" width="480"/>](https://user-images.githubusercontent.com/7511379/118886284-66754780-b901-11eb-9068-29b5a607ccaf.png)
* Assignment of EPG from DVB or XML for IPTV services (Enigma2 only).
[<img src="https://user-images.githubusercontent.com/7511379/141681187-fae4e784-c9e0-43df-b499-4d38e83d6560.png" width="480"/>](https://user-images.githubusercontent.com/7511379/141681187-fae4e784-c9e0-43df-b499-4d38e83d6560.png)
* Playback of IPTV or other streams directly from the bouquet list.
[<img src="https://user-images.githubusercontent.com/7511379/141681129-98f78cdc-9a98-46ef-b738-618a327634d4.png" width="480"/>](https://user-images.githubusercontent.com/7511379/141681129-98f78cdc-9a98-46ef-b738-618a327634d4.png)
* Control panel (via HTTP API).
[<img src="https://user-images.githubusercontent.com/7511379/141684475-4511ea4f-b152-42d5-b9c8-f3e1e9a160d0.png" width="480"/>](https://user-images.githubusercontent.com/7511379/141684475-4511ea4f-b152-42d5-b9c8-f3e1e9a160d0.png)
* Ability to view EPG and manage timers (via HTTP API).
* Simple FTP client (experimental).
[<img src="https://user-images.githubusercontent.com/7511379/118527372-e8bb0b80-b749-11eb-9653-4ad64c99a05a.png" width="480"/>](https://user-images.githubusercontent.com/7511379/118527372-e8bb0b80-b749-11eb-9653-4ad64c99a05a.png)
[<img src="https://user-images.githubusercontent.com/7511379/141681165-5679c331-72e7-4044-b365-dcdb30b1433c.png" width="480"/>](https://user-images.githubusercontent.com/7511379/141681165-5679c331-72e7-4044-b365-dcdb30b1433c.png)
#### Keyboard shortcuts
* **Ctrl + X** - only in bouquet list.
@@ -51,8 +50,10 @@ Clipboard is **"rubber"**. There is an accumulation before the insertion!
* **Ctrl + D** - load data from receiver.
* **Ctrl + U/B** - upload data/bouquets to receiver.
* **Ctrl + I** - extra info, details.
* **Ctrl + F** - show/hide search bar.
* **Ctrl + F** - show search bar.
* **Ctrl + Shift + F** - show/hide filter bar.
* **Ctrl + T** - show/hide built-in Telnet client.
* **Ctrl + Shift + L** - show/hide logging panel.
For **multiple** selection with the mouse, press and hold the **Ctrl** key!
@@ -71,13 +72,32 @@ To create a simple **debian package**, you can use the *build-deb.sh.* You can a
Users of **LTS** versions of [Ubuntu](https://ubuntu.com/) or distributions based on them can use [PPA](https://launchpad.net/~dmitriy-yefremov/+archive/ubuntu/demon-editor) repository.
A ready-made [package](https://aur.archlinux.org/packages/demoneditor-bin) is also available for [Arch Linux](https://archlinux.org/) users in the [AUR](https://aur.archlinux.org/) repository.
* ### macOS
**This program can be run on macOS.** To work in this OS, you must use a [separate branch](https://github.com/DYefremov/DemonEditor/tree/experimental-mac). A ready-made package can be downloaded from the [releases](https://github.com/DYefremov/DemonEditor/releases) page.
**The functionality and performance of this version may be different from the Linux version!**
**This program can be run on macOS.**
To run the program on macOS, you need to install [brew](https://brew.sh/).
Then install the required components via terminal:
```brew install python3 gtk+3 pygobject3 adwaita-icon-theme```
```pip3 install requests, pillow```
Launch is similar to Linux.
You can also download the ready-made package as a ***.dmg** file from the [releases](https://github.com/DYefremov/DemonEditor/releases) page.
Recommended copy the package to the **Application** directory.
Perhaps in the security settings it will be necessary to allow the launch of this application!
* ### MS Windows
**Windows users can also run this program.** One way is to use the [MSYS2](https://www.msys2.org/) platform.
In addition, you can download a ready-made build (**64-bit**) from the [releases](https://github.com/DYefremov/DemonEditor/releases) page.
**All builds may contain components distributed under the GPL [v3](http://www.gnu.org/licenses/gpl-3.0.html) or lower license.
By downloading and using this packages you agree to the terms of this [license](http://www.gnu.org/licenses/gpl-3.0.html) and the possible inconvenience associated with this!**
THIS SOFTWARE COMES WITH ABSOLUTELY NO WARRANTY.
AUTHOR IS NOT LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY CONNECTION WITH THIS SOFTWARE.
## Important
The program is tested only with [openATV](https://www.opena.tv/) image and **Formuler F1** receiver in [Linux Mint](https://linuxmint.com/) (MATE 64-bit) distribution!
The program is tested only with [openATV](https://www.opena.tv/) image and **Formuler F1** receiver in [Linux Mint](https://linuxmint.com/) (MATE 64-bit) distribution!
Support for DVB-T/T2 and DVB-C channels for Neutrino is not fully implemented and has an experimental status.
Terrestrial(DVB-T/T2) and cable(DVB-C) channels are only supported for Enigma2.
Main supported *lamedb* format is version **4**. Versions **3** and **5** has only **experimental** support! For version **3** is only read mode available. When saving, version **4** format is used instead.
When using the multiple import feature, from *lamedb* will be taken data **only for channels that are in the selected bouquets!**
@@ -85,6 +105,8 @@ If you need full set of the data, including *[satellites, terrestrial, cables].x
just load your data via *"File/Open"* and press *"Save"*. When importing separate bouquet files, only those services
(excluding IPTV) that are in the **current open lamedb** (main list of services) will be imported.
**The built-in Telnet client does not support ANSI escape sequences!**
For streams playback, this app supports [VLC](https://www.videolan.org/vlc/), [MPV](https://mpv.io/) and [GStreamer](https://gstreamer.freedesktop.org/). Depending on your distro, you may need to install additional packages and libraries.
#### Command line arguments:
* **-l** - write logs to file.

View File

@@ -1,7 +1,37 @@
""" Common elements module """
# -*- coding: utf-8 -*-
#
# The MIT License (MIT)
#
# Copyright (c) 2018-2021 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
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# Author: Dmitriy Yefremov
#
""" Common elements module. """
from collections import namedtuple
from enum import Enum
from app.commons import log
Service = namedtuple("Service", ["flags_cas", "transponder_type", "coded", "service", "locked", "hide", "package",
"service_type", "picon", "picon_id", "ssid", "freq", "rate", "pol", "fec",
"system", "pos", "data_id", "fav_id", "transponder"])
@@ -206,14 +236,15 @@ def get_value_by_name(en, name):
def is_transponder_valid(tr: Transponder):
""" Checks transponder validity """
""" Checks transponder validity. """
try:
int(tr.frequency)
int(tr.symbol_rate)
tr.pls_mode is None or int(tr.pls_mode)
tr.pls_code is None or int(tr.pls_code)
tr.is_id is None or int(tr.is_id)
except TypeError:
except (TypeError, ValueError) as e:
log(f"Transponder validation error: {e}\n{tr}")
return False
if tr.polarization not in POLARIZATION.values():

View File

@@ -151,18 +151,18 @@ class LameDbReader:
is_v3 = False
if len(tid) < 4:
is_v3 = True
tid = "{:0>4}".format(tid)
tid = f"{tid:0>4}"
data[2] = tid
if len(nid) < 4:
is_v3 = True
nid = "{:0>4}".format(nid)
nid = f"{nid:0>4}"
data[3] = nid
if is_v3:
data[0] = "{:0>4}".format(data[0])
data[0] = f"{data[0]:0>4}"
data_id = _SEP.join(data)
srv_type = int(data[4])
transponder_id = "{}:{}:{}".format(data[1], tid, nid)
transponder_id = f"{data[1]}:{tid}:{nid}"
transponder = transponders.get(transponder_id, None)
tid = tid.lstrip(sp).upper()
@@ -170,9 +170,9 @@ class LameDbReader:
ssid = str(data[0]).lstrip(sp).upper()
onid = str(data[1]).lstrip(sp).upper()
# For comparison in bouquets. Needed in upper case!!!
fav_id = "{}:{}:{}:{}".format(ssid, tid, nid, onid)
picon_id = "1_0_{:X}_{}_{}_{}_{}_0_0_0.png".format(srv_type, ssid, tid, nid, onid)
s_id = "1:0:{:X}:{}:{}:{}:{}:0:0:0:".format(srv_type, ssid, tid, nid, onid)
fav_id = f"{ssid}:{tid}:{nid}:{onid}"
picon_id = f"1_0_{srv_type:X}_{ssid}_{tid}_{nid}_{onid}_0_0_0.png"
s_id = f"1:0:{srv_type:X}:{ssid}:{tid}:{nid}:{onid}:0:0:0:"
all_flags = srv[2].split(",")
coded = CODED_ICON if list(filter(lambda x: x.startswith("C:"), all_flags)) else None
@@ -203,7 +203,7 @@ class LameDbReader:
system = "DVB-S2" if len(tr) > 7 else "DVB-S"
pos = tr[4]
if tr_type is TrType.Terrestrial:
system = T_SYSTEM.get(tr[10], None)
system = T_SYSTEM.get(tr[10] if len(tr) > 10 else "0", None)
pos = "T"
fec = T_FEC.get(tr[3], None)
elif tr_type is TrType.Cable:
@@ -217,13 +217,13 @@ class LameDbReader:
# Formatting displayed values.
try:
freq = "{}".format(int(freq) // 1000)
rate = "{}".format(int(rate) // 1000)
freq = f"{int(freq) // 1000}"
rate = f"{int(rate) // 1000}"
if tr_type is TrType.Satellite:
pos = int(pos)
pos = "{:0.1f}{}".format(abs(pos / 10), "W" if pos < 0 else "E")
pos = f"{abs(pos / 10):0.1f}{'W' if pos < 0 else 'E'}"
except ValueError as e:
log("Parse error [parse_services]: {}".format(e))
log(f"Parse error [parse_services]: {e}")
s = Service(srv[2], tr_type.value, coded, srv_name, locked, hide, package, service_type, None,
picon_id, data[0], freq, rate, pol, fec, system, pos, data_id, fav_id, transponder)

View File

@@ -46,7 +46,7 @@ from app.ui.uicommons import show_notification
_YT_PATTERN = re.compile(r"https://www.youtube.com/.+(?:v=)([\w-]{11}).*")
_YT_LIST_PATTERN = re.compile(r"https://www.youtube.com/.+?(?:list=)([\w-]{18,})?.*")
_YT_VIDEO_PATTERN = re.compile(r"https://r\d+---sn-[\w]{10}-[\w]{3,5}.googlevideo.com/videoplayback?.*")
_HEADERS = {"User-Agent": "Mozilla/5.0 (X11; Linux i586; rv:31.0) Gecko/20100101 Firefox/69.0",
_HEADERS = {"User-Agent": "Mozilla/5.0 (Linux x86_64; rv:92.0) Gecko/20100101 Firefox/92.0",
"DNT": "1",
"Accept-Encoding": "gzip, deflate"}
@@ -109,6 +109,8 @@ class YouTube:
if self._settings.enable_yt_dl and url:
if not self._yt_dl:
self._yt_dl = YouTubeDL.get_instance(self._settings, self._callback)
if not self._yt_dl:
raise YouTubeException("youtube-dl initialization error.")
return self._yt_dl.get_yt_link(url, skip_errors)
return self.get_yt_link_by_id(video_id)
@@ -130,7 +132,7 @@ class YouTube:
try:
resp = json.loads(player_resp)
except JSONDecodeError as e:
log("{}: Parsing player response error: {}".format(__class__.__name__, e))
log(f"{__class__.__name__}: Parsing player response error: {e}")
else:
det = resp.get("videoDetails", None)
title = det.get("title", None) if det else None
@@ -162,14 +164,19 @@ class YouTube:
""" Returns tuple from the playlist header and list of tuples (title, video id). """
if self._settings.enable_yt_dl and url:
try:
if not self._yt_dl:
raise YouTubeException("youtube-dl is not initialized!")
self._yt_dl.update_options({"noplaylist": False, "extract_flat": True})
info = self._yt_dl.get_info(url, skip_errors=False)
if "url" in info:
info = self._yt_dl.get_info(info.get("url"), skip_errors=False)
return info.get("title", ""), [(e.get("title", ""), e.get("id", "")) for e in info.get("entries", [])]
finally:
# Restoring default options
self._yt_dl.update_options({"noplaylist": True, "extract_flat": False})
if self._yt_dl:
self._yt_dl.update_options({"noplaylist": True, "extract_flat": False})
return PlayListParser.get_yt_playlist(list_id)
@@ -218,7 +225,7 @@ class PlayListParser(HTMLParser):
self._is_script = False
def error(self, message):
log("{} Parsing error: {}".format(__class__.__name__, message))
log(f"{__class__.__name__} Parsing error: {message}")
@property
def header(self):
@@ -259,7 +266,7 @@ class YouTubeDL:
"cookiefile": "cookies.txt"} # File name where cookies should be read from and dumped to.
def __init__(self, settings, callback):
self._path = "{}tools{}".format(settings.default_data_path, SEP)
self._path = f"{settings.default_data_path}tools{SEP}"
self._update = settings.enable_yt_dl_update
self._supported = {"22", "18"}
self._dl = None
@@ -276,7 +283,7 @@ class YouTubeDL:
return cls._DL_INSTANCE
def init(self):
if not os.path.isfile("{}youtube_dl{}version.py".format(self._path, SEP)):
if not os.path.isfile(f"{self._path}youtube_dl{SEP}version.py"):
self.get_latest_release()
if self._path not in sys.path:
@@ -293,12 +300,17 @@ class YouTubeDL:
except ImportError as e:
log("YouTubeDLHelper error: {}".format(str(e)))
else:
if self._path not in youtube_dl.__file__:
msg = "Another version of youtube-dl was found on your system!"
log(msg)
raise YouTubeException(msg)
if self._update:
if hasattr(youtube_dl.version, "__version__"):
l_ver = self.get_last_release_id()
cur_ver = youtube_dl.version.__version__
if l_ver and youtube_dl.version.__version__ < l_ver:
msg = "youtube-dl has new release!\nCurrent: {}. Last: {}.".format(cur_ver, l_ver)
msg = f"youtube-dl has new release!\nCurrent: {cur_ver}. Last: {l_ver}."
show_notification(msg)
log(msg)
self._callback(msg, False)
@@ -318,7 +330,7 @@ class YouTubeDL:
with urlopen(url, timeout=10) as resp:
return json.loads(resp.read().decode("utf-8")).get("tag_name", "0")
except URLError as e:
log("YouTubeDLHelper error [get last release id]: {}".format(e))
log(f"YouTubeDLHelper error [get last release id]: {e}")
def get_latest_release(self):
try:
@@ -329,6 +341,9 @@ class YouTubeDL:
r = json.loads(resp.read().decode("utf-8"))
zip_url = r.get("zipball_url", None)
if zip_url:
if os.path.isdir(self._path):
shutil.rmtree(self._path)
zip_file = self._path + "yt.zip"
os.makedirs(os.path.dirname(self._path), exist_ok=True)
f_name, headers = urlretrieve(zip_url, filename=zip_file)
@@ -336,25 +351,22 @@ class YouTubeDL:
import zipfile
with zipfile.ZipFile(f_name) as arch:
if os.path.isdir(self._path):
shutil.rmtree(self._path)
else:
os.makedirs(os.path.dirname(self._path), exist_ok=True)
for info in arch.infolist():
pref, sep, f = info.filename.partition("/youtube_dl/")
if sep:
arch.extract(info.filename)
shutil.move(info.filename, "{}{}{}".format(self._path, sep, f))
shutil.move(info.filename, f"{self._path}{sep}{f}")
shutil.rmtree(pref)
msg = "Getting the last youtube-dl release is done!"
show_notification(msg)
log(msg)
self._callback(msg, False)
return True
if os.path.isfile(zip_file):
os.remove(zip_file)
return True
except URLError as e:
log("YouTubeDLHelper error: {}".format(e))
log(f"YouTubeDLHelper error: {e}")
raise YouTubeException(e)
finally:
self._is_update_process = False
@@ -377,10 +389,10 @@ class YouTubeDL:
try:
return self._dl.extract_info(url, download=False)
except URLError as e:
log(str(e))
log(f"YouTubeDLHelper error [get info]: {e}")
raise YouTubeException(e)
except self._DownloadError as e:
log(str(e))
log(f"YouTubeDLHelper error [get info]: {e}")
if not skip_errors:
raise YouTubeException(e)

View File

@@ -38,7 +38,7 @@ from app.commons import run_idle
from app.settings import SettingsType, SEP
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
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, KeyboardKey, MOD_MASK, IS_GNOME_SESSION
class RestoreType(Enum):
@@ -74,6 +74,24 @@ class BackupDialog:
self._info_check_button = builder.get_object("info_check_button")
self._info_bar = builder.get_object("info_bar")
self._message_label = builder.get_object("message_label")
if IS_GNOME_SESSION:
header_bar = Gtk.HeaderBar(visible=True, show_close_button=True)
self._dialog_window.set_titlebar(header_bar)
button_box = builder.get_object("main_button_box")
button_box.set_margin_top(0)
button_box.set_margin_bottom(0)
button_box.set_margin_left(0)
button_box.reparent(header_bar)
ch_button = builder.get_object("info_check_button")
ch_button.set_margin_right(0)
h_bar = builder.get_object("header_bar")
h_bar.remove(ch_button)
h_bar.set_visible(False)
header_bar.pack_end(ch_button)
# Setting the last size of the dialog window if it was saved
window_size = self._settings.get("backup_tool_window_size")
if window_size:

View File

@@ -124,7 +124,6 @@ Author: Dmitriy Yefremov
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">5</property>
<child>
<object class="GtkBox" id="header_bar">
<property name="visible">True</property>
@@ -232,6 +231,7 @@ Author: Dmitriy Yefremov
<object class="GtkPaned" id="main_paned">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="margin_top">5</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_bottom">5</property>

View File

@@ -598,18 +598,6 @@ Author: Dmitriy Yefremov
<property name="margin_bottom">5</property>
<property name="row_spacing">5</property>
<property name="column_spacing">5</property>
<child>
<object class="GtkLabel" id="timer_service_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Service:</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="timer_description_label">
<property name="visible">True</property>
@@ -634,17 +622,6 @@ Author: Dmitriy Yefremov
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="timer_service_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="primary_icon_name">document-edit-symbolic</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">3</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="timer_desc_entry">
<property name="visible">True</property>
@@ -690,6 +667,115 @@ Author: Dmitriy Yefremov
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="timer_service_ref_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Service reference:</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">9</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="timer_service_ref_entry">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="editable">False</property>
<property name="width_chars">25</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">9</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="timer_event_id_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Event ID:</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">10</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="timer_event_id_entry">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="editable">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">10</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="timer_location_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Location:</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">12</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="timer_location_entry">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<property name="placeholder_text" translatable="yes">Default</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">12</property>
</packing>
</child>
<child>
<object class="GtkBox" id="timer_dialog_location_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">end</property>
<property name="margin_top">10</property>
<property name="spacing">5</property>
<child>
<object class="GtkImage" id="timer_location_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">document-edit-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSwitch" id="timer_location_switch">
<property name="visible">True</property>
<property name="can_focus">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">11</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="timer_begins_label">
<property name="visible">True</property>
@@ -699,7 +785,7 @@ Author: Dmitriy Yefremov
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">4</property>
<property name="top_attach">3</property>
</packing>
</child>
<child>
@@ -724,7 +810,7 @@ Author: Dmitriy Yefremov
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">4</property>
<property name="top_attach">3</property>
</packing>
</child>
<child>
@@ -736,7 +822,7 @@ Author: Dmitriy Yefremov
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">5</property>
<property name="top_attach">4</property>
</packing>
</child>
<child>
@@ -761,7 +847,7 @@ Author: Dmitriy Yefremov
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">5</property>
<property name="top_attach">4</property>
</packing>
</child>
<child>
@@ -773,7 +859,7 @@ Author: Dmitriy Yefremov
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">6</property>
<property name="top_attach">5</property>
</packing>
</child>
<child>
@@ -954,7 +1040,7 @@ Author: Dmitriy Yefremov
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">6</property>
<property name="top_attach">5</property>
</packing>
</child>
<child>
@@ -966,7 +1052,7 @@ Author: Dmitriy Yefremov
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">7</property>
<property name="top_attach">6</property>
</packing>
</child>
<child>
@@ -981,7 +1067,7 @@ Author: Dmitriy Yefremov
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">7</property>
<property name="top_attach">6</property>
</packing>
</child>
<child>
@@ -993,7 +1079,7 @@ Author: Dmitriy Yefremov
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">8</property>
<property name="top_attach">7</property>
</packing>
</child>
<child>
@@ -1010,115 +1096,30 @@ Author: Dmitriy Yefremov
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">7</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="timer_service_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Service:</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">8</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="timer_service_ref_label">
<object class="GtkEntry" id="timer_service_entry">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Service reference:</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">9</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="timer_service_ref_entry">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="editable">False</property>
<property name="width_chars">25</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">9</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="timer_event_id_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Event ID:</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">10</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="timer_event_id_entry">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="editable">False</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">10</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="timer_location_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Location:</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">12</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="timer_location_entry">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can_focus">True</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<property name="placeholder_text" translatable="yes">Default</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">12</property>
</packing>
</child>
<child>
<object class="GtkBox" id="timer_dialog_location_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">end</property>
<property name="spacing">5</property>
<child>
<object class="GtkImage" id="timer_location_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">document-edit-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSwitch" id="timer_location_switch">
<property name="visible">True</property>
<property name="can_focus">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">11</property>
<property name="top_attach">8</property>
</packing>
</child>
<child>

View File

@@ -36,7 +36,7 @@ from urllib.parse import quote
from gi.repository import GLib
from .dialogs import get_builder, show_dialog, DialogType, get_message
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, Page, Column, KeyboardKey
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, Page, Column, KeyboardKey, IS_GNOME_SESSION
from ..commons import run_task, run_with_delay, log, run_idle
from ..connections import HttpAPI, UtfFTP
from ..eparser.ecommons import BqServiceType
@@ -159,7 +159,7 @@ class TimerTool(Gtk.Box):
class TimerDialog(Gtk.Dialog):
def __init__(self, parent, action=None, timer_data=None, *args, **kwargs):
super().__init__(*args, **kwargs)
super().__init__(use_header_bar=IS_GNOME_SESSION, *args, **kwargs)
self._action = action or TimerTool.TimerAction.ADD
self._timer_data = timer_data or {}
@@ -213,7 +213,7 @@ class TimerTool(Gtk.Box):
self._timer_desc_entry.drag_dest_unset()
self._timer_service_entry.drag_dest_unset()
self.add_buttons(get_message("Cancel"), Gtk.ResponseType.CLOSE, get_message("Save"), Gtk.ResponseType.OK)
self.add_buttons(get_message("Cancel"), Gtk.ResponseType.CANCEL, get_message("Save"), Gtk.ResponseType.OK)
self.get_content_area().pack_start(builder.get_object("timer_dialog_frame"), True, True, 5)
if self._action is TimerTool.TimerAction.ADD:

View File

@@ -40,7 +40,7 @@ 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">2.0.0 Alpha2</property>
<property name="version">2.0.1 Beta</property>
<property name="copyright">2018-2021 Dmitriy Yefremov
</property>
<property name="comments" translatable="yes">Enigma2 channel and satellite list editor.</property>
@@ -91,51 +91,36 @@ Author: Dmitriy Yefremov
<property name="type_hint">utility</property>
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<child type="titlebar">
<placeholder/>
<child type="action">
<object class="GtkButton" id="input_dialog_cancel_button">
<property name="label" translatable="yes">Cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
</object>
</child>
<child type="action">
<object class="GtkButton" id="input_dialog_ok_button">
<property name="label" translatable="yes">OK</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
<accelerator key="Return" signal="activate"/>
</object>
</child>
<child internal-child="vbox">
<object class="GtkBox">
<property name="can_focus">False</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_top">4</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox">
<property name="can_focus">False</property>
<property name="valign">center</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="input_dialog_cancel_button">
<property name="label" translatable="yes">Cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="input_dialog_ok_button">
<property name="label" translatable="yes">OK</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
<accelerator key="Return" signal="activate"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
@@ -147,10 +132,10 @@ Author: Dmitriy Yefremov
<object class="GtkEntry" id="input_entry">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="margin_left">2</property>
<property name="margin_right">2</property>
<property name="margin_top">2</property>
<property name="margin_bottom">2</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_top">5</property>
<property name="margin_bottom">5</property>
<property name="primary_icon_name">document-edit-symbolic</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>

View File

@@ -225,8 +225,8 @@ Author: Dmitriy Yefremov
<object class="GtkFrame" id="main_settings_box_frame">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">10</property>
<property name="margin_right">10</property>
<property name="margin_left">5</property>
<property name="margin_right">5</property>
<property name="margin_top">5</property>
<property name="label_xalign">0.019999999552965164</property>
<property name="shadow_type">in</property>
@@ -239,12 +239,13 @@ Author: Dmitriy Yefremov
<property name="margin_top">10</property>
<property name="margin_bottom">10</property>
<property name="orientation">vertical</property>
<property name="spacing">10</property>
<child>
<object class="GtkGrid" id="main_settings_bo">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="row_spacing">2</property>
<property name="column_spacing">2</property>
<property name="row_spacing">5</property>
<property name="column_spacing">10</property>
<property name="column_homogeneous">True</property>
<child>
<object class="GtkLabel" id="ip_label">
@@ -310,9 +311,8 @@ Author: Dmitriy Yefremov
<object class="GtkBox" id="extra_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_left">10</property>
<property name="margin_right">10</property>
<child>
<object class="GtkCheckButton" id="remove_unused_check_button">
<property name="label" translatable="yes">Remove unused bouquets</property>
@@ -384,7 +384,7 @@ Author: Dmitriy Yefremov
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
<property name="position">1</property>
</packing>
</child>
<child>
@@ -438,54 +438,85 @@ Author: Dmitriy Yefremov
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">6</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkExpander" id="expander">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="margin_left">1</property>
<property name="margin_right">1</property>
<property name="margin_bottom">1</property>
<property name="resize_toplevel">True</property>
<object class="GtkFrame" id="log_bar_frame">
<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="label_xalign">0</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkScrolledWindow" id="scrolled_window">
<property name="height_request">120</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTextView" id="text_view">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="editable">False</property>
<property name="left_margin">5</property>
<property name="right_margin">5</property>
<object class="GtkInfoBar" id="log_bar">
<property name="can_focus">False</property>
<property name="baseline_position">bottom</property>
<property name="message_type">other</property>
<property name="show_close_button">True</property>
<child internal-child="action_area">
<object class="GtkButtonBox" id="log_bar_button_box">
<property name="can_focus">False</property>
<property name="layout_style">end</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child internal-child="content_area">
<object class="GtkBox" id="log_bar_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkScrolledWindow" id="scrolled_window">
<property name="height_request">100</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTextView" id="text_view">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="editable">False</property>
<property name="left_margin">5</property>
<property name="right_margin">5</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="expander_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Extra:</property>
</object>
<child type="label_item">
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">7</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkInfoBar" id="info_bar">
<property name="can_focus">False</property>
<property name="margin_left">1</property>
<property name="margin_right">1</property>
<property name="margin_bottom">1</property>
<property name="show_close_button">True</property>
<signal name="response" handler="on_info_bar_close" swapped="no"/>
<child internal-child="action_area">

View File

@@ -35,7 +35,7 @@ from app.connections import download_data, DownloadType, upload_data
from app.settings import SettingsType
from app.ui.backup import backup_data, restore_data
from app.ui.main_helper import append_text_to_tview
from app.ui.settings_dialog import show_settings_dialog
from app.ui.settings_dialog import SettingsDialog
from .dialogs import show_dialog, DialogType, get_message, get_builder
from .uicommons import Gtk, UI_RESOURCES_PATH
@@ -59,10 +59,6 @@ class DownloadDialog:
self._dialog_window = builder.get_object("download_dialog_window")
self._dialog_window.set_transient_for(transient)
self._info_bar = builder.get_object("info_bar")
self._message_label = builder.get_object("info_bar_message_label")
self._text_view = builder.get_object("text_view")
self._expander = builder.get_object("expander")
self._host_entry = builder.get_object("host_entry")
self._data_path_entry = builder.get_object("data_path_entry")
self._remove_unused_check_button = builder.get_object("remove_unused_check_button")
@@ -73,6 +69,13 @@ class DownloadDialog:
self._use_http_switch = builder.get_object("use_http_switch")
self._http_radio_button = builder.get_object("http_radio_button")
self._profile_combo_box = builder.get_object("profile_combo_box")
# Info.
self._info_bar = builder.get_object("info_bar")
self._message_label = builder.get_object("info_bar_message_label")
self._text_view = builder.get_object("text_view")
self._log_bar = builder.get_object("log_bar")
self._log_bar.bind_property("visible", builder.get_object("log_bar_frame"), "visible")
self._log_bar.connect("response", lambda b, r: b.set_visible(False))
self.init_settings()
@@ -120,8 +123,9 @@ class DownloadDialog:
self._dialog_window.destroy()
def on_settings(self, item):
response = show_settings_dialog(self._dialog_window, self._settings)
if response != Gtk.ResponseType.CANCEL:
dialog = SettingsDialog(self._dialog_window, self._settings)
dialog.show()
if dialog.is_updated():
self._s_type = self._settings.setting_type
self.update_profiles()
gen = self._update_settings_callback()
@@ -147,7 +151,7 @@ class DownloadDialog:
@run_task
def download(self, download, d_type):
""" Download/upload data from/to receiver """
GLib.idle_add(self._expander.set_expanded, True)
GLib.idle_add(self._log_bar.set_visible, True)
self.clear_output()
backup, backup_src, data_path = self._settings.backup_before_downloading, None, None

View File

@@ -158,6 +158,8 @@ Author: Dmitriy Yefremov
<columns>
<!-- column-name service -->
<column type="gchararray"/>
<!-- column-name pos -->
<column type="gchararray"/>
<!-- column-name service_id -->
<column type="gchararray"/>
</columns>
@@ -671,7 +673,7 @@ Author: Dmitriy Yefremov
<property name="image">filter_image</property>
<property name="always_show_image">True</property>
<signal name="toggled" handler="on_filter_toggled" swapped="no"/>
<accelerator key="f" signal="clicked" modifiers="GDK_SHIFT_MASK | GDK_CONTROL_MASK"/>
<accelerator key="f" signal="clicked" modifiers="GDK_SHIFT_MASK | Primary"/>
</object>
<packing>
<property name="expand">False</property>
@@ -851,7 +853,6 @@ Author: Dmitriy Yefremov
<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="orientation">vertical</property>
<child>
<object class="GtkScrolledWindow">
@@ -868,22 +869,22 @@ Author: Dmitriy Yefremov
<signal name="button-press-event" handler="on_popup_menu" object="source_popup_menu" swapped="no"/>
<signal name="drag-begin" handler="on_drag_begin" swapped="no"/>
<signal name="drag-data-get" handler="on_drag_data_get" swapped="no"/>
<signal name="key-release-event" handler="on_key_release" swapped="no"/>
<signal name="key-press-event" handler="on_key_press" swapped="no"/>
<child internal-child="selection">
<object class="GtkTreeSelection"/>
</child>
<child>
<object class="GtkTreeViewColumn" id="service_column">
<property name="resizable">True</property>
<property name="sizing">autosize</property>
<property name="min_width">50</property>
<property name="title" translatable="yes">Service</property>
<property name="expand">True</property>
<property name="alignment">0.5</property>
<property name="sort_column_id">0</property>
<child>
<object class="GtkCellRendererText" id="source_service_cellrenderertext">
<object class="GtkCellRendererText" id="source_service_renderertext">
<property name="xpad">5</property>
<property name="ellipsize">end</property>
</object>
<attributes>
<attribute name="text">0</attribute>
@@ -892,15 +893,14 @@ Author: Dmitriy Yefremov
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="ref_column">
<property name="resizable">True</property>
<property name="sizing">autosize</property>
<property name="min_width">50</property>
<property name="title" translatable="yes">Reference</property>
<property name="expand">True</property>
<object class="GtkTreeViewColumn" id="pos_column">
<property name="min_width">70</property>
<property name="title" translatable="yes">Pos</property>
<property name="alignment">0.5</property>
<property name="sort_column_id">1</property>
<child>
<object class="GtkCellRendererText" id="source_reference_cellrenderertext">
<object class="GtkCellRendererText" id="source_pos_renderertext">
<property name="xpad">5</property>
<property name="xalign">0.50999999046325684</property>
</object>
<attributes>
@@ -909,6 +909,23 @@ Author: Dmitriy Yefremov
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn" id="ref_column">
<property name="resizable">True</property>
<property name="min_width">50</property>
<property name="title" translatable="yes">Reference</property>
<property name="alignment">0.5</property>
<child>
<object class="GtkCellRendererText" id="source_reference_renderertext">
<property name="xpad">10</property>
<property name="xalign">0.50999999046325684</property>
</object>
<attributes>
<attribute name="text">2</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
</object>
@@ -1039,7 +1056,6 @@ Author: Dmitriy Yefremov
<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="orientation">vertical</property>
<child>
<object class="GtkScrolledWindow" id="fav_scrolled_window">
@@ -1056,7 +1072,7 @@ Author: Dmitriy Yefremov
<property name="tooltip_column">9</property>
<signal name="button-press-event" handler="on_bouquet_popup_menu" object="bouquet_popup_menu" swapped="no"/>
<signal name="drag-data-received" handler="on_drag_data_received" swapped="no"/>
<signal name="key-release-event" handler="on_key_release" swapped="no"/>
<signal name="key-release-event" handler="on_key_press" swapped="no"/>
<child internal-child="selection">
<object class="GtkTreeSelection">
<property name="mode">multiple</property>

View File

@@ -44,7 +44,7 @@ from app.settings import SEP
from app.tools.epg import EPG, ChannelsParser
from app.ui.dialogs import get_message, show_dialog, DialogType, get_builder
from .main_helper import on_popup_menu, update_entry_data
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, Column, EPG_ICON, KeyboardKey
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, Column, EPG_ICON, KeyboardKey, IS_GNOME_SESSION
class RefsSource(Enum):
@@ -80,7 +80,7 @@ class EpgDialog:
"on_enable_filtering_switch": self.on_enable_filtering_switch,
"on_update_on_start_switch": self.on_update_on_start_switch,
"on_field_icon_press": self.on_field_icon_press,
"on_key_release": self.on_key_release}
"on_key_press": self.on_key_press}
self._services = {}
self._ex_services = services
@@ -93,7 +93,6 @@ class EpgDialog:
self._use_web_source = False
self._update_epg_data_on_start = False
self._refs_source = RefsSource.SERVICES
self._show_tooltips = True
self._download_xml_is_active = False
builder = get_builder(UI_RESOURCES_PATH + "epg.glade", handlers)
@@ -132,6 +131,17 @@ class EpgDialog:
self._epg_dat_stb_path_entry = builder.get_object("epg_dat_stb_path_entry")
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"))
self._dialog.set_titlebar(header_bar)
builder.get_object("left_action_box").reparent(header_bar)
right_box = builder.get_object("right_action_box")
builder.get_object("main_actions_box").remove(right_box)
header_bar.pack_end(right_box)
builder.get_object("toolbar_box").set_visible(False)
# Setting the last size of the dialog window
window_size = self._settings.get("epg_tool_window_size")
if window_size:
@@ -188,14 +198,14 @@ class EpgDialog:
try:
self.download_epg_from_stb()
except OSError as e:
self.show_info_message("Download epg.dat file error: {}".format(e), Gtk.MessageType.ERROR)
self.show_info_message(f"Download epg.dat file error: {e}", Gtk.MessageType.ERROR)
return
yield True
try:
refs = EPG.get_epg_refs(self._epg_dat_path_entry.get_text() + "epg.dat")
except FileNotFoundError as e:
self.show_info_message("Read data error: {}".format(e), Gtk.MessageType.ERROR)
self.show_info_message(f"Read data error: {e}", Gtk.MessageType.ERROR)
return
yield True
@@ -225,7 +235,7 @@ class EpgDialog:
s_types = (BqServiceType.MARKER.value, BqServiceType.IPTV.value)
filtered = filter(None, [srvs.get(ref) for ref in refs]) if refs else filter(
lambda s: s.service_type not in s_types, self._ex_services.values())
list(map(self._services_model.append, map(lambda s: (s.service, s.fav_id), filtered)))
list(map(self._services_model.append, map(lambda s: (s.service, s.pos, s.fav_id), filtered)))
self.update_source_count_info()
def init_xml_source(self, refs):
@@ -274,7 +284,7 @@ class EpgDialog:
path = tfp.name.rstrip(".gz")
except (HTTPError, URLError) as e:
raise ValueError("{} {}".format(get_message("Download XML file error."), e))
raise ValueError(f"{get_message('Download XML file error.')} {e}")
else:
try:
with open(path, "wb") as f_out:
@@ -282,7 +292,7 @@ class EpgDialog:
shutil.copyfileobj(f, f_out)
os.remove(tfp.name)
except Exception as e:
raise ValueError("{} {}".format(get_message("Unpacking data error."), e))
raise ValueError(f"{get_message('Unpacking data error.')} {e}")
finally:
self._download_xml_is_active = False
self.update_active_header_elements(True)
@@ -291,7 +301,7 @@ class EpgDialog:
s_refs, info = ChannelsParser.get_refs_from_xml(path)
yield True
except Exception as e:
raise ValueError("{} {}".format(get_message("XML parsing error:"), e))
raise ValueError(f"{get_message('XML parsing error:')} {e}")
else:
if refs:
s_refs = filter(lambda x: x.num in refs, s_refs)
@@ -300,7 +310,7 @@ class EpgDialog:
self.update_source_count_info()
yield True
def on_key_release(self, view, event):
def on_key_press(self, view, event):
""" Handling keystrokes """
key_code = event.hardware_keycode
if not KeyboardKey.value_exist(key_code):
@@ -348,7 +358,7 @@ class EpgDialog:
for row in self._services_model:
name = re.sub("\\W+", "", str(row[0])).upper()
name = name.translate(tr) if use_cyrillic else name
source[name] = row[1]
source[name] = row
success_count = 0
not_founded = {}
@@ -378,7 +388,7 @@ class EpgDialog:
get_message("Count of successfully configured services:"),
success_count), Gtk.MessageType.INFO)
def assign_data(self, row, ref, show_error=False):
def assign_data(self, row, data, show_error=False):
if row[Column.FAV_TYPE] != BqServiceType.IPTV.value:
if not show_error:
self.show_info_message(get_message("Not allowed in this context!"), Gtk.MessageType.ERROR)
@@ -386,14 +396,15 @@ class EpgDialog:
fav_id = row[Column.FAV_ID]
fav_id_data = fav_id.split(":")
fav_id_data[3:7] = ref.split(":")
fav_id_data[3:7] = data[-1].split(":")
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
row[Column.FAV_TOOLTIP] = ":".join(fav_id_data[:10]) if self._show_tooltips else None
src = f"{get_message('EPG source')}: {data[0]} ({data[1]})"
row[Column.FAV_TOOLTIP] = f"{get_message('Service reference')}: {':'.join(fav_id_data[:10])}\n{src}"
def on_filter_toggled(self, button: Gtk.ToggleButton):
self._filter_bar.set_search_mode(button.get_active())
@@ -412,7 +423,7 @@ class EpgDialog:
model, paths = self._source_view.get_selection().get_selected_rows()
self._current_ref.clear()
if paths:
self._current_ref.append(model[paths][1])
self._current_ref.append(model[paths][:])
def on_assign_ref(self, item=None):
if self._current_ref:
@@ -481,7 +492,7 @@ class EpgDialog:
# ***************** Drag-and-drop *********************#
def init_drag_and_drop(self):
""" Enable drag-and-drop """
""" Enable drag-and-drop. """
target = []
self._source_view.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK, target, Gdk.DragAction.COPY)
self._source_view.drag_source_add_text_targets()
@@ -494,17 +505,22 @@ class EpgDialog:
if selection.count_selected_rows() > 1:
view.do_toggle_cursor_row(view)
def on_drag_data_get(self, view: Gtk.TreeView, drag_context, data, info, time):
def on_drag_data_get(self, view, drag_context, data, info, time):
model, paths = view.get_selection().get_selected_rows()
if paths:
val = model.get_value(model.get_iter(paths), 1)
data.set_text(val, -1)
s_data = model[paths][:]
if all(s_data):
data.set_text("::::".join(s_data), -1)
else:
self.show_info_message(get_message("Source error!"), Gtk.MessageType.ERROR)
def on_drag_data_received(self, view: Gtk.TreeView, drag_context, x, y, data, info, time):
def on_drag_data_received(self, view, drag_context, x, y, data, info, time):
path, pos = view.get_dest_row_at_pos(x, y)
model = view.get_model()
self.assign_data(model[path], data.get_text())
self.update_epg_count()
data = data.get_text()
if data:
self.assign_data(model[path], data.split("::::"))
self.update_epg_count()
return False
# ***************** Options *********************#

View File

@@ -632,7 +632,7 @@ Author: Dmitriy Yefremov
<property name="image">rename_image_2</property>
<property name="use_stock">False</property>
<signal name="activate" handler="on_file_edit" object="file_name_column_renderer" swapped="no"/>
<accelerator key="r" signal="activate" modifiers="GDK_CONTROL_MASK"/>
<accelerator key="r" signal="activate" modifiers="Primary"/>
<accelerator key="F2" signal="activate"/>
</object>
</child>

View File

@@ -469,7 +469,7 @@ class FtpClientBox(Gtk.HBox):
resp = "2"
try:
GLib.idle_add(self._app._wait_dialog.show)
GLib.idle_add(self._app.wait_dialog.show)
uris = data.get_uris()
if self._settings.is_darwin and len(uris) == 1:
@@ -488,7 +488,7 @@ class FtpClientBox(Gtk.HBox):
else:
resp = self._ftp.send_file(path.name, str(path.parent) + "/", callback=self.update_ftp_info)
finally:
GLib.idle_add(self._app._wait_dialog.hide)
GLib.idle_add(self._app.wait_dialog.hide)
if resp and resp[0] == "2":
itr = self._ftp_model.get_iter_first()
if itr:
@@ -507,7 +507,7 @@ class FtpClientBox(Gtk.HBox):
def on_file_drag_data_received(self, view, context, x, y, data, info, time):
cur_path = self._file_model.get_value(self._file_model.get_iter_first(), self.Column.ATTR) + "/"
try:
GLib.idle_add(self._app._wait_dialog.show)
GLib.idle_add(self._app.wait_dialog.show)
uris = data.get_uris()
if self._settings.is_darwin and len(uris) == 1:
@@ -525,7 +525,7 @@ class FtpClientBox(Gtk.HBox):
except OSError as e:
log(e)
finally:
GLib.idle_add(self._app._wait_dialog.hide)
GLib.idle_add(self._app.wait_dialog.hide)
self.init_file_data(cur_path)
Gtk.drag_finish(context, True, False, time)
@@ -564,6 +564,10 @@ class FtpClientBox(Gtk.HBox):
self.on_ftp_file_remove()
elif self._file_view.is_focus():
self.on_file_remove()
elif key is KeyboardKey.RETURN:
path, column = view.get_cursor()
if path:
view.emit("row-activated", path, column)
def on_view_press(self, view, event):
if event.get_event_type() == Gdk.EventType.BUTTON_PRESS and event.button == Gdk.BUTTON_PRIMARY:

View File

@@ -185,7 +185,7 @@ Author: Dmitriy Yefremov
<object class="GtkImage" id="cancel_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-cancel</property>
<property name="stock">gtk-close</property>
</object>
</child>
</object>
@@ -268,6 +268,33 @@ Author: Dmitriy Yefremov
<property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property>
<signal name="response" handler="on_response" swapped="no"/>
<child type="action">
<object class="GtkButton" id="cancel_config_list_button">
<property name="label" translatable="yes">Cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
</object>
</child>
<child type="action">
<object class="GtkButton" id="list_configuration_apply_button">
<property name="label" translatable="yes">Apply</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
<signal name="clicked" handler="on_apply" swapped="no"/>
</object>
</child>
<child type="action">
<object class="GtkButton" id="list_configuration_ok_button">
<property name="label" translatable="yes">OK</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
</object>
</child>
<child internal-child="vbox">
<object class="GtkBox" id="iptv_list_configuration_dialog_box">
<property name="can_focus">False</property>
@@ -278,48 +305,6 @@ Author: Dmitriy Yefremov
<property name="can_focus">False</property>
<property name="valign">center</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="cancel_config_list_button">
<property name="label" translatable="yes">Cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="list_configuration_apply_button">
<property name="label" translatable="yes">Apply</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
<signal name="clicked" handler="on_apply" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="list_configuration_ok_button">
<property name="label" translatable="yes">OK</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
@@ -873,6 +858,34 @@ Author: Dmitriy Yefremov
<child type="titlebar">
<placeholder/>
</child>
<child type="action">
<object class="GtkButton" id="iptv_dialog_cancel_button">
<property name="label" translatable="yes">Cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
</object>
</child>
<child type="action">
<object class="GtkButton" id="iptv_dialog_add_button">
<property name="label" translatable="yes">Add</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
<signal name="clicked" handler="on_save" swapped="no"/>
</object>
</child>
<child type="action">
<object class="GtkButton" id="iptv_dialog_save_button">
<property name="label" translatable="yes">Save</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
<signal name="clicked" handler="on_save" swapped="no"/>
</object>
</child>
<child internal-child="vbox">
<object class="GtkBox" id="iptv_dialog_box">
<property name="can_focus">False</property>
@@ -882,49 +895,6 @@ Author: Dmitriy Yefremov
<property name="can_focus">False</property>
<property name="valign">center</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="iptv_dialog_cancel_button">
<property name="label" translatable="yes">Cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="iptv_dialog_add_button">
<property name="label" translatable="yes">Add</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
<signal name="clicked" handler="on_save" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="iptv_dialog_save_button">
<property name="label" translatable="yes">Save</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
<signal name="clicked" handler="on_save" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
@@ -938,7 +908,6 @@ Author: Dmitriy Yefremov
<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="orientation">vertical</property>
<child>
<object class="GtkFrame" id="iptv_dialog_service_data_frame">
@@ -1340,60 +1309,60 @@ Author: Dmitriy Yefremov
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkInfoBar" id="info_bar">
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkInfoBar" id="info_bar">
<property name="can_focus">False</property>
<property name="show_close_button">True</property>
<signal name="response" handler="on_info_bar_close" swapped="no"/>
<child internal-child="action_area">
<object class="GtkButtonBox">
<property name="can_focus">False</property>
<property name="show_close_button">True</property>
<signal name="response" handler="on_info_bar_close" swapped="no"/>
<child internal-child="action_area">
<object class="GtkButtonBox">
<property name="spacing">6</property>
<property name="layout_style">end</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child internal-child="content_area">
<object class="GtkBox">
<property name="can_focus">False</property>
<property name="spacing">16</property>
<child>
<object class="GtkLabel" id="info_bar_message_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">6</property>
<property name="layout_style">end</property>
<property name="halign">start</property>
<property name="label" translatable="yes">label</property>
<property name="ellipsize">end</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child internal-child="content_area">
<object class="GtkBox">
<property name="can_focus">False</property>
<property name="spacing">16</property>
<child>
<object class="GtkLabel" id="info_bar_message_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">label</property>
<property name="ellipsize">end</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
<property name="position">2</property>
</packing>
</child>
</object>

View File

@@ -474,6 +474,8 @@ class IptvListDialog:
self._apply_button = builder.get_object("list_configuration_apply_button")
self._cancel_button = builder.get_object("cancel_config_list_button")
self._ok_button = builder.get_object("list_configuration_ok_button")
self._ok_button.bind_property("visible", self._apply_button, "visible", 4)
self._ok_button.bind_property("visible", self._cancel_button, "visible", 4)
# Style
style_provider = Gtk.CssProvider()
style_provider.load_from_path(UI_RESOURCES_PATH + "style.css")
@@ -585,27 +587,29 @@ class IptvListConfigurationDialog(IptvListDialog):
sid_auto = self._sid_auto_check_button.get_active()
nid_default = self._nid_check_button.get_active()
namespace_default = self._namespace_check_button.get_active()
all_default = self.is_all_data_default()
st_type = get_stream_type(self._stream_type_combobox)
s_id = 0 if id_default else int(self._list_srv_id_entry.get_text())
s_id = "0" if id_default else self._list_srv_id_entry.get_text()
srv_type = "1" if type_default else self._list_srv_type_entry.get_text()
tid = "0" if tid_default else "{:X}".format(int(self._list_tid_entry.get_text()))
nid = "0" if nid_default else "{:X}".format(int(self._list_nid_entry.get_text()))
namespace = "0" if namespace_default else "{:X}".format(int(self._list_namespace_entry.get_text()))
sid = "0" if sid_auto else self._list_sid_entry.get_text()
tid = "0" if tid_default else f"{int(self._list_tid_entry.get_text()):X}"
nid = "0" if nid_default else f"{int(self._list_nid_entry.get_text()):X}"
namespace = "0" if namespace_default else f"{int(self._list_namespace_entry.get_text()):X}"
for index, row in enumerate(self._rows):
fav_id = row[Column.FAV_ID]
data, sep, desc = fav_id.partition("http")
data = data.split(":")
if self.is_all_data_default():
if all_default:
data[1], data[2], data[3], data[4], data[5], data[6] = "010000"
else:
data[0], data[1], data[2], data[4], data[5], data[6] = st_type, s_id, srv_type, tid, nid, namespace
data[3] = "{:X}".format(index) if sid_auto else "0"
data[3] = f"{index:X}" if sid_auto else sid
data = ":".join(data)
new_fav_id = "{}{}{}".format(data, sep, desc)
new_fav_id = f"{data}{sep}{desc}"
row[Column.FAV_ID] = new_fav_id
srv = self._services.pop(fav_id, None)
@@ -616,6 +620,7 @@ class IptvListConfigurationDialog(IptvListDialog):
list(map(lambda r: self._bouquet.append(r[Column.FAV_ID]), self._fav_model))
self._info_bar.set_visible(True)
self._ok_button.set_visible(True)
class M3uImportDialog(IptvListDialog):
@@ -636,8 +641,6 @@ class M3uImportDialog(IptvListDialog):
self._dialog.set_title(get_message("Playlist import"))
self._dialog.connect("delete-event", self.on_close)
self._apply_button.set_label(get_message("Import"))
self._ok_button.bind_property("visible", self._apply_button, "visible", 4)
self._ok_button.bind_property("visible", self._cancel_button, "visible", 4)
# Progress
self._progress_bar = Gtk.ProgressBar(visible=False, valign="center")
self._spinner = Gtk.Spinner(active=False)
@@ -662,7 +665,7 @@ class M3uImportDialog(IptvListDialog):
extra_box.pack_start(self._info_label, False, False, 5)
extra_box.pack_end(self._picon_box, True, True, 5)
frame = Gtk.Frame(visible=True)
frame = Gtk.Frame(visible=True, margin_bottom=5)
frame.add(extra_box)
self._data_box.add(frame)
@@ -678,7 +681,7 @@ class M3uImportDialog(IptvListDialog):
GLib.idle_add(self._picon_box.set_sensitive, True)
break
finally:
msg = "{} {}.".format(get_message("Streams detected:"), len(self._services) if self._services else 0)
msg = f"{get_message('Streams detected:')} {len(self._services) if self._services else 0}."
GLib.idle_add(self._info_label.set_text, msg)
GLib.idle_add(self._spinner.set_property, "active", False)
@@ -697,6 +700,8 @@ class M3uImportDialog(IptvListDialog):
s_type = params[1]
params = params[2:]
st_type = get_stream_type(self._stream_type_combobox)
sid_auto = self._sid_auto_check_button.get_active()
sid = 0 if sid_auto else int(self._list_sid_entry.get_text())
for i, s in enumerate(self._services, start=params[0]):
# Skipping markers.
@@ -704,7 +709,7 @@ class M3uImportDialog(IptvListDialog):
services.append(s)
continue
params[0] = i
params[0] = i if sid_auto else sid
picon_id = "{}_{}_{:X}_{:X}_{:X}_{:X}_{:X}_0_0_0.png".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:
@@ -764,16 +769,16 @@ class M3uImportDialog(IptvListDialog):
@run_idle
def on_picon_load_done(self, data, user_data):
try:
self._info_label.set_text("Processing: {}".format(user_data))
self._info_label.set_text(f"Processing: {user_data}")
f = Gio.MemoryInputStream.new_from_data(data)
pixbuf = GdkPixbuf.Pixbuf.new_from_stream_at_scale(f, 220, 132, False, self._cancellable)
path = "{}{}".format(self._pic_path, user_data)
path = f"{self._pic_path}{user_data}"
pixbuf.savev(path, "png", [], [])
self._picons[user_data] = get_picon_pixbuf(path)
except GLib.GError as e:
self.update_progress(1)
if e.code != Gio.IOErrorEnum.CANCELLED:
log("Loading picon [{}] data error: {}".format(user_data, e))
log(f"Loading picon [{user_data}] data error: {e}")
else:
self.update_progress()
@@ -789,14 +794,14 @@ class M3uImportDialog(IptvListDialog):
self._progress_bar.set_visible(False)
self._progress_bar.set_fraction(0.0)
self._apply_button.set_sensitive(True)
self._info_label.set_text("Errors: {}.".format(self._errors_count))
self._info_label.set_text(f"Errors: {self._errors_count}.")
self._is_download = False
gen = self.update_fav_model()
GLib.idle_add(lambda: next(gen, False), priority=GLib.PRIORITY_LOW)
def update_fav_model(self):
services = self._app._services
services = self._app.current_services
picons = self._app._picons
model = self._app.fav_view.get_model()
for r in model:

View File

@@ -1,5 +1,6 @@
* {
-GtkDialog-action-area-border: 5em;
-GtkDialog-action-area-border: 6em;
-GtkDialog-button-spacing: 12;
}
entry {
@@ -36,3 +37,7 @@ switch slider {
min-height: 1.5em;
min-width: 1.5em;
}
.dialog-action-area button {
margin-bottom: 0.6em;
}

View File

@@ -344,7 +344,7 @@ Author: Dmitriy Yefremov
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_new_bouquet" object="bouquets_tree_view" swapped="no"/>
<accelerator key="Insert" signal="activate" modifiers="GDK_CONTROL_MASK"/>
<accelerator key="Insert" signal="activate" modifiers="Primary"/>
</object>
</child>
<child>
@@ -355,7 +355,8 @@ Author: Dmitriy Yefremov
<property name="can_focus">False</property>
<property name="image">import_bouquet_image</property>
<property name="use_stock">False</property>
<accelerator key="i" signal="activate" modifiers="GDK_CONTROL_MASK"/>
<signal name="activate" handler="on_import_bouquet" swapped="no"/>
<accelerator key="i" signal="activate" modifiers="Primary"/>
</object>
</child>
<child>
@@ -383,7 +384,7 @@ Author: Dmitriy Yefremov
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_bouquets_cut" object="bouquets_tree_view" swapped="no"/>
<accelerator key="x" signal="activate" modifiers="GDK_CONTROL_MASK"/>
<accelerator key="x" signal="activate" modifiers="Primary"/>
</object>
</child>
<child>
@@ -395,7 +396,7 @@ Author: Dmitriy Yefremov
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_bouquets_copy" object="bouquets_tree_view" swapped="no"/>
<accelerator key="c" signal="activate" modifiers="GDK_CONTROL_MASK"/>
<accelerator key="c" signal="activate" modifiers="Primary"/>
</object>
</child>
<child>
@@ -407,7 +408,7 @@ Author: Dmitriy Yefremov
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_bouquets_paste" object="bouquets_tree_view" swapped="no"/>
<accelerator key="v" signal="activate" modifiers="GDK_CONTROL_MASK"/>
<accelerator key="v" signal="activate" modifiers="Primary"/>
</object>
</child>
<child>
@@ -425,7 +426,7 @@ Author: Dmitriy Yefremov
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_edit" swapped="no"/>
<accelerator key="e" signal="activate" modifiers="GDK_CONTROL_MASK"/>
<accelerator key="e" signal="activate" modifiers="Primary"/>
</object>
</child>
<child>
@@ -918,7 +919,7 @@ Author: Dmitriy Yefremov
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_to_fav_end_copy" object="services_tree_view" swapped="no"/>
<accelerator key="BackSpace" signal="activate" modifiers="GDK_CONTROL_MASK"/>
<accelerator key="BackSpace" signal="activate" modifiers="Primary"/>
</object>
</child>
<child>
@@ -929,7 +930,7 @@ Author: Dmitriy Yefremov
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_to_fav_copy" object="services_tree_view" swapped="no"/>
<accelerator key="Insert" signal="activate" modifiers="GDK_CONTROL_MASK"/>
<accelerator key="Insert" signal="activate" modifiers="Primary"/>
</object>
</child>
<child>
@@ -1033,7 +1034,7 @@ Author: Dmitriy Yefremov
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_services_copy" object="services_tree_view" swapped="no"/>
<accelerator key="c" signal="activate" modifiers="GDK_CONTROL_MASK"/>
<accelerator key="c" signal="activate" modifiers="Primary"/>
</object>
</child>
<child>
@@ -1044,7 +1045,7 @@ Author: Dmitriy Yefremov
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_edit" swapped="no"/>
<accelerator key="e" signal="activate" modifiers="GDK_CONTROL_MASK"/>
<accelerator key="e" signal="activate" modifiers="Primary"/>
</object>
</child>
<child>
@@ -1291,7 +1292,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">2.0.0 Alpha2</property>
<property name="label">2.0.1 Beta</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
@@ -3690,7 +3691,7 @@ Author: Dmitriy Yefremov
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_fav_cut" object="fav_tree_view" swapped="no"/>
<accelerator key="x" signal="activate" modifiers="GDK_CONTROL_MASK"/>
<accelerator key="x" signal="activate" modifiers="Primary"/>
</object>
</child>
<child>
@@ -3702,7 +3703,7 @@ Author: Dmitriy Yefremov
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_fav_copy" object="fav_tree_view" swapped="no"/>
<accelerator key="c" signal="activate" modifiers="GDK_CONTROL_MASK"/>
<accelerator key="c" signal="activate" modifiers="Primary"/>
</object>
</child>
<child>
@@ -3714,7 +3715,7 @@ Author: Dmitriy Yefremov
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_fav_paste" object="fav_tree_view" swapped="no"/>
<accelerator key="v" signal="activate" modifiers="GDK_CONTROL_MASK"/>
<accelerator key="v" signal="activate" modifiers="Primary"/>
</object>
</child>
<child>
@@ -3731,7 +3732,7 @@ Author: Dmitriy Yefremov
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_edit" swapped="no"/>
<accelerator key="e" signal="activate" modifiers="GDK_CONTROL_MASK"/>
<accelerator key="e" signal="activate" modifiers="Primary"/>
</object>
</child>
<child>

View File

@@ -60,16 +60,12 @@ from .dialogs import show_dialog, DialogType, get_chooser_dialog, WaitDialog, ge
from .download_dialog import DownloadDialog
from .imports import ImportDialog, import_bouquet
from .iptv import IptvDialog, SearchUnavailableDialog, IptvListConfigurationDialog, YtListImportDialog, M3uImportDialog
from .main_helper import (insert_marker, move_items, rename, ViewTarget, set_flags, locate_in_services,
scroll_to, get_base_model, update_picons_data, copy_picon_reference, assign_picons,
remove_picon, is_only_one_item_selected, gen_bouquets, BqGenType, append_picons,
get_selection, get_model_data, remove_all_unused_picons, get_picon_pixbuf, get_base_itrs,
get_iptv_url)
from .main_helper import *
from .picons import PiconManager
from .satellites import SatellitesTool, ServicesUpdateDialog
from .search import SearchProvider
from .service_details_dialog import ServiceDetailsDialog, Action
from .settings_dialog import show_settings_dialog
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)
@@ -159,6 +155,7 @@ class Application(Gtk.Application):
"on_import_m3u": self.on_import_m3u,
"on_bouquet_export": self.on_bouquet_export,
"on_export_to_m3u": self.on_export_to_m3u,
"on_import_bouquet": self.on_import_bouquet,
"on_insert_marker": self.on_insert_marker,
"on_insert_space": self.on_insert_space,
"on_fav_press": self.on_fav_press,
@@ -429,7 +426,7 @@ class Application(Gtk.Application):
def do_startup(self):
Gtk.Application.do_startup(self)
# App menu.
builder = get_builder(UI_RESOURCES_PATH + "app_menu.ui")
builder = get_builder(UI_RESOURCES_PATH + "app_menu.ui", tag="attribute")
if not IS_GNOME_SESSION:
if IS_DARWIN:
self.set_app_menu(builder.get_object("mac_app_menu"))
@@ -1404,15 +1401,25 @@ class Application(Gtk.Application):
def on_view_drag_data_received(self, view, drag_context, x, y, data, info, time):
txt = data.get_text()
uris = data.get_uris()
name, model = get_model_data(view)
if txt:
name, model = get_model_data(view)
if txt.startswith("file://") and name == self.SERVICE_MODEL_NAME:
self.on_import_data(urlparse(unquote(txt)).path.strip())
elif name == self.FAV_MODEL_NAME:
self.receive_selection(view=view, drop_info=view.get_dest_row_at_pos(x, y), data=txt)
elif len(uris) == 2:
self.picons_buffer = self.on_assign_picon(view, urlparse(unquote(uris[0])).path,
urlparse(unquote(uris[1])).path + os.sep)
if uris:
if len(uris) == 2:
self.picons_buffer = self.on_assign_picon(view, urlparse(unquote(uris[0])).path,
urlparse(unquote(uris[1])).path + os.sep)
elif IS_DARWIN and len(uris) == 1:
src, sep, dest = uris[0].partition(self.DRAG_SEP)
src_path = urlparse(unquote(src)).path
if dest:
dest_path = urlparse(unquote(dest)).path + os.sep
self.picons_buffer = self.on_assign_picon(view, src_path, dest_path)
drag_context.finish(True, False, time)
def on_bq_view_drag_data_received(self, view, drag_context, x, y, data, info, time):
@@ -2196,13 +2203,14 @@ class Application(Gtk.Application):
self._bouquets["{}:{}".format(b_row[Column.BQ_NAME], b_row[Column.BQ_TYPE])] = bq
def delete_selection(self, view, *args):
""" Used for clear selection on given view(s) """
""" Used for clear selection on given view(s). """
for v in [view, *args]:
v.get_selection().unselect_all()
def on_settings(self, action, value=None):
response = show_settings_dialog(self._main_window, self._settings)
if response != Gtk.ResponseType.CANCEL:
dialog = SettingsDialog(self._main_window, self._settings)
dialog.show()
if dialog.is_updated():
gen = self.update_settings()
GLib.idle_add(lambda: next(gen, False), priority=GLib.PRIORITY_LOW)
@@ -2540,6 +2548,10 @@ class Application(Gtk.Application):
GLib.idle_add(lambda: next(gen, False), priority=GLib.PRIORITY_LOW)
def on_import_data(self, path):
if self._services_load_spinner.get_property("active"):
self.show_error_message("Data loading in progress!")
return
msg = "Combine with the current data?"
if len(self._services_model) > 0 and show_dialog(DialogType.QUESTION, self._main_window,
msg) == Gtk.ResponseType.OK:
@@ -3629,12 +3641,16 @@ def start_app():
try:
Settings.get_instance()
except SettingsReadException as e:
msg = "{}\n {}".format(get_message("Error reading or writing program settings!"), e)
msg = f"{get_message('Error reading or writing program settings!')}\n {e}"
show_dialog(DialogType.INFO, transient=Gtk.Dialog(), text=msg)
except SettingsException as e:
msg = "{} \n{}".format(e, get_message("All setting were reset. Restart the program!"))
show_dialog(DialogType.INFO, transient=Gtk.Dialog(), text=msg)
msg = f"{e}\n\n{get_message('It is recommended to load the default settings!')}"
dlg = Gtk.Dialog()
if show_dialog(DialogType.QUESTION, dlg, msg) != Gtk.ResponseType.OK:
return True
Settings.reset_to_default()
show_dialog(DialogType.INFO, transient=dlg, text=get_message("All setting were reset. Restart the program!"))
else:
app = Application()
app.run(sys.argv)

View File

@@ -26,7 +26,14 @@
#
""" Helper module for the ui. """
""" Helper module for the GUI. """
__all__ = ("insert_marker", "move_items", "rename", "ViewTarget", "set_flags", "locate_in_services",
"scroll_to", "get_base_model", "update_picons_data", "copy_picon_reference", "assign_picons",
"remove_picon", "is_only_one_item_selected", "gen_bouquets", "BqGenType", "append_picons",
"get_selection", "get_model_data", "remove_all_unused_picons", "get_picon_pixbuf", "get_base_itrs",
"get_iptv_url", "update_entry_data", "append_text_to_tview", "on_popup_menu")
import os
import shutil
from collections import defaultdict

View File

@@ -618,10 +618,10 @@ Author: Dmitriy Yefremov
</packing>
</child>
<child>
<object class="GtkSwitch" id="auto_filer_switch">
<object class="GtkSwitch" id="auto_filter_switch">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip_text" translatable="yes">Automatically set the name selected in the favorites list. </property>
<property name="tooltip_text" translatable="yes">Automatically set the name selected in the favorites list.</property>
<property name="valign">center</property>
<property name="margin_right">5</property>
</object>
@@ -633,7 +633,7 @@ Author: Dmitriy Yefremov
</packing>
</child>
<child>
<object class="GtkLabel" id="auto_filer_label">
<object class="GtkLabel" id="auto_filter_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Auto</property>
@@ -675,7 +675,7 @@ Author: Dmitriy Yefremov
<property name="can_focus">False</property>
<child>
<object class="GtkCheckButton" id="src_filter_button">
<property name="label" translatable="yes">Filer</property>
<property name="label" translatable="yes">Filter</property>
<property name="can_focus">False</property>
<property name="focus_on_click">False</property>
<property name="receives_default">False</property>
@@ -705,7 +705,7 @@ Author: Dmitriy Yefremov
<object class="GtkTreeView" id="picons_src_view">
<property name="visible">True</property>
<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="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="enable_grid_lines">horizontal</property>
<property name="tooltip_column">0</property>

View File

@@ -172,7 +172,7 @@ class PiconManager(Gtk.Box):
self._info_bar.connect("response", lambda b, r: b.set_visible(False))
# Filter.
self._filter_bar = builder.get_object("filter_bar")
self._auto_filer_switch = builder.get_object("auto_filer_switch")
self._auto_filter_switch = builder.get_object("auto_filter_switch")
self._filter_button = builder.get_object("filter_button")
self._filter_button.bind_property("active", self._filter_bar, "visible")
self._filter_button.bind_property("active", self._src_filter_button, "visible")
@@ -339,8 +339,11 @@ class PiconManager(Gtk.Box):
def on_picons_view_drag_data_get(self, view, drag_context, data, info, time):
model, path = view.get_selection().get_selected_rows()
if path:
data.set_uris([Path(model[path][-1]).as_uri(),
Path(self._settings.profile_picons_path).as_uri()])
dest_uri = Path(self._settings.profile_picons_path).as_uri()
if IS_DARWIN:
data.set_uris([f"{Path(model[path][-1]).as_uri()}{self._app.DRAG_SEP}{dest_uri}"])
else:
data.set_uris([Path(model[path][-1]).as_uri(), dest_uri])
def on_picons_view_drag_drop(self, view, drag_context, x, y, time):
view.stop_emission_by_name("drag_drop")
@@ -357,7 +360,7 @@ class PiconManager(Gtk.Box):
self.update_picons_from_file(view, txt)
return
itr_str, sep, src = txt.partition("::::")
itr_str, sep, src = txt.partition(self._app.DRAG_SEP)
if src == self._app.BQ_MODEL_NAME:
return
@@ -568,6 +571,7 @@ class PiconManager(Gtk.Box):
dest_path = path or self._settings.profile_picons_path
settings = Settings(self._settings.settings)
settings.profile_picons_path = f"{dest_path}{SEP}"
settings.current_profile = self._settings.current_profile
self.show_info_message(get_message("Please, wait..."), Gtk.MessageType.INFO)
self.run_func(lambda: upload_data(settings=settings,
download_type=DownloadType.PICONS,
@@ -580,6 +584,7 @@ class PiconManager(Gtk.Box):
path = path or self._settings.profile_picons_path
settings = Settings(self._settings.settings)
settings.profile_picons_path = path + SEP
settings.current_profile = self._settings.current_profile
self.run_func(lambda: download_data(settings=settings,
download_type=DownloadType.PICONS,
callback=self.append_output,
@@ -937,7 +942,7 @@ class PiconManager(Gtk.Box):
self._filter_button.set_active(not self._filter_button.get_active())
def on_fav_changed(self, view, path, column):
if self._app.page is Page.PICONS and self._auto_filer_switch.get_active():
if self._app.page is Page.PICONS and self._auto_filter_switch.get_active():
model = view.get_model()
self._picons_filter_entry.set_text(model.get_value(model.get_iter(path), Column.FAV_SERVICE))

View File

@@ -148,7 +148,7 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Audio Track</property>
<property name="icon_name">multimedia-volume-control</property>
<property name="icon_name">audio-volume-high</property>
</object>
</child>
</object>

View File

@@ -36,9 +36,9 @@ from app.connections import HttpAPI
from app.eparser.ecommons import BqServiceType
from app.settings import PlayStreamsMode, IS_DARWIN, SettingsType
from app.tools.media import Player
from app.ui.dialogs import get_builder
from app.ui.dialogs import get_builder, get_message
from app.ui.main_helper import get_iptv_url
from app.ui.uicommons import Gtk, Gdk, UI_RESOURCES_PATH, FavClickMode, Column, IS_GNOME_SESSION
from app.ui.uicommons import Gtk, Gdk, UI_RESOURCES_PATH, FavClickMode, Column, IS_GNOME_SESSION, Page
class PlayerBox(Gtk.Box):
@@ -295,7 +295,7 @@ class PlayerBox(Gtk.Box):
""" Returns a string representation of time from duration in milliseconds """
m, s = divmod(duration // 1000, 60)
h, m = divmod(m, 60)
return "{}{:02d}:{:02d}".format(str(h) + ":" if h else "", m, s)
return f"{str(h) + ':' if h else ''}{m:02d}:{s:02d}"
def set_player_area_size(self, widget):
w, h = self._app.app_window.get_size()
@@ -310,6 +310,7 @@ class PlayerBox(Gtk.Box):
if self._playback_window:
self._playback_window.show()
self._playback_window.set_title(self.get_playback_title())
else:
self._playback_window = Gtk.Window(title=self.get_playback_title(),
window_position=Gtk.WindowPosition.CENTER,
@@ -331,10 +332,13 @@ class PlayerBox(Gtk.Box):
self._playback_window.show()
def get_playback_title(self):
path, column = self._fav_view.get_cursor()
if path:
return "DemonEditor [{}]".format(self._app.fav_view.get_model()[path][:][Column.FAV_SERVICE])
return "DemonEditor [Playback]"
if self._app.page is not Page.RECORDINGS:
path, column = self._fav_view.get_cursor()
if path:
return f"DemonEditor [{self._app.fav_view.get_model()[path][:][Column.FAV_SERVICE]}]"
else:
return f"DemonEditor [{get_message('Recordings')}]"
return f"DemonEditor [{get_message('Playback')}]"
def on_play_stream(self):
path, column = self._fav_view.get_cursor()
@@ -396,11 +400,13 @@ class PlayerBox(Gtk.Box):
else:
self._current_mrl = url
@run_idle
def on_played(self, player, duration):
GLib.idle_add(self._fav_view.set_sensitive, True)
self._fav_view.set_sensitive(True)
if not IS_DARWIN:
self.on_duration_changed(duration)
@run_idle
def on_error(self, player, msg):
self._app.show_error_message(msg)
self._fav_view.set_sensitive(True)

View File

@@ -166,7 +166,7 @@ Author: Dmitriy Yefremov
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_edit" object="satellite_view" swapped="no"/>
<accelerator key="e" signal="activate" modifiers="GDK_CONTROL_MASK"/>
<accelerator key="e" signal="activate" modifiers="Primary"/>
</object>
</child>
<child>
@@ -220,7 +220,7 @@ Author: Dmitriy Yefremov
<property name="use_underline">True</property>
<property name="use_stock">True</property>
<signal name="activate" handler="on_edit" object="transponder_view" swapped="no"/>
<accelerator key="e" signal="activate" modifiers="GDK_CONTROL_MASK"/>
<accelerator key="e" signal="activate" modifiers="Primary"/>
</object>
</child>
<child>
@@ -1482,7 +1482,7 @@ Author: Dmitriy Yefremov
<property name="image">sat_update_cancel_image</property>
<property name="always_show_image">True</property>
<signal name="clicked" handler="on_cancel_receive" swapped="no"/>
<accelerator key="z" signal="clicked" modifiers="GDK_CONTROL_MASK"/>
<accelerator key="z" signal="clicked" modifiers="Primary"/>
</object>
<packing>
<property name="expand">False</property>
@@ -1518,7 +1518,7 @@ Author: Dmitriy Yefremov
<property name="icon_size">1</property>
</object>
</child>
<accelerator key="f" signal="clicked" modifiers="GDK_SHIFT_MASK | GDK_CONTROL_MASK"/>
<accelerator key="f" signal="clicked" modifiers="GDK_SHIFT_MASK | Primary"/>
</object>
<packing>
<property name="expand">False</property>
@@ -1542,7 +1542,7 @@ Author: Dmitriy Yefremov
<property name="icon_size">1</property>
</object>
</child>
<accelerator key="f" signal="clicked" modifiers="GDK_CONTROL_MASK"/>
<accelerator key="f" signal="clicked" modifiers="Primary"/>
</object>
<packing>
<property name="expand">False</property>

View File

@@ -275,6 +275,38 @@ Author: Dmitriy Yefremov
<child type="titlebar">
<placeholder/>
</child>
<child type="action">
<object class="GtkButton" id="cancel_button">
<property name="label" translatable="yes">Cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
<signal name="clicked" handler="on_cancel" swapped="no"/>
</object>
</child>
<child type="action">
<object class="GtkButton" id="apply_button">
<property name="label" translatable="yes">Apply</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Save current service</property>
<property name="valign">center</property>
<signal name="clicked" handler="on_save" swapped="no"/>
<accelerator key="Return" signal="activate"/>
</object>
</child>
<child type="action">
<object class="GtkButton" id="create_button">
<property name="label" translatable="yes">Create</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Create and save as new service</property>
<property name="valign">center</property>
<signal name="clicked" handler="on_create_new" swapped="no"/>
</object>
</child>
<child internal-child="vbox">
<object class="GtkBox" id="dialog_vbox">
<property name="can_focus">False</property>
@@ -287,53 +319,6 @@ Author: Dmitriy Yefremov
<property name="can_focus">False</property>
<property name="valign">center</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="cancel_button">
<property name="label" translatable="yes">Cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
<signal name="clicked" handler="on_cancel" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="apply_button">
<property name="label" translatable="yes">Apply</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Save current service</property>
<property name="valign">center</property>
<signal name="clicked" handler="on_save" swapped="no"/>
<accelerator key="Return" signal="activate"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="create_button">
<property name="label" translatable="yes">Create</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Create and save as new service</property>
<property name="valign">center</property>
<signal name="clicked" handler="on_create_new" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
@@ -1644,6 +1629,9 @@ Author: Dmitriy Yefremov
</child>
</object>
</child>
<action-widgets>
<action-widget response="-6">cancel_button</action-widget>
</action-widgets>
</object>
<object class="GtkListStore" id="transponder_services_liststore">
<columns>
@@ -1676,6 +1664,24 @@ Author: Dmitriy Yefremov
<child>
<placeholder/>
</child>
<child type="action">
<object class="GtkButton" id="tr_services_no_button">
<property name="label" translatable="yes">Cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
</object>
</child>
<child type="action">
<object class="GtkButton" id="tr_services_ok_button">
<property name="label" translatable="yes">OK</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
</object>
</child>
<child internal-child="vbox">
<object class="GtkBox" id="tr_services_dialog_vbox">
<property name="can_focus">False</property>
@@ -1685,34 +1691,6 @@ Author: Dmitriy Yefremov
<object class="GtkButtonBox">
<property name="can_focus">False</property>
<property name="valign">center</property>
<child>
<object class="GtkButton" id="tr_services_no_button">
<property name="label" translatable="yes">Cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="tr_services_ok_button">
<property name="label" translatable="yes">OK</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="valign">center</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>

File diff suppressed because it is too large Load Diff

View File

@@ -34,7 +34,7 @@ from app.connections import test_telnet, test_ftp, TestException, test_http, Htt
from app.settings import SettingsType, Settings, PlayStreamsMode, IS_LINUX, SEP, IS_WIN
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
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, FavClickMode, DEFAULT_ICON, APP_FONT, IS_GNOME_SESSION
def show_settings_dialog(transient, options):
@@ -50,7 +50,6 @@ class SettingsDialog:
"on_settings_type_changed": self.on_settings_type_changed,
"on_reset": self.on_reset,
"on_response": self.on_response,
"apply_settings": self.apply_settings,
"on_connection_test": self.on_connection_test,
"on_info_bar_close": self.on_info_bar_close,
"on_set_color_switch": self.on_set_color_switch,
@@ -86,11 +85,12 @@ class SettingsDialog:
"on_icon_theme_add": self.on_icon_theme_add,
"on_icon_theme_remove": self.on_icon_theme_remove}
# Settings
# Settings.
self._ext_settings = settings
self._settings = Settings(settings.settings)
self._profiles = self._settings.profiles
self._s_type = self._settings.setting_type
self._updated = False
builder = get_builder(UI_RESOURCES_PATH + "settings_dialog.glade", handlers)
@@ -135,7 +135,7 @@ class SettingsDialog:
self._neutrino_radio_button = builder.get_object("neutrino_radio_button")
self._support_ver5_switch = builder.get_object("support_ver5_switch")
self._force_bq_name_switch = builder.get_object("force_bq_name_switch")
# Streaming
# Streaming.
self._apply_presets_button = builder.get_object("apply_presets_button")
self._transcoding_switch = builder.get_object("transcoding_switch")
self._edit_preset_switch = builder.get_object("edit_preset_switch")
@@ -192,7 +192,6 @@ class SettingsDialog:
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("enable_http_box"), "sensitive")
self._enigma_radio_button.bind_property("active", builder.get_object("enable_experimental_box"), "sensitive")
self._enigma_radio_button.bind_property("active", builder.get_object("program_frame"), "sensitive")
self._enigma_radio_button.bind_property("active", builder.get_object("experimental_box"), "sensitive")
@@ -200,6 +199,9 @@ class SettingsDialog:
self._profile_view = builder.get_object("profile_tree_view")
self._profile_add_button = builder.get_object("profile_add_button")
self._profile_remove_button = builder.get_object("profile_remove_button")
# Network.
# Separated due to a bug with response (presumably in the builder) in ubuntu 18.04 and derivatives.
builder.get_object("network_settings_frame").add(builder.get_object("network_box"))
# Style.
self._style_provider = Gtk.CssProvider()
self._style_provider.load_from_path(UI_RESOURCES_PATH + "style.css")
@@ -208,6 +210,16 @@ class SettingsDialog:
for el in self._digit_elems:
el.get_style_context().add_provider_for_screen(Gdk.Screen.get_default(), self._style_provider,
Gtk.STYLE_PROVIDER_PRIORITY_USER)
if IS_GNOME_SESSION:
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.set_custom_title(switcher)
self._dialog.set_titlebar(header_bar)
self.init_ui_elements()
self.init_profiles()
@@ -233,8 +245,7 @@ class SettingsDialog:
self._neutrino_radio_button.set_active(self._s_type is SettingsType.NEUTRINO_MP)
self.update_picon_paths()
self.update_title()
http_active = self._support_http_api_switch.get_active()
self._click_mode_zap_button.set_sensitive(is_enigma_profile and http_active)
self._click_mode_zap_button.set_sensitive(self._support_http_api_switch.get_active())
self._lang_combo_box.set_active_id(self._ext_settings.language)
self.on_info_bar_close() if is_enigma_profile else self.show_info_message(
"The Neutrino has only experimental support. Not all features are supported!", Gtk.MessageType.WARNING)
@@ -267,14 +278,15 @@ class SettingsDialog:
self._picons_paths_box.set_active(0)
def show(self):
self._dialog.run()
return self._dialog.run()
def is_updated(self):
return self._updated
def on_response(self, dialog, resp):
if resp == Gtk.ResponseType.OK and not self.apply_settings():
return
self._dialog.destroy()
return resp
if resp == Gtk.ResponseType.ACCEPT:
self._updated = self.on_save_settings()
dialog.destroy()
def on_field_icon_press(self, entry, icon, event_button):
update_entry_data(entry, self._dialog, self._settings)
@@ -324,12 +336,12 @@ class SettingsDialog:
self._picons_size_button.set_active_id(str(self._settings.list_picon_size))
self._tooltip_logo_size_button.set_active_id(str(self._settings.tooltip_logo_size))
self._list_font_button.set_font(self._settings.list_font)
self._support_http_api_switch.set_active(self._settings.http_api_support)
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._force_bq_name_switch.set_active(self._settings.force_bq_names)
self._support_http_api_switch.set_active(self._settings.http_api_support)
self._enable_yt_dl_switch.set_active(self._settings.enable_yt_dl)
self._enable_update_yt_dl_switch.set_active(self._settings.enable_yt_dl_update)
self._enable_send_to_switch.set_active(self._settings.enable_send_to)
@@ -366,9 +378,9 @@ class SettingsDialog:
self._settings.satellites_xml_path = self._satellites_xml_field.get_text()
self._settings.picons_path = self._picons_paths_box.get_active_id()
def apply_settings(self, item=None):
def on_save_settings(self, item=None):
if show_dialog(DialogType.QUESTION, self._dialog) != Gtk.ResponseType.OK:
return
return False
self.on_apply_profile_settings()
self._ext_settings.profiles = self._settings.profiles
@@ -391,6 +403,7 @@ class SettingsDialog:
self._ext_settings.list_picon_size = int(self._picons_size_button.get_active_id())
self._ext_settings.tooltip_logo_size = int(self._tooltip_logo_size_button.get_active_id())
self._ext_settings.list_font = self._list_font_button.get_font()
self._ext_settings.http_api_support = self._support_http_api_switch.get_active()
if not IS_LINUX:
self._ext_settings.dark_mode = self._dark_mode_switch.get_active()
@@ -406,13 +419,13 @@ class SettingsDialog:
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.force_bq_names = self._force_bq_name_switch.get_active()
self._ext_settings.http_api_support = self._support_http_api_switch.get_active()
self._ext_settings.enable_yt_dl = self._enable_yt_dl_switch.get_active()
self._ext_settings.enable_yt_dl_update = self._enable_update_yt_dl_switch.get_active()
self._ext_settings.enable_send_to = self._enable_send_to_switch.get_active()
self._ext_settings.default_profile = list(filter(lambda r: r[1], self._profile_view.get_model()))[0][0]
self._ext_settings.save()
return True
@run_task
@@ -594,7 +607,7 @@ class SettingsDialog:
self._ext_settings.picons_paths = tuple(r[0] for r in model)
def on_remove_picon_path(self, button):
msg = f"{get_message('This may change the settings of other profiles!')}\n\n\t\t{'Are you sure?'}"
msg = f"{get_message('This may change the settings of other profiles!')}\n\n\t\t{get_message('Are you sure?')}"
if show_dialog(DialogType.QUESTION, self._dialog, msg) != Gtk.ResponseType.OK:
return
@@ -790,15 +803,16 @@ class SettingsDialog:
@run_task
def unpack_theme(self, src, dst, button):
try:
os.makedirs(os.path.dirname(dst), exist_ok=True)
from shutil import unpack_archive
import subprocess
log("Unpacking '{}' started...".format(src))
p = subprocess.Popen(["tar", "-xvf", src, "-C", dst],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
p.communicate()
log(f"Unpacking '{src}' started...")
os.makedirs(os.path.dirname(dst), exist_ok=True)
unpack_archive(src, dst)
log("Unpacking end.")
except (ValueError, OSError) as e:
msg = f"Unpacking error: {e}"
log(msg)
self.show_info_message(msg, Gtk.MessageType.ERROR)
finally:
self.update_theme_button(button, dst)

View File

@@ -1,3 +1,31 @@
# -*- coding: utf-8 -*-
#
# The MIT License (MIT)
#
# Copyright (c) 2018-2021 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
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# Author: Dmitriy Yefremov
#
import locale
import os
from enum import Enum, IntEnum
@@ -7,7 +35,7 @@ import gi
gi.require_version("Gtk", "3.0")
gi.require_version("Gdk", "3.0")
from gi.repository import Gtk, Gdk
from gi.repository import Gtk, Gdk, GLib
from app.settings import Settings, SettingsException, IS_DARWIN, GTK_PATH, IS_LINUX
@@ -78,16 +106,22 @@ else:
theme = Gtk.IconTheme.get_default()
theme.append_search_path(UI_RESOURCES_PATH + "icons")
_IMAGE_MISSING = theme.load_icon("image-missing", 16, 0) if theme.lookup_icon("image-missing", 16, 0) else None
CODED_ICON = theme.load_icon("emblem-readonly", 16, 0) if theme.lookup_icon(
"emblem-readonly", 16, 0) else _IMAGE_MISSING
LOCKED_ICON = theme.load_icon("changes-prevent-symbolic", 16, 0) if theme.lookup_icon(
"system-lock-screen", 16, 0) else _IMAGE_MISSING
HIDE_ICON = theme.load_icon("go-jump", 16, 0) if theme.lookup_icon("go-jump", 16, 0) else _IMAGE_MISSING
TV_ICON = theme.load_icon("tv-symbolic", 16, 0) if theme.lookup_icon("tv-symbolic", 16, 0) else _IMAGE_MISSING
IPTV_ICON = theme.load_icon("emblem-shared", 16, 0) if theme.lookup_icon("emblem-shared", 16, 0) else None
EPG_ICON = theme.load_icon("gtk-index", 16, 0) if theme.lookup_icon("gtk-index", 16, 0) else None
DEFAULT_ICON = theme.load_icon("emblem-default", 16, 0) if theme.lookup_icon("emblem-default", 16, 0) else None
def get_icon(name, size, default=None):
try:
return theme.load_icon(name, size, 0) if theme.lookup_icon(name, size, 0) else default
except GLib.Error:
return default
_IMAGE_MISSING = get_icon("image-missing", 16)
CODED_ICON = get_icon("emblem-readonly", 16, _IMAGE_MISSING)
LOCKED_ICON = get_icon("changes-prevent-symbolic", 16, _IMAGE_MISSING)
HIDE_ICON = get_icon("go-jump", 16, _IMAGE_MISSING)
TV_ICON = get_icon("tv-symbolic", 16, _IMAGE_MISSING)
IPTV_ICON = get_icon("emblem-shared", 16, _IMAGE_MISSING)
EPG_ICON = get_icon("gtk-index", 16, _IMAGE_MISSING)
DEFAULT_ICON = get_icon("emblem-default", 16, _IMAGE_MISSING)
@lru_cache(maxsize=1)
@@ -263,10 +297,12 @@ if IS_LINUX:
LEFT = 113
RIGHT = 114
F2 = 68
F5 = 71
F7 = 73
SPACE = 65
DELETE = 119
BACK_SPACE = 22
RETURN = 36
CTRL_L = 37
CTRL_R = 105
# Laptop codes
@@ -301,10 +337,12 @@ elif IS_DARWIN:
LEFT = 123
RIGHT = 123
F2 = 120
F5 = 96
F7 = 98
SPACE = 49
DELETE = 51
BACK_SPACE = 76
RETURN = 36
CTRL_L = 55
CTRL_R = 55
# Laptop codes.
@@ -337,10 +375,12 @@ else:
LEFT = 37
RIGHT = 39
F2 = 113
F5 = 116
F7 = 118
SPACE = 32
DELETE = 46
BACK_SPACE = 8
RETURN = 13
CTRL_L = 17
CTRL_R = 163
# Laptop codes.

View File

@@ -1,5 +1,5 @@
#!/bin/bash
VER="2.0.0_Alpha2"
VER="2.0.1_Beta"
B_PATH="dist/DemonEditor"
DEB_PATH="$B_PATH/usr/share/demoneditor"

View File

@@ -1,5 +1,5 @@
Package: demon-editor
Version: 2.0.0-Alpha2
Version: 2.0.1-Beta
Section: utils
Priority: optional
Architecture: all

View File

@@ -69,7 +69,7 @@ app = BUNDLE(coll,
'CFBundleGetInfoString': "Enigma2 channel and satellite editor",
'LSApplicationCategoryType': 'public.app-category.utilities',
'LSMinimumSystemVersion': '10.13',
'CFBundleShortVersionString': f"2.0.0.{BUILD_DATE} Alpha2",
'CFBundleShortVersionString': f"2.0.1.{BUILD_DATE} Beta",
'NSHumanReadableCopyright': u"Copyright © 2021, Dmitriy Yefremov",
'NSRequiresAquaSystemAppearance': 'false'
})

View File

@@ -1258,3 +1258,45 @@ msgstr "Дадаць піконы"
msgid "Logs"
msgstr "Логі"
msgid "Title"
msgstr "Назва"
msgid "Time"
msgstr "Час"
msgid "Length"
msgstr "Працягласць"
msgid "Additional source"
msgstr "Дадатковая крыніца"
msgid "Automatically set the name selected in the favorites list."
msgstr "Аўтаматычная ўсталёўка імя са спіса абранага."
msgid "Playback"
msgstr "Прайграванне"
msgid "Audio"
msgstr "Аўдыё"
msgid "Audio Track"
msgstr "Аўдыёдарожка"
msgid "Subtitle"
msgstr "Субтытры"
msgid "Subtitle Track"
msgstr "Дарожка субтытраў"
msgid "Aspect ratio"
msgstr "Стасунак бакоў"
msgid "This may change the settings of other profiles!"
msgstr "Гэта можа змяніць налады іншых профіляў!"
msgid "Drag the services to the desired picon or picon to the list of selected services."
msgstr "Перацягніце сэрвісы на патрэбны пікон ці пікон на спіс абраных сэрвісаў."
msgid "Sets the profile folder as default to store picons, backups, etc."
msgstr "Усталёўвае тэчку профілю па змаўчанні для захоўвання піконаў, рэзервовых копій і т. п."

View File

@@ -1272,3 +1272,45 @@ msgstr "Picons hinzufügen"
msgid "Logs"
msgstr "Logs"
msgid "Title"
msgstr "Titel"
msgid "Time"
msgstr "Zeit"
msgid "Length"
msgstr "Dauer"
msgid "Additional source"
msgstr "Zusätzliche Quelle"
msgid "Automatically set the name selected in the favorites list."
msgstr "Automatisch den in der Favoritenliste ausgewählten Namen einstellen."
msgid "Playback"
msgstr "Wiedergabe"
msgid "Audio"
msgstr ""
msgid "Audio Track"
msgstr "Audio"
msgid "Subtitle"
msgstr "Untertitel"
msgid "Subtitle Track"
msgstr "Untertitelspur"
msgid "Aspect ratio"
msgstr "Seitenverhältnis"
msgid "This may change the settings of other profiles!"
msgstr "Dadurch können sich die Einstellungen anderer Profile ändern!"
msgid "Drag the services to the desired picon or picon to the list of selected services."
msgstr "Ziehe die Dienste auf das gewünschte Picon oder Picon in die Liste der ausgewählten Dienste."
msgid "Sets the profile folder as default to store picons, backups, etc."
msgstr "Legt den Profilordner als Standardordner zum Speichern von Piconen, Backups usw. fest."

View File

@@ -1,30 +1,26 @@
# Copyright (C) 2018-2020 Dmitriy Yefremov
# Copyright (C) 2018-2019 Dmitriy Yefremov
# This file is distributed under the MIT license.
#
#
msgid ""
msgstr ""
"Last-Translator: wwns\n"
"Last-Translator: wwns <https://github.com/wwns>\n"
"Language: pl\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Project-Id-Version: \n"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
"Language-Team: \n"
"X-Generator: Poedit 3.0\n"
msgid "translator-credits"
msgstr "wwns"
# Main
msgid "File"
msgstr "Plik"
msgid "View"
msgstr "Widok"
msgid "Lock"
msgstr "Zablokuj"
msgid "Service"
msgstr "Serwis"
msgstr "Usługa"
msgid "Package"
msgstr "Pakiet"
@@ -48,7 +44,7 @@ msgid "System"
msgstr "System"
msgid "Pos"
msgstr "Pos"
msgstr "Poz"
msgid "Num"
msgstr "Num"
@@ -113,6 +109,9 @@ msgstr "Ustaw domyślną nazwę"
msgid "Insert marker"
msgstr "Wstaw znacznik"
msgid "Insert space"
msgstr "Wstaw spację"
msgid "Locate in services"
msgstr "Znajdź w usługach"
@@ -179,6 +178,9 @@ msgstr "Zapisz"
msgid "Search"
msgstr "Szukaj"
msgid "Services"
msgstr "Kanały"
msgid "Services filter"
msgstr "Filtr kanałów"
@@ -206,8 +208,8 @@ msgstr "Aktualna ścieżka danych:"
msgid "Data:"
msgstr "Dane:"
msgid "Enigma2 channel and satellite list editor for GNU/Linux."
msgstr "Edytor kanałów Enigma2 i listy satelitów dla GNU/Linux."
msgid "Enigma2 channel and satellite list editor."
msgstr "Edytor kanałów i list satelitarnych Enigma2."
msgid "Host:"
msgstr "Host:"
@@ -222,7 +224,7 @@ msgid "Receive files from receiver"
msgstr "Pobieranie plików z odbiornika"
msgid "Receiver IP:"
msgstr "Odbiornik IP:"
msgstr "Adres IP odbiornika:"
msgid "Remove unused bouquets"
msgstr "Usuń nieużywany bouquet"
@@ -252,22 +254,7 @@ msgid "User bouquet files:"
msgstr "Pliki bukietu użytkownika:"
msgid "Extra:"
msgstr "Dodatkowe"
msgid "IPTV tools"
msgstr "Narzędzia IPTV"
msgid "Picons manager"
msgstr "Menedżer pikonów"
msgid "Hide/Skip"
msgstr "Ukryj/Pomiń"
msgid "Parent lock"
msgstr "Blokada rodzicielska"
msgid "There are unsaved changes.\n\n\t Save them now?"
msgstr "Istnieją niezapisane zmiany.\n\n\t Zapisać je teraz?"
msgstr "Dodatkowe:"
# Filter bar
msgid "Only free"
@@ -280,6 +267,9 @@ msgid "All types"
msgstr "Wszystkie typy"
# Streams player
msgid "Play"
msgstr "Odtwarzaj"
msgid "Stop playback"
msgstr "Zatrzymaj odtwarzanie"
@@ -311,8 +301,8 @@ msgstr "Format nazw pikon:"
msgid "Resize:"
msgstr "Zmień rozmiar:"
msgid "Current picons path:"
msgstr "Aktualna ścieżka pikon:"
msgid "Current picons path"
msgstr "Aktualna ścieżka pikon"
msgid "Receiver picons path:"
msgstr "Ścieżka pikon odbiornika:"
@@ -390,12 +380,6 @@ msgid "Remove selection"
msgstr "Usuń wybrane"
# Service details dialog
msgid "To the top"
msgstr "Przenieś na góre bukietu"
msgid "To the end"
msgstr "Przenieś na koniec bukietu"
msgid "Service data:"
msgstr "Dane usług:"
@@ -467,7 +451,7 @@ msgid "Preferences"
msgstr "Preferencje"
msgid "Profile:"
msgstr "Profil:"
msgstr "Profile:"
msgid "Timeout between commands in seconds"
msgstr "Limit czasu między poleceniami w sekundach"
@@ -481,6 +465,9 @@ msgstr "Login:"
msgid "Options"
msgstr "Opcje"
msgid "Rename"
msgstr "Zmień nazwę"
msgid "Password:"
msgstr "Hasło:"
@@ -497,13 +484,13 @@ msgid "Picons path:"
msgstr "Ścieżka pikon:"
msgid "Network settings:"
msgstr "Ustawienia sieci:"
msgstr "Ustawienia połaczenia:"
msgid "STB file paths:"
msgstr "Ścieżki do plików w STB:"
msgid "Local file paths:"
msgstr "Lokalne ścieżki plików:"
msgstr "Lokalne ścieżki do plików:"
# Dialogs messages
msgid "Error. No bouquet is selected!"
@@ -539,6 +526,9 @@ msgstr "Wybierz tylko jeden element!"
msgid "No png file is selected!"
msgstr "Nie wybrano pliku png!"
msgid "No profile selected!"
msgstr "Nie wybroano profilu !"
msgid "No reference is present!"
msgstr "Brak referencji!"
@@ -606,6 +596,15 @@ msgstr "Brak danych do zapisania!"
msgid "Network"
msgstr "Sieć"
msgid "Paths"
msgstr "Ścieżki"
msgid "Program"
msgstr "Program"
msgid "Backup:"
msgstr "Kopia:"
msgid "Backup"
msgstr "Kopia"
@@ -621,11 +620,26 @@ msgstr "Przywróć bukiety"
msgid "Restore all"
msgstr "Przywrócić wszystko"
msgid "Before saving"
msgstr "Przed zapisaniem"
msgid "Before downloading from the receiver"
msgstr "Przed pobraniem z odbiornika"
msgid "Set background color for the services"
msgstr "Ustaw kolor tła dla usług"
msgid "Marked as new:"
msgstr "Oznacz jako nowy:"
msgid "With an extra name in the bouquet:"
msgstr "Z dodatkową nazwą w bukiecie:"
msgid "Select"
msgstr "Wybierz"
msgid "About"
msgstr "Wersja"
msgstr "O programie"
msgid "Exit"
msgstr "Wyjście"
@@ -633,15 +647,6 @@ msgstr "Wyjście"
msgid "Tools"
msgstr "Narzędzia"
msgid "Cut"
msgstr "Wytnij"
msgid "Paste"
msgstr "Wklej"
msgid "Insert space"
msgstr "Wstaw spację"
# Import
msgid "Import"
msgstr "Importuj"
@@ -664,12 +669,27 @@ msgstr "Usuń wszystkie nieużywane"
msgid "Test"
msgstr "Test"
msgid "Details"
msgstr "Właściwości"
msgid "Test connection"
msgstr "Testuj połączenie"
msgid "Double click on the service in the bouquet list:"
msgstr "Kliknij dwukrotnie usługę na liście bukietów:"
msgid "Zap"
msgstr "Przełącz"
msgid "Play stream"
msgstr "Odtwórz strumień"
msgid "Disabled"
msgstr "Wyłączone"
msgid "Enable lamedb ver. 5 support"
msgstr "Włącz wsparcie dla lamedb w wer.5"
msgid "Enable HTTP API"
msgstr "Włącz API HTTP"
msgid "Switch(zap) the channel(Ctrl + Z)"
msgstr "Przełącz(zap) kanał(Ctrl + Z)"
@@ -770,11 +790,26 @@ msgstr "Import listy odtwarzania"
msgid "Getting link error:"
msgstr "Błąd pobierania łącza:"
msgid "Extra"
msgstr "Ekstra"
msgid "Apply profile settings"
msgstr "Zastosuj ustawienia profilu"
msgid "Settings type:"
msgstr "Ustawienia dla:"
msgid "Set default"
msgstr "Ustaw domyślnie"
msgstr "Uataw domyślnie"
msgid "Language:"
msgstr "Język:"
msgid "Load the last open configuration at program startup"
msgstr "Załaduj ostatnią otwartą konfigurację podczas uruchamiania programu"
msgid "Enable direct playback bar"
msgstr "Włącz pasek bezpośredniego odtwarzania"
msgid "Enables direct sending and playback of media links on the receiver"
msgstr "Umożliwia bezpośrednie wysyłanie i odtwarzanie łączy multimedialnych w odbiorniku"
@@ -782,23 +817,8 @@ msgstr "Umożliwia bezpośrednie wysyłanie i odtwarzanie łączy multimedialnyc
msgid "Watch the channel in the program"
msgstr "Obejrzyj kanał w programie"
msgid "Receiver info"
msgstr "Informacje o odbiorniku"
msgid "Operates in standby mode or current active transponder!"
msgstr "Działa w trybie gotowości lub aktualnie jest aktywny transponder!"
msgid "Download picons from the receiver"
msgstr "Pobierz pikony z odbiornika"
msgid "Remove picons from the receiver"
msgstr "Usuń pikony z odbiornika"
msgid "Use http to reload data in the receiver."
msgstr "Użyj http aby przeładować dane w odbiorniku."
msgid "Apply profile settings"
msgstr "Zastosuj ustawienia profilu"
msgid "Zap and Play"
msgstr "Przełącz i Odtwórz"
msgid "Drag or paste the link here"
msgstr "Przeciągnij lub wklej tutaj link"
@@ -809,34 +829,156 @@ msgstr "Usuń dodane linki z listy odtwarzania"
msgid "A bouquet with that name exists!"
msgstr "Istnieje bukiet o tej nazwie!"
msgid "Details"
msgstr "Właściwości"
msgid "Profile"
msgstr "Profil"
msgid "Reset"
msgstr "Reset profilu"
msgid "File"
msgstr "Plik"
msgid "Picons manager"
msgstr "Menedżer pikonów"
msgid "Explorer"
msgstr "Explorer"
msgid "Satellite url:"
msgstr "Satelitarny url:"
msgid "Cut"
msgstr "Wytnij"
msgid "Paste"
msgstr "Wklej"
msgid "To the top"
msgstr "Przenieś na góre bukietu"
msgid "To the end"
msgstr "Przenieś na koniec bukietu"
msgid "View"
msgstr "Widok"
msgid "Lock"
msgstr "Zablokuj"
msgid "Parent lock"
msgstr "Blokada rodzicielska"
msgid "Hide/Skip"
msgstr "Ukryj/Pomiń"
msgid "IPTV tools"
msgstr "Narzędzia IPTV"
msgid "Make profile folder as default for the additional data"
msgstr "Ustaw folder profilu jako domyślny dla dodatkowych danych"
msgid "Default data path:"
msgstr "Domyślna ścieżka danych:"
msgid "Streams record path:"
msgstr "Ścieżka zapisu nagrań:"
msgid "Record"
msgstr "Nagrania"
msgid "Record:"
msgstr "Nagrania:"
msgid "Record to disk:"
msgstr "Zapis na dysk:"
msgid "Streaming"
msgstr "Transmisja"
msgid "Activate transcoding"
msgstr "Aktywuj"
msgid "Presets:"
msgstr "Ustawienia transkodowania:"
msgid "Video options:"
msgstr "Opcje wideo:"
msgid "Audio options:"
msgstr "Opcje audio:"
msgid "Bitrate (kb/s):"
msgstr "Szybkość transmisji (kb/s):"
msgid "Codec:"
msgstr "Kodek:"
msgid "Width (px):"
msgstr "Szerokość (px):"
msgid "Height (px):"
msgstr "Wysokość (px):"
msgid "Channels:"
msgstr "Kanały:"
msgid "Remove all picons from the receiver"
msgstr "Usuń wszystkie pikony z odbiornika"
msgid "Sample rate (Hz):"
msgstr "Częstotliwość próbkowania (Hz):"
msgid "Download from the receiver"
msgstr "Pobierz z odbiornika"
msgid "Play streams mode:"
msgstr "Tryb odtwarzania strumieni:"
msgid "The Neutrino has only experimental support. Not all features are supported!"
msgstr "Neutrino ma jedynie wsparcie eksperymentalne. Nie wszystkie funkcje są obsługiwane!"
msgid "Built-in player"
msgstr "Wbudowany odtwarzacz"
msgid "In a separate window"
msgstr "W osobnym oknie"
msgid "Only get m3u file"
msgstr "Tylko pobierz plik m3u"
msgid "Save and restart the program to apply the settings."
msgstr "Zapisz i uruchom ponownie program, aby zastosować ustawienia."
msgid "Some images may have problems displaying the favorites list!"
msgstr "Niektóre obrazy mogą mieć problemy z wyświetlaniem listy ulubionych!"
# Appearance
msgid "Operates in standby mode or current active transponder!"
msgstr "Działa w trybie gotowości lub aktualnie jest aktywny transponder!"
msgid "No connection to the receiver!"
msgstr "Brak połączenia z odbiornikiem!"
msgid "Signal level"
msgstr "Poziom sygnału"
msgid "Receiver info"
msgstr "Informacje o odbiorniku"
msgid "A profile with that name exists!"
msgstr "Profil o tej nazwie już istnieje!"
msgid "Show short info as hints in the main services list"
msgstr "Pokaż krótkie informacje jako wskazówki na głównej liście usług"
msgid "Show detailed info as hints in the bouquet list"
msgstr "Pokaż szczegółowe informacje jako wskazówki na liście bukietów"
msgid "Enable alternate bouquet file naming"
msgstr "Włącz alternatywne nazewnictwo plików bukietów"
msgid "Allows you to name bouquet files using their names."
msgstr "Pozwala nazwać pliki bukietów przy użyciu ich nazw."
msgid "Appearance"
msgstr "Wygląd"
msgid "Enable Dark Mode"
msgstr "Włącz tryb ciemny"
msgid "Enable Themes support"
msgstr "Włącz obsługę motywów"
msgid "EXPERIMENTAL!"
msgstr "EKSPERYMENTALNE!"
msgid "Gtk3 Theme:"
msgstr "Gtk3 motyw:"
@@ -846,159 +988,346 @@ msgstr "Motyw ikon:"
msgid "Gtk3 Themes and Icons:"
msgstr "Gtk3 motywy i ikony:"
msgid "Save and restart the program to apply the settings."
msgstr "Zapisz i uruchom ponownie program, aby zastosować ustawienia."
msgid "Deleting data..."
msgstr "Usuwanie danych…"
# Extra
msgid "Extra"
msgstr "Ekstra"
msgid "Download from the receiver"
msgstr "Pobierz z odbiornika"
msgid "Enable alternate bouquet file naming"
msgstr "Włącz alternatywne nazewnictwo plików bukietów"
msgid "Remove all picons from the receiver"
msgstr "Usuń wszystkie pikony z odbiornika"
msgid "Allows you to name bouquet files using their names."
msgstr "Pozwala nazwać pliki bukietów przy użyciu ich nazw."
msgid "Enable HTTP API"
msgstr "Włącz API HTTP"
msgid "Double click on the service in the bouquet list:"
msgstr "Kliknij dwukrotnie usługę na liście bukietów:"
msgid "Zap"
msgstr "Przełącz"
msgid "Play"
msgstr "Odtwarzaj"
msgid "Zap and Play"
msgstr "Przełącz i Odtwórz"
msgid "Play stream"
msgstr "Odtwórz strumień"
msgid "Disabled"
msgstr "Wyłączone"
msgid "Enable experimental features"
msgstr "Włącz funkcje eksperymentalne"
msgid "Enable lamedb ver. 5 support"
msgstr "Włącz wsparcie dla lamedb w wer.5"
msgid "Service reference"
msgstr "Odniesienie do usługi"
msgid "Enable support for"
msgstr "Włącz obsługę"
msgid "Enables parsing links using youtube-dl to get direct links to media"
msgstr "Umożliwia analizowanie linków za pomocą youtube-dl, aby uzyskać bezpośrednie linki do multimediów"
msgid "Auto-check for updates"
msgstr "Automatyczne sprawdzanie aktualizacji"
msgid "Enable direct playback bar"
msgstr "Włącz pasek bezpośredniego odtwarzania"
msgid "Filter services"
msgstr "Filtruj usługi"
#Program
msgid "Program"
msgstr "Program"
msgid "Filter services in the main list."
msgstr "Filtruj usługi na głównej liście."
msgid "Language:"
msgstr "Język:"
msgid "Destination:"
msgstr "Miejsce docelowe:"
msgid "Load the last open configuration at program startup"
msgstr "Załaduj ostatnią otwartą konfigurację podczas uruchamiania programu"
msgid "EXPERIMENTAL!"
msgstr "EKSPERYMENTALNE!"
msgid "Show short info as hints in the main services list"
msgstr "Pokaż krótkie informacje jako wskazówki na głównej liście usług"
msgid "Sorting data..."
msgstr "Sortowanie danych…"
msgid "Show detailed info as hints in the bouquet list"
msgstr "Pokaż szczegółowe informacje jako wskazówki na liście bukietów"
msgid ""
"There are unsaved changes.\n"
"\n"
"\t Save them now?"
msgstr ""
"Istnieją niezapisane zmiany.\n"
"\n"
"\t Zapisać je teraz?"
msgid "Set background color for the services"
msgstr "Ustaw kolor tła dla usług"
msgid ""
"Are you sure you want to change the order\n"
"\t of services in this bouquet?"
msgstr ""
"Czy na pewno chcesz zmienić kolejność?\n"
"\t usług w tym bukiecie?"
msgid "Marked as new:"
msgstr "Oznacz jako nowy:"
msgid "Remove from the receiver"
msgstr "Usuń z odbiornika"
msgid "With an extra name in the bouquet:"
msgstr "Z dodatkową nazwą w bukiecie:"
msgid "Screenshot"
msgstr "Zrzut ekranu"
msgid "Backup:"
msgstr "Kopia:"
msgid "Video"
msgstr "Opcje wideo"
msgid "Before saving"
msgstr "Przed zapisaniem"
msgid "The Neutrino has only experimental support. Not all features are supported!"
msgstr "Neutrino ma jedynie wsparcie eksperymentalne. Nie wszystkie funkcje są obsługiwane!"
msgid "Before downloading from the receiver"
msgstr "Przed pobraniem z odbiornika"
msgid "Enable experimental features"
msgstr "Włącz funkcje eksperymentalne"
#Streaming
msgid "Streaming"
msgstr "Transmisja"
msgid "Can't Playback!"
msgstr "Nie można odtworzyć!"
msgid "Record to disk:"
msgstr "Nagrywanie na dysk:"
msgid "Enable Dark Mode"
msgstr "Włącz tryb ciemny"
msgid "Activate transcoding"
msgstr "Aktywuj transkodowanie"
msgid "Extract..."
msgstr "Rozpakuj…"
msgid "Presets:"
msgstr "Ustawienia wstępne:"
msgid "Unsupported format!"
msgstr "Format nieobsługiwany!"
msgid "720p TV/device"
msgstr "Dla urządzeń z obsługą rozdzielczości 720p"
msgid "Combine with the current data?"
msgstr "Połączyć z aktualnymi danymi?"
msgid "1080p TV/device"
msgstr "Dla urządzeń z obsługą rozdzielczości 1080p"
msgid "Importing data done!"
msgstr "Importowanie danych zakończone!"
msgid "Video options:"
msgstr "Opcje wideo:"
msgid "Current service"
msgstr "Bieżąca usługa"
msgid "Width (px):"
msgstr "Szerokość (px):"
msgid "Open folder"
msgstr "Otwórz folder"
msgid "Height (px):"
msgstr "Wysokość (px):"
msgid "Open archive"
msgstr "Otwórz archiwum"
msgid "Codec:"
msgstr "Kodek:"
msgid "Import from Web"
msgstr "Importuj z sieci"
msgid "Audio options:"
msgstr "Opcje audio:"
msgid "Control"
msgstr "Kontrola"
msgid "Services"
msgstr "Kanały"
msgid "Timers"
msgstr "Timery"
msgid "Sample rate (Hz):"
msgstr "Częstotliwość próbkowania (Hz):"
msgid "Timer"
msgstr "Timer"
msgid "Play streams mode:"
msgstr "Odtwarzaj tryb strumieni:"
msgid "Add timer"
msgstr "Dodaj timer"
msgid "Bulit-in player"
msgstr "Wbudowany odtwarzacz"
msgid "Hr."
msgstr "Hr."
msgid "VLC media player"
msgstr "Odtwarzacz multimedialny VLC"
msgid "Min."
msgstr "Min."
msgid "Only get m3u file"
msgstr "Tylko pobierz plik m3u"
msgid "Power"
msgstr "Włącz"
# Paths
msgid "Paths"
msgstr "Ścieżki"
msgid "Standby"
msgstr "Czuwanie"
msgid "Make profile folder as default for the additional data"
msgstr "Ustaw folder profilu jako domyślny dla dodatkowych danych"
msgid "Wake Up"
msgstr "Wybudź"
msgid "Reboot"
msgstr "Restart"
msgid "Restart GUI"
msgstr "Restart Interfejsu Graficznego"
msgid "Shutdown"
msgstr "Wyłącz"
msgid "Shut down"
msgstr "Wyłacz"
msgid "Do Nothing"
msgstr "Nie rób nic"
msgid "Auto"
msgstr "Auto"
msgid "Grab screenshot"
msgstr "Zrób zrzut ekranu"
msgid "Enabled:"
msgstr "Włączony:"
msgid "Name:"
msgstr "Nazwa:"
msgid "Description:"
msgstr "Opis:"
msgid "Service:"
msgstr "Usługa:"
msgid "Service reference:"
msgstr "Odniesienie do usługi:"
msgid "Event ID:"
msgstr "Identyfikator wydarzenia:"
msgid "Begins:"
msgstr "Początek:"
msgid "Ends:"
msgstr "Koniec:"
msgid "Repeated:"
msgstr "Powtórz:"
msgid "Action:"
msgstr "Akcja:"
msgid "After event:"
msgstr "Po wydarzeniu:"
msgid "Location:"
msgstr "Lokalizacja:"
msgid "Mo"
msgstr "Po"
msgid "Tu"
msgstr "Wt"
msgid "We"
msgstr "Śr"
msgid "Th"
msgstr "Cz"
msgid "Fr"
msgstr "Pt"
msgid "Sa"
msgstr "So"
msgid "Su"
msgstr "Ni"
msgid "Set"
msgstr "Ustaw"
msgid "Services update"
msgstr "Aktualizacja usług"
msgid "Create folder"
msgstr "Utwórz folder"
msgid "FTP client"
msgstr "Klient-FTP"
msgid "The file size is too large!"
msgstr "Rozmiar pliku jest za duży!"
msgid "Connect"
msgstr "Połącz"
msgid "Disconnect"
msgstr "Rozłącz"
msgid "Size"
msgstr "Rozmiar"
msgid "Date"
msgstr "Data"
msgid "Toggle display position"
msgstr "Przełącz pozycję wyświetlania"
msgid "Alternatives"
msgstr "Alternatywy"
msgid "Add alternatives"
msgstr "Dodaj alternatywy"
msgid "DreamOS only!"
msgstr "Tylko DreamOS!"
msgid "A similar service is already in this list!"
msgstr "Podobna usługa jest już na tej liście!"
msgid ""
"Play mode has been changed!\n"
"Restart the program to apply the settings."
msgstr ""
"Tryb odtwarzania został zmieniony!\n"
"Uruchom ponownie, aby zastosować ustawienia."
msgid "Set values for TID, NID and Namespace for correct naming of the picons!"
msgstr "Ustaw wartości dla TID, NID i Namespace dla poprawnego nazewnictwa pikonów!"
msgid "Streams detected:"
msgstr "Wykryte strumienie:"
msgid "Download picons"
msgstr "Pobierz pikony"
msgid "Errors:"
msgstr "Błędy:"
msgid "Use to play streams:"
msgstr "Użyj do odtwarzania strumieni:"
msgid "Font in the lists:"
msgstr "Czcionka na listach:"
msgid "Picons size in the lists:"
msgstr "Rozmiar pikonów na listach:"
msgid "Logo size in tooltips:"
msgstr "Rozmiar logo w podpowiedziach:"
msgid "Save as"
msgstr "Zapisz jako"
msgid "Mark duplicates"
msgstr "Zaznacz duplikaty"
msgid "Load only for selected bouquet"
msgstr "Załaduj tylko dla wybranego bukietu"
msgid "The task is canceled!"
msgstr "Zadanie anulowane!"
msgid "Data loading in progress!"
msgstr "Trwa ładowanie danych!"
msgid "Recordings"
msgstr "Nagrania"
msgid "Help"
msgstr "Pomoc"
msgid "HTTP API is not activated. Check your settings!"
msgstr "Interfejs API HTTP nie jest aktywowany. Sprawdź swoje ustawienia!"
msgid "Add picons"
msgstr "Dodaj pikony"
msgid "Logs"
msgstr "Logi"
msgid "Title"
msgstr "Tytuł"
msgid "Time"
msgstr "Czas"
msgid "Length"
msgstr "Długość"
msgid "Additional source"
msgstr "Dodatkowe źródło"
msgid "Automatically set the name selected in the favorites list."
msgstr "Automatycznie ustaw nazwę wybraną na liście ulubionych."
msgid "Playback"
msgstr "Odtwarzanie"
msgid "Audio"
msgstr "Audio"
msgid "Audio Track"
msgstr "Ścieżka Audio"
msgid "Subtitle"
msgstr "Napisy"
msgid "Subtitle Track"
msgstr "Ścieżka napisów"
msgid "Aspect ratio"
msgstr "Współczynnik proporcji"
msgid "This may change the settings of other profiles!"
msgstr "Może to zmienić ustawienia innych profili!"
msgid "Drag the services to the desired picon or picon to the list of selected services."
msgstr "Przeciągnij usługi na żądaną ikonę lub na listę wybranych usług."
msgid "Sets the profile folder as default to store picons, backups, etc."
msgstr "Ustawia folder profilu jako domyślny do przechowywania pikonów, kopii zapasowych itp."
msgid "Default data path:"
msgstr "Domyślna ścieżka danych:"
msgid "Record:"
msgstr "Nagrania:"
msgid "Streams record path:"
msgstr "Ścieżka zapisu nagrań:"

View File

@@ -1255,3 +1255,45 @@ msgstr "Добавить пиконы"
msgid "Logs"
msgstr "Журнал"
msgid "Title"
msgstr "Название"
msgid "Time"
msgstr "Время"
msgid "Length"
msgstr "Длительность"
msgid "Additional source"
msgstr "Дополнительный источник"
msgid "Automatically set the name selected in the favorites list."
msgstr "Автоматическая установка имени из списка избранного."
msgid "Playback"
msgstr "Воспроизведение"
msgid "Audio"
msgstr "Аудио"
msgid "Audio Track"
msgstr "Аудиодорожка"
msgid "Subtitle"
msgstr "Субтитры"
msgid "Subtitle Track"
msgstr "Дорожка субтитров"
msgid "Aspect ratio"
msgstr "Соотношение сторон"
msgid "This may change the settings of other profiles!"
msgstr "Это может изменить настройки других профилей!"
msgid "Drag the services to the desired picon or picon to the list of selected services."
msgstr "Перетащите сервисы на нужный пикон или пикон на список выбранных сервисов."
msgid "Sets the profile folder as default to store picons, backups, etc."
msgstr "Устанавливает папку профиля по умолчанию для хранения пиконов, резервных копий и т. п."

View File

@@ -3,13 +3,13 @@ msgstr ""
"Project-Id-Version: DemonEditor\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-04-16 15:59+0300\n"
"PO-Revision-Date: 2021-06-13 14:54+0300\n"
"PO-Revision-Date: 2021-11-11 23:49+0300\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Last-Translator: audi06_19 <info@dreamosat-forum.com>\n"
"Last-Translator: audi06_19 <audi06_19@hotmail.com>\n"
"Language-Team: \n"
"X-Generator: Poedit 2.4.1\n"
"X-Generator: Poedit 3.0\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Language: tr\n"
@@ -206,8 +206,8 @@ msgstr "Mevcut veri yolu:"
msgid "Data:"
msgstr "Veri:"
msgid "Enigma2 channel and satellite list editor for GNU/Linux."
msgstr "GNU/Linux için Enigma2 kanalı ve uydu listesi editörü."
msgid "Enigma2 channel and satellite list editor."
msgstr "Enigma2 kanal ve uydu listesi düzenleyicisi."
msgid "Host:"
msgstr "Ana bilgisayar:"
@@ -299,8 +299,8 @@ msgstr "Piconların adı biçimi:"
msgid "Resize:"
msgstr "Yeniden boyutlandır:"
msgid "Current picons path:"
msgstr "Geçerli picon yolları:"
msgid "Current picons path"
msgstr "Mevcut piconların yolu"
msgid "Receiver picons path:"
msgstr "Alıcı picon yolu:"
@@ -1269,3 +1269,63 @@ msgstr "Yalnızca seçilen buket için yükle"
msgid "The task is canceled!"
msgstr "Görev iptal edildi!"
msgid "Data loading in progress!"
msgstr "Veri yükleme devam ediyor!"
msgid "Recordings"
msgstr "Kayıtlar"
msgid "Help"
msgstr "Yardım"
msgid "HTTP API is not activated. Check your settings!"
msgstr "HTTP API etkinleştirilmedi. Ayarlarınızı kontrol edin!"
msgid "Add picons"
msgstr "Piconlar ekle"
msgid "Logs"
msgstr "Loglar"
msgid "Title"
msgstr "Başlık"
msgid "Time"
msgstr "Zaman"
msgid "Length"
msgstr "Uzunluk"
msgid "Additional source"
msgstr "Ek kaynak"
msgid "Automatically set the name selected in the favorites list."
msgstr "Favoriler listesinde seçilen adı otomatik olarak ayarlayın."
msgid "Playback"
msgstr "Oynatım"
msgid "Audio"
msgstr "Ses"
msgid "Audio Track"
msgstr "Ses parçası"
msgid "Subtitle"
msgstr "Altyazı"
msgid "Subtitle Track"
msgstr "Altyazı Parçası"
msgid "Aspect ratio"
msgstr "En boy oranı"
msgid "This may change the settings of other profiles!"
msgstr "Bu, diğer profillerin ayarlarını değiştirebilir!"
msgid "Drag the services to the desired picon or picon to the list of selected services."
msgstr "Hizmetleri istediğiniz simgeye veya simgeyi seçili hizmetler listesine sürükleyin."
msgid "Sets the profile folder as default to store picons, backups, etc."
msgstr "Picon'ları, yedekleri vb. depolamak için profil klasörünü varsayılan olarak ayarlar."