Compare commits

...

42 Commits

Author SHA1 Message Date
DYefremov
1780fbadbd fixed signal update for control tab 2021-11-22 19:41:30 +03:00
DYefremov
4fe4e92442 fixed some folders display for the recording tab 2021-11-22 16:33:24 +03:00
DYefremov
bfad5cf9ac bump version 2021-11-22 14:19:52 +03:00
DYefremov
5d285f61c0 fixed a typo in the Italian translation 2021-11-18 19:52:40 +03:00
DYefremov
f61d9a1f61 fix tid and nid order for KingOfSat web source 2021-11-18 11:31:01 +03:00
DYefremov
8d115677d1 minor fix for picon downloader 2021-11-17 22:42:09 +03:00
DYefremov
f7c6cd6908 preventing gen bouquets for an empty config 2021-11-17 13:05:15 +03:00
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
54 changed files with 2317 additions and 1654 deletions

View File

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

View File

@@ -1,33 +1,32 @@
# <img src="app/ui/icons/hicolor/96x96/apps/demon-editor.png" width="32" /> DemonEditor # <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) [![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. ### 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).
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).
## Main features of the program ## Main features of the program
* Editing bouquets, channels, satellites. * 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. * 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. * 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. * 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. * 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/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/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/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. * Extended support of IPTV.
* Import to bouquet(Neutrino WEBTV) from m3u. * Import to bouquet(Neutrino WEBTV) from m3u.
* Export of bouquets with IPTV services in m3u. * Export of bouquets with IPTV services in m3u.
* Assignment of EPG from DVB or XML for IPTV services (only Enigma2, experimental). * Assignment of EPG from DVB or XML for IPTV services (Enigma2 only).
* Preview (playback) of IPTV or other streams directly from the bouquet list. [<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)
[<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) * Playback of IPTV or other streams directly from the bouquet list.
* Control panel with the ability to view EPG and manage timers (via HTTP API, experimental). [<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)
[<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) * 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). * 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 #### Keyboard shortcuts
* **Ctrl + X** - only in bouquet list. * **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 + D** - load data from receiver.
* **Ctrl + U/B** - upload data/bouquets to receiver. * **Ctrl + U/B** - upload data/bouquets to receiver.
* **Ctrl + I** - extra info, details. * **Ctrl + I** - extra info, details.
* **Ctrl + F** - show/hide search bar. * **Ctrl + F** - show search bar.
* **Ctrl + Shift + F** - show/hide filter 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! 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. 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. 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 * ### 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. **This program can be run on macOS.**
**The functionality and performance of this version may be different from the Linux version!** 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 ## 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. 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!** 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 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. (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. 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: #### Command line arguments:
* **-l** - write logs to file. * **-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 collections import namedtuple
from enum import Enum from enum import Enum
from app.commons import log
Service = namedtuple("Service", ["flags_cas", "transponder_type", "coded", "service", "locked", "hide", "package", Service = namedtuple("Service", ["flags_cas", "transponder_type", "coded", "service", "locked", "hide", "package",
"service_type", "picon", "picon_id", "ssid", "freq", "rate", "pol", "fec", "service_type", "picon", "picon_id", "ssid", "freq", "rate", "pol", "fec",
"system", "pos", "data_id", "fav_id", "transponder"]) "system", "pos", "data_id", "fav_id", "transponder"])
@@ -206,14 +236,15 @@ def get_value_by_name(en, name):
def is_transponder_valid(tr: Transponder): def is_transponder_valid(tr: Transponder):
""" Checks transponder validity """ """ Checks transponder validity. """
try: try:
int(tr.frequency) int(tr.frequency)
int(tr.symbol_rate) int(tr.symbol_rate)
tr.pls_mode is None or int(tr.pls_mode) tr.pls_mode is None or int(tr.pls_mode)
tr.pls_code is None or int(tr.pls_code) tr.pls_code is None or int(tr.pls_code)
tr.is_id is None or int(tr.is_id) 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 return False
if tr.polarization not in POLARIZATION.values(): if tr.polarization not in POLARIZATION.values():

View File

@@ -151,18 +151,18 @@ class LameDbReader:
is_v3 = False is_v3 = False
if len(tid) < 4: if len(tid) < 4:
is_v3 = True is_v3 = True
tid = "{:0>4}".format(tid) tid = f"{tid:0>4}"
data[2] = tid data[2] = tid
if len(nid) < 4: if len(nid) < 4:
is_v3 = True is_v3 = True
nid = "{:0>4}".format(nid) nid = f"{nid:0>4}"
data[3] = nid data[3] = nid
if is_v3: if is_v3:
data[0] = "{:0>4}".format(data[0]) data[0] = f"{data[0]:0>4}"
data_id = _SEP.join(data) data_id = _SEP.join(data)
srv_type = int(data[4]) 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) transponder = transponders.get(transponder_id, None)
tid = tid.lstrip(sp).upper() tid = tid.lstrip(sp).upper()
@@ -170,9 +170,9 @@ class LameDbReader:
ssid = str(data[0]).lstrip(sp).upper() ssid = str(data[0]).lstrip(sp).upper()
onid = str(data[1]).lstrip(sp).upper() onid = str(data[1]).lstrip(sp).upper()
# For comparison in bouquets. Needed in upper case!!! # For comparison in bouquets. Needed in upper case!!!
fav_id = "{}:{}:{}:{}".format(ssid, tid, nid, onid) fav_id = f"{ssid}:{tid}:{nid}:{onid}"
picon_id = "1_0_{:X}_{}_{}_{}_{}_0_0_0.png".format(srv_type, ssid, tid, nid, onid) picon_id = f"1_0_{srv_type:X}_{ssid}_{tid}_{nid}_{onid}_0_0_0.png"
s_id = "1:0:{:X}:{}:{}:{}:{}:0:0:0:".format(srv_type, ssid, tid, nid, onid) s_id = f"1:0:{srv_type:X}:{ssid}:{tid}:{nid}:{onid}:0:0:0:"
all_flags = srv[2].split(",") all_flags = srv[2].split(",")
coded = CODED_ICON if list(filter(lambda x: x.startswith("C:"), all_flags)) else None 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" system = "DVB-S2" if len(tr) > 7 else "DVB-S"
pos = tr[4] pos = tr[4]
if tr_type is TrType.Terrestrial: 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" pos = "T"
fec = T_FEC.get(tr[3], None) fec = T_FEC.get(tr[3], None)
elif tr_type is TrType.Cable: elif tr_type is TrType.Cable:
@@ -217,13 +217,13 @@ class LameDbReader:
# Formatting displayed values. # Formatting displayed values.
try: try:
freq = "{}".format(int(freq) // 1000) freq = f"{int(freq) // 1000}"
rate = "{}".format(int(rate) // 1000) rate = f"{int(rate) // 1000}"
if tr_type is TrType.Satellite: if tr_type is TrType.Satellite:
pos = int(pos) 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: 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, 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) picon_id, data[0], freq, rate, pol, fec, system, pos, data_id, fav_id, transponder)

View File

@@ -57,7 +57,7 @@ class PiconsCzDownloader:
_PERM_URL = "https://picon.cz/download/7337" _PERM_URL = "https://picon.cz/download/7337"
_BASE_URL = "https://picon.cz/download/" _BASE_URL = "https://picon.cz/download/"
_BASE_LOGO_URL = "https://picon.cz/picon/0/" _BASE_LOGO_URL = "https://picon.cz/picon/0/"
_HEADER = {"User-Agent": "DemonEditor/2.0.0", "Referer": ""} _HEADER = {"User-Agent": "DemonEditor/2.0.2", "Referer": ""}
_LINK_PATTERN = re.compile(r"((.*)-\d+x\d+)-(.*)_by_chocholousek.7z$") _LINK_PATTERN = re.compile(r"((.*)-\d+x\d+)-(.*)_by_chocholousek.7z$")
_FILE_PATTERN = re.compile(b"\\s+(1_.*\\.png).*") _FILE_PATTERN = re.compile(b"\\s+(1_.*\\.png).*")
@@ -130,7 +130,7 @@ class PiconsCzDownloader:
# TODO: think about https://github.com/miurahr/py7zr # TODO: think about https://github.com/miurahr/py7zr
exe = "7z" exe = "7z"
if IS_DARWIN and GTK_PATH: if IS_DARWIN and GTK_PATH:
exe = "./7z" exe = "./7zr"
if IS_LINUX and not os.path.isfile(f"/usr/bin/{exe}"): if IS_LINUX and not os.path.isfile(f"/usr/bin/{exe}"):
raise PiconsError("7-zip [7z] archiver not found!") raise PiconsError("7-zip [7z] archiver not found!")
@@ -219,7 +219,8 @@ class PiconsCzDownloader:
"picontransparentdark": "td220", "picontransparentdark": "td220",
"piconoled": "o96", "piconoled": "o96",
"piconblack80": "b50", "piconblack80": "b50",
"piconblack3d": "b50" "piconblack3d": "b50",
"piconwin11": "win11220"
} }
def get_name_map(self): def get_name_map(self):

View File

@@ -539,7 +539,7 @@ class ServicesParser(HTMLParser):
tr = tr[0] tr = tr[0]
s_pos, freq, pol, sys, mod, sr_fec = tr[0].text, tr[2].text, tr[3].text, tr[6].text, tr[7].text, tr[8].text s_pos, freq, pol, sys, mod, sr_fec = tr[0].text, tr[2].text, tr[3].text, tr[6].text, tr[7].text, tr[8].text
tid, nid = tr[10].text, tr[11].text nid, tid = tr[10].text, tr[11].text
pos = sat_position pos = sat_position
if not sat_position: if not sat_position:

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_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_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?.*") _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", "DNT": "1",
"Accept-Encoding": "gzip, deflate"} "Accept-Encoding": "gzip, deflate"}
@@ -109,6 +109,8 @@ class YouTube:
if self._settings.enable_yt_dl and url: if self._settings.enable_yt_dl and url:
if not self._yt_dl: if not self._yt_dl:
self._yt_dl = YouTubeDL.get_instance(self._settings, self._callback) 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._yt_dl.get_yt_link(url, skip_errors)
return self.get_yt_link_by_id(video_id) return self.get_yt_link_by_id(video_id)
@@ -130,7 +132,7 @@ class YouTube:
try: try:
resp = json.loads(player_resp) resp = json.loads(player_resp)
except JSONDecodeError as e: except JSONDecodeError as e:
log("{}: Parsing player response error: {}".format(__class__.__name__, e)) log(f"{__class__.__name__}: Parsing player response error: {e}")
else: else:
det = resp.get("videoDetails", None) det = resp.get("videoDetails", None)
title = det.get("title", None) if det else 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). """ """ Returns tuple from the playlist header and list of tuples (title, video id). """
if self._settings.enable_yt_dl and url: if self._settings.enable_yt_dl and url:
try: try:
if not self._yt_dl:
raise YouTubeException("youtube-dl is not initialized!")
self._yt_dl.update_options({"noplaylist": False, "extract_flat": True}) self._yt_dl.update_options({"noplaylist": False, "extract_flat": True})
info = self._yt_dl.get_info(url, skip_errors=False) info = self._yt_dl.get_info(url, skip_errors=False)
if "url" in info: if "url" in info:
info = self._yt_dl.get_info(info.get("url"), skip_errors=False) 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", [])] return info.get("title", ""), [(e.get("title", ""), e.get("id", "")) for e in info.get("entries", [])]
finally: finally:
# Restoring default options # 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) return PlayListParser.get_yt_playlist(list_id)
@@ -218,7 +225,7 @@ class PlayListParser(HTMLParser):
self._is_script = False self._is_script = False
def error(self, message): def error(self, message):
log("{} Parsing error: {}".format(__class__.__name__, message)) log(f"{__class__.__name__} Parsing error: {message}")
@property @property
def header(self): def header(self):
@@ -259,7 +266,7 @@ class YouTubeDL:
"cookiefile": "cookies.txt"} # File name where cookies should be read from and dumped to. "cookiefile": "cookies.txt"} # File name where cookies should be read from and dumped to.
def __init__(self, settings, callback): 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._update = settings.enable_yt_dl_update
self._supported = {"22", "18"} self._supported = {"22", "18"}
self._dl = None self._dl = None
@@ -276,7 +283,7 @@ class YouTubeDL:
return cls._DL_INSTANCE return cls._DL_INSTANCE
def init(self): 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() self.get_latest_release()
if self._path not in sys.path: if self._path not in sys.path:
@@ -293,12 +300,17 @@ class YouTubeDL:
except ImportError as e: except ImportError as e:
log("YouTubeDLHelper error: {}".format(str(e))) log("YouTubeDLHelper error: {}".format(str(e)))
else: 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 self._update:
if hasattr(youtube_dl.version, "__version__"): if hasattr(youtube_dl.version, "__version__"):
l_ver = self.get_last_release_id() l_ver = self.get_last_release_id()
cur_ver = youtube_dl.version.__version__ cur_ver = youtube_dl.version.__version__
if l_ver and youtube_dl.version.__version__ < l_ver: 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) show_notification(msg)
log(msg) log(msg)
self._callback(msg, False) self._callback(msg, False)
@@ -318,7 +330,7 @@ class YouTubeDL:
with urlopen(url, timeout=10) as resp: with urlopen(url, timeout=10) as resp:
return json.loads(resp.read().decode("utf-8")).get("tag_name", "0") return json.loads(resp.read().decode("utf-8")).get("tag_name", "0")
except URLError as e: 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): def get_latest_release(self):
try: try:
@@ -329,6 +341,9 @@ class YouTubeDL:
r = json.loads(resp.read().decode("utf-8")) r = json.loads(resp.read().decode("utf-8"))
zip_url = r.get("zipball_url", None) zip_url = r.get("zipball_url", None)
if zip_url: if zip_url:
if os.path.isdir(self._path):
shutil.rmtree(self._path)
zip_file = self._path + "yt.zip" zip_file = self._path + "yt.zip"
os.makedirs(os.path.dirname(self._path), exist_ok=True) os.makedirs(os.path.dirname(self._path), exist_ok=True)
f_name, headers = urlretrieve(zip_url, filename=zip_file) f_name, headers = urlretrieve(zip_url, filename=zip_file)
@@ -336,25 +351,22 @@ class YouTubeDL:
import zipfile import zipfile
with zipfile.ZipFile(f_name) as arch: 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(): for info in arch.infolist():
pref, sep, f = info.filename.partition("/youtube_dl/") pref, sep, f = info.filename.partition("/youtube_dl/")
if sep: if sep:
arch.extract(info.filename) 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) shutil.rmtree(pref)
msg = "Getting the last youtube-dl release is done!" msg = "Getting the last youtube-dl release is done!"
show_notification(msg) show_notification(msg)
log(msg) log(msg)
self._callback(msg, False) self._callback(msg, False)
return True
if os.path.isfile(zip_file):
os.remove(zip_file)
return True
except URLError as e: except URLError as e:
log("YouTubeDLHelper error: {}".format(e)) log(f"YouTubeDLHelper error: {e}")
raise YouTubeException(e) raise YouTubeException(e)
finally: finally:
self._is_update_process = False self._is_update_process = False
@@ -377,10 +389,10 @@ class YouTubeDL:
try: try:
return self._dl.extract_info(url, download=False) return self._dl.extract_info(url, download=False)
except URLError as e: except URLError as e:
log(str(e)) log(f"YouTubeDLHelper error [get info]: {e}")
raise YouTubeException(e) raise YouTubeException(e)
except self._DownloadError as e: except self._DownloadError as e:
log(str(e)) log(f"YouTubeDLHelper error [get info]: {e}")
if not skip_errors: if not skip_errors:
raise YouTubeException(e) raise YouTubeException(e)

View File

@@ -38,7 +38,7 @@ from app.commons import run_idle
from app.settings import SettingsType, SEP from app.settings import SettingsType, SEP
from app.ui.dialogs import show_dialog, DialogType, get_builder from app.ui.dialogs import show_dialog, DialogType, get_builder
from app.ui.main_helper import append_text_to_tview 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): class RestoreType(Enum):
@@ -74,6 +74,24 @@ class BackupDialog:
self._info_check_button = builder.get_object("info_check_button") self._info_check_button = builder.get_object("info_check_button")
self._info_bar = builder.get_object("info_bar") self._info_bar = builder.get_object("info_bar")
self._message_label = builder.get_object("message_label") 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 # Setting the last size of the dialog window if it was saved
window_size = self._settings.get("backup_tool_window_size") window_size = self._settings.get("backup_tool_window_size")
if window_size: if window_size:

View File

@@ -124,7 +124,6 @@ Author: Dmitriy Yefremov
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<property name="spacing">5</property>
<child> <child>
<object class="GtkBox" id="header_bar"> <object class="GtkBox" id="header_bar">
<property name="visible">True</property> <property name="visible">True</property>
@@ -232,6 +231,7 @@ Author: Dmitriy Yefremov
<object class="GtkPaned" id="main_paned"> <object class="GtkPaned" id="main_paned">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="margin_top">5</property>
<property name="margin_left">5</property> <property name="margin_left">5</property>
<property name="margin_right">5</property> <property name="margin_right">5</property>
<property name="margin_bottom">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="margin_bottom">5</property>
<property name="row_spacing">5</property> <property name="row_spacing">5</property>
<property name="column_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> <child>
<object class="GtkLabel" id="timer_description_label"> <object class="GtkLabel" id="timer_description_label">
<property name="visible">True</property> <property name="visible">True</property>
@@ -634,17 +622,6 @@ Author: Dmitriy Yefremov
<property name="top_attach">1</property> <property name="top_attach">1</property>
</packing> </packing>
</child> </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> <child>
<object class="GtkEntry" id="timer_desc_entry"> <object class="GtkEntry" id="timer_desc_entry">
<property name="visible">True</property> <property name="visible">True</property>
@@ -690,6 +667,115 @@ Author: Dmitriy Yefremov
<property name="top_attach">0</property> <property name="top_attach">0</property>
</packing> </packing>
</child> </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> <child>
<object class="GtkLabel" id="timer_begins_label"> <object class="GtkLabel" id="timer_begins_label">
<property name="visible">True</property> <property name="visible">True</property>
@@ -699,7 +785,7 @@ Author: Dmitriy Yefremov
</object> </object>
<packing> <packing>
<property name="left_attach">0</property> <property name="left_attach">0</property>
<property name="top_attach">4</property> <property name="top_attach">3</property>
</packing> </packing>
</child> </child>
<child> <child>
@@ -724,7 +810,7 @@ Author: Dmitriy Yefremov
</object> </object>
<packing> <packing>
<property name="left_attach">1</property> <property name="left_attach">1</property>
<property name="top_attach">4</property> <property name="top_attach">3</property>
</packing> </packing>
</child> </child>
<child> <child>
@@ -736,7 +822,7 @@ Author: Dmitriy Yefremov
</object> </object>
<packing> <packing>
<property name="left_attach">0</property> <property name="left_attach">0</property>
<property name="top_attach">5</property> <property name="top_attach">4</property>
</packing> </packing>
</child> </child>
<child> <child>
@@ -761,7 +847,7 @@ Author: Dmitriy Yefremov
</object> </object>
<packing> <packing>
<property name="left_attach">1</property> <property name="left_attach">1</property>
<property name="top_attach">5</property> <property name="top_attach">4</property>
</packing> </packing>
</child> </child>
<child> <child>
@@ -773,7 +859,7 @@ Author: Dmitriy Yefremov
</object> </object>
<packing> <packing>
<property name="left_attach">0</property> <property name="left_attach">0</property>
<property name="top_attach">6</property> <property name="top_attach">5</property>
</packing> </packing>
</child> </child>
<child> <child>
@@ -954,7 +1040,7 @@ Author: Dmitriy Yefremov
</object> </object>
<packing> <packing>
<property name="left_attach">1</property> <property name="left_attach">1</property>
<property name="top_attach">6</property> <property name="top_attach">5</property>
</packing> </packing>
</child> </child>
<child> <child>
@@ -966,7 +1052,7 @@ Author: Dmitriy Yefremov
</object> </object>
<packing> <packing>
<property name="left_attach">0</property> <property name="left_attach">0</property>
<property name="top_attach">7</property> <property name="top_attach">6</property>
</packing> </packing>
</child> </child>
<child> <child>
@@ -981,7 +1067,7 @@ Author: Dmitriy Yefremov
</object> </object>
<packing> <packing>
<property name="left_attach">1</property> <property name="left_attach">1</property>
<property name="top_attach">7</property> <property name="top_attach">6</property>
</packing> </packing>
</child> </child>
<child> <child>
@@ -993,7 +1079,7 @@ Author: Dmitriy Yefremov
</object> </object>
<packing> <packing>
<property name="left_attach">0</property> <property name="left_attach">0</property>
<property name="top_attach">8</property> <property name="top_attach">7</property>
</packing> </packing>
</child> </child>
<child> <child>
@@ -1010,115 +1096,30 @@ Author: Dmitriy Yefremov
</object> </object>
<packing> <packing>
<property name="left_attach">1</property> <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> <property name="top_attach">8</property>
</packing> </packing>
</child> </child>
<child> <child>
<object class="GtkLabel" id="timer_service_ref_label"> <object class="GtkEntry" id="timer_service_entry">
<property name="visible">True</property> <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="can_focus">True</property>
<property name="primary_icon_name">document-edit-symbolic</property> <property name="primary_icon_name">document-edit-symbolic</property>
<property name="placeholder_text" translatable="yes">Default</property>
</object> </object>
<packing> <packing>
<property name="left_attach">1</property> <property name="left_attach">1</property>
<property name="top_attach">12</property> <property name="top_attach">8</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>
</packing> </packing>
</child> </child>
<child> <child>

View File

@@ -36,7 +36,7 @@ from urllib.parse import quote
from gi.repository import GLib from gi.repository import GLib
from .dialogs import get_builder, show_dialog, DialogType, get_message 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 ..commons import run_task, run_with_delay, log, run_idle
from ..connections import HttpAPI, UtfFTP from ..connections import HttpAPI, UtfFTP
from ..eparser.ecommons import BqServiceType from ..eparser.ecommons import BqServiceType
@@ -159,7 +159,7 @@ class TimerTool(Gtk.Box):
class TimerDialog(Gtk.Dialog): class TimerDialog(Gtk.Dialog):
def __init__(self, parent, action=None, timer_data=None, *args, **kwargs): 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._action = action or TimerTool.TimerAction.ADD
self._timer_data = timer_data or {} self._timer_data = timer_data or {}
@@ -213,7 +213,7 @@ class TimerTool(Gtk.Box):
self._timer_desc_entry.drag_dest_unset() self._timer_desc_entry.drag_dest_unset()
self._timer_service_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) self.get_content_area().pack_start(builder.get_object("timer_dialog_frame"), True, True, 5)
if self._action is TimerTool.TimerAction.ADD: if self._action is TimerTool.TimerAction.ADD:
@@ -716,10 +716,14 @@ class RecordingsTool(Gtk.Box):
for f in files: for f in files:
f_data = f.split() f_data = f.split()
if len(f_data) < 9:
log(f"{__class__.__name__}. Folder data parsing error. [{f}]")
continue
f_type = f_data[0][0] f_type = f_data[0][0]
if f_type == "d": if f_type == "d":
model.append((self._icon, f_data[-1], self._ftp.pwd())) model.append((self._icon, " ".join(f_data[8:]), self._ftp.pwd()))
def on_path_activated(self, view, path, column): def on_path_activated(self, view, path, column):
row = view.get_model()[path][:] row = view.get_model()[path][:]

View File

@@ -40,7 +40,7 @@ Author: Dmitriy Yefremov
<property name="icon_name">system-help</property> <property name="icon_name">system-help</property>
<property name="type_hint">normal</property> <property name="type_hint">normal</property>
<property name="program_name">DemonEditor</property> <property name="program_name">DemonEditor</property>
<property name="version">2.0.0 Alpha2</property> <property name="version">2.0.2 Beta</property>
<property name="copyright">2018-2021 Dmitriy Yefremov <property name="copyright">2018-2021 Dmitriy Yefremov
</property> </property>
<property name="comments" translatable="yes">Enigma2 channel and satellite list editor.</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="type_hint">utility</property>
<property name="skip_taskbar_hint">True</property> <property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property> <property name="skip_pager_hint">True</property>
<child type="titlebar"> <child type="action">
<placeholder/> <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>
<child internal-child="vbox"> <child internal-child="vbox">
<object class="GtkBox"> <object class="GtkBox">
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="margin_left">5</property> <property name="margin_left">5</property>
<property name="margin_right">5</property> <property name="margin_right">5</property>
<property name="margin_top">4</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area"> <child internal-child="action_area">
<object class="GtkButtonBox"> <object class="GtkButtonBox">
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="valign">center</property> <property name="valign">center</property>
<property name="layout_style">end</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> </object>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
@@ -147,10 +132,10 @@ Author: Dmitriy Yefremov
<object class="GtkEntry" id="input_entry"> <object class="GtkEntry" id="input_entry">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="margin_left">2</property> <property name="margin_left">5</property>
<property name="margin_right">2</property> <property name="margin_right">5</property>
<property name="margin_top">2</property> <property name="margin_top">5</property>
<property name="margin_bottom">2</property> <property name="margin_bottom">5</property>
<property name="primary_icon_name">document-edit-symbolic</property> <property name="primary_icon_name">document-edit-symbolic</property>
<property name="primary_icon_activatable">False</property> <property name="primary_icon_activatable">False</property>
<property name="secondary_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"> <object class="GtkFrame" id="main_settings_box_frame">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="margin_left">10</property> <property name="margin_left">5</property>
<property name="margin_right">10</property> <property name="margin_right">5</property>
<property name="margin_top">5</property> <property name="margin_top">5</property>
<property name="label_xalign">0.019999999552965164</property> <property name="label_xalign">0.019999999552965164</property>
<property name="shadow_type">in</property> <property name="shadow_type">in</property>
@@ -239,12 +239,13 @@ Author: Dmitriy Yefremov
<property name="margin_top">10</property> <property name="margin_top">10</property>
<property name="margin_bottom">10</property> <property name="margin_bottom">10</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<property name="spacing">10</property>
<child> <child>
<object class="GtkGrid" id="main_settings_bo"> <object class="GtkGrid" id="main_settings_bo">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="row_spacing">2</property> <property name="row_spacing">5</property>
<property name="column_spacing">2</property> <property name="column_spacing">10</property>
<property name="column_homogeneous">True</property> <property name="column_homogeneous">True</property>
<child> <child>
<object class="GtkLabel" id="ip_label"> <object class="GtkLabel" id="ip_label">
@@ -310,9 +311,8 @@ Author: Dmitriy Yefremov
<object class="GtkBox" id="extra_box"> <object class="GtkBox" id="extra_box">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="margin_left">5</property> <property name="margin_left">10</property>
<property name="margin_right">5</property> <property name="margin_right">10</property>
<property name="margin_top">5</property>
<child> <child>
<object class="GtkCheckButton" id="remove_unused_check_button"> <object class="GtkCheckButton" id="remove_unused_check_button">
<property name="label" translatable="yes">Remove unused bouquets</property> <property name="label" translatable="yes">Remove unused bouquets</property>
@@ -384,7 +384,7 @@ Author: Dmitriy Yefremov
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="fill">True</property> <property name="fill">True</property>
<property name="position">2</property> <property name="position">1</property>
</packing> </packing>
</child> </child>
<child> <child>
@@ -438,54 +438,85 @@ Author: Dmitriy Yefremov
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="fill">False</property> <property name="fill">False</property>
<property name="position">6</property> <property name="position">2</property>
</packing> </packing>
</child> </child>
<child> <child>
<object class="GtkExpander" id="expander"> <object class="GtkFrame" id="log_bar_frame">
<property name="visible">True</property> <property name="can_focus">False</property>
<property name="can_focus">True</property> <property name="margin_left">5</property>
<property name="margin_left">1</property> <property name="margin_right">5</property>
<property name="margin_right">1</property> <property name="margin_bottom">5</property>
<property name="margin_bottom">1</property> <property name="label_xalign">0</property>
<property name="resize_toplevel">True</property> <property name="shadow_type">in</property>
<child> <child>
<object class="GtkScrolledWindow" id="scrolled_window"> <object class="GtkInfoBar" id="log_bar">
<property name="height_request">120</property> <property name="can_focus">False</property>
<property name="visible">True</property> <property name="baseline_position">bottom</property>
<property name="can_focus">True</property> <property name="message_type">other</property>
<property name="shadow_type">in</property> <property name="show_close_button">True</property>
<child> <child internal-child="action_area">
<object class="GtkTextView" id="text_view"> <object class="GtkButtonBox" id="log_bar_button_box">
<property name="visible">True</property> <property name="can_focus">False</property>
<property name="can_focus">True</property> <property name="layout_style">end</property>
<property name="editable">False</property>
<property name="left_margin">5</property>
<property name="right_margin">5</property>
</object> </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> </child>
</object> </object>
</child> </child>
<child type="label"> <child type="label_item">
<object class="GtkLabel" id="expander_label"> <placeholder/>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Extra:</property>
</object>
</child> </child>
</object> </object>
<packing> <packing>
<property name="expand">False</property> <property name="expand">True</property>
<property name="fill">True</property> <property name="fill">True</property>
<property name="position">7</property> <property name="position">3</property>
</packing> </packing>
</child> </child>
<child> <child>
<object class="GtkInfoBar" id="info_bar"> <object class="GtkInfoBar" id="info_bar">
<property name="can_focus">False</property> <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> <property name="show_close_button">True</property>
<signal name="response" handler="on_info_bar_close" swapped="no"/> <signal name="response" handler="on_info_bar_close" swapped="no"/>
<child internal-child="action_area"> <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.settings import SettingsType
from app.ui.backup import backup_data, restore_data from app.ui.backup import backup_data, restore_data
from app.ui.main_helper import append_text_to_tview 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 .dialogs import show_dialog, DialogType, get_message, get_builder
from .uicommons import Gtk, UI_RESOURCES_PATH 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 = builder.get_object("download_dialog_window")
self._dialog_window.set_transient_for(transient) 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._host_entry = builder.get_object("host_entry")
self._data_path_entry = builder.get_object("data_path_entry") self._data_path_entry = builder.get_object("data_path_entry")
self._remove_unused_check_button = builder.get_object("remove_unused_check_button") 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._use_http_switch = builder.get_object("use_http_switch")
self._http_radio_button = builder.get_object("http_radio_button") self._http_radio_button = builder.get_object("http_radio_button")
self._profile_combo_box = builder.get_object("profile_combo_box") 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() self.init_settings()
@@ -120,8 +123,9 @@ class DownloadDialog:
self._dialog_window.destroy() self._dialog_window.destroy()
def on_settings(self, item): def on_settings(self, item):
response = show_settings_dialog(self._dialog_window, self._settings) dialog = SettingsDialog(self._dialog_window, self._settings)
if response != Gtk.ResponseType.CANCEL: dialog.show()
if dialog.is_updated():
self._s_type = self._settings.setting_type self._s_type = self._settings.setting_type
self.update_profiles() self.update_profiles()
gen = self._update_settings_callback() gen = self._update_settings_callback()
@@ -147,7 +151,7 @@ class DownloadDialog:
@run_task @run_task
def download(self, download, d_type): def download(self, download, d_type):
""" Download/upload data from/to receiver """ """ 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() self.clear_output()
backup, backup_src, data_path = self._settings.backup_before_downloading, None, None backup, backup_src, data_path = self._settings.backup_before_downloading, None, None

View File

@@ -158,6 +158,8 @@ Author: Dmitriy Yefremov
<columns> <columns>
<!-- column-name service --> <!-- column-name service -->
<column type="gchararray"/> <column type="gchararray"/>
<!-- column-name pos -->
<column type="gchararray"/>
<!-- column-name service_id --> <!-- column-name service_id -->
<column type="gchararray"/> <column type="gchararray"/>
</columns> </columns>
@@ -671,7 +673,7 @@ Author: Dmitriy Yefremov
<property name="image">filter_image</property> <property name="image">filter_image</property>
<property name="always_show_image">True</property> <property name="always_show_image">True</property>
<signal name="toggled" handler="on_filter_toggled" swapped="no"/> <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> </object>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
@@ -851,7 +853,6 @@ Author: Dmitriy Yefremov
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="margin_left">5</property> <property name="margin_left">5</property>
<property name="margin_right">5</property> <property name="margin_right">5</property>
<property name="margin_bottom">5</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="GtkScrolledWindow"> <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="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-begin" handler="on_drag_begin" swapped="no"/>
<signal name="drag-data-get" handler="on_drag_data_get" 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"> <child internal-child="selection">
<object class="GtkTreeSelection"/> <object class="GtkTreeSelection"/>
</child> </child>
<child> <child>
<object class="GtkTreeViewColumn" id="service_column"> <object class="GtkTreeViewColumn" id="service_column">
<property name="resizable">True</property> <property name="resizable">True</property>
<property name="sizing">autosize</property>
<property name="min_width">50</property> <property name="min_width">50</property>
<property name="title" translatable="yes">Service</property> <property name="title" translatable="yes">Service</property>
<property name="expand">True</property> <property name="expand">True</property>
<property name="alignment">0.5</property> <property name="alignment">0.5</property>
<property name="sort_column_id">0</property> <property name="sort_column_id">0</property>
<child> <child>
<object class="GtkCellRendererText" id="source_service_cellrenderertext"> <object class="GtkCellRendererText" id="source_service_renderertext">
<property name="xpad">5</property> <property name="xpad">5</property>
<property name="ellipsize">end</property>
</object> </object>
<attributes> <attributes>
<attribute name="text">0</attribute> <attribute name="text">0</attribute>
@@ -892,15 +893,14 @@ Author: Dmitriy Yefremov
</object> </object>
</child> </child>
<child> <child>
<object class="GtkTreeViewColumn" id="ref_column"> <object class="GtkTreeViewColumn" id="pos_column">
<property name="resizable">True</property> <property name="min_width">70</property>
<property name="sizing">autosize</property> <property name="title" translatable="yes">Pos</property>
<property name="min_width">50</property>
<property name="title" translatable="yes">Reference</property>
<property name="expand">True</property>
<property name="alignment">0.5</property> <property name="alignment">0.5</property>
<property name="sort_column_id">1</property>
<child> <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> <property name="xalign">0.50999999046325684</property>
</object> </object>
<attributes> <attributes>
@@ -909,6 +909,23 @@ Author: Dmitriy Yefremov
</child> </child>
</object> </object>
</child> </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> </object>
</child> </child>
</object> </object>
@@ -1039,7 +1056,6 @@ Author: Dmitriy Yefremov
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="margin_left">5</property> <property name="margin_left">5</property>
<property name="margin_right">5</property> <property name="margin_right">5</property>
<property name="margin_bottom">5</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="GtkScrolledWindow" id="fav_scrolled_window"> <object class="GtkScrolledWindow" id="fav_scrolled_window">
@@ -1056,7 +1072,7 @@ Author: Dmitriy Yefremov
<property name="tooltip_column">9</property> <property name="tooltip_column">9</property>
<signal name="button-press-event" handler="on_bouquet_popup_menu" object="bouquet_popup_menu" swapped="no"/> <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="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"> <child internal-child="selection">
<object class="GtkTreeSelection"> <object class="GtkTreeSelection">
<property name="mode">multiple</property> <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.tools.epg import EPG, ChannelsParser
from app.ui.dialogs import get_message, show_dialog, DialogType, get_builder from app.ui.dialogs import get_message, show_dialog, DialogType, get_builder
from .main_helper import on_popup_menu, update_entry_data 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): class RefsSource(Enum):
@@ -80,7 +80,7 @@ class EpgDialog:
"on_enable_filtering_switch": self.on_enable_filtering_switch, "on_enable_filtering_switch": self.on_enable_filtering_switch,
"on_update_on_start_switch": self.on_update_on_start_switch, "on_update_on_start_switch": self.on_update_on_start_switch,
"on_field_icon_press": self.on_field_icon_press, "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._services = {}
self._ex_services = services self._ex_services = services
@@ -93,7 +93,6 @@ class EpgDialog:
self._use_web_source = False self._use_web_source = False
self._update_epg_data_on_start = False self._update_epg_data_on_start = False
self._refs_source = RefsSource.SERVICES self._refs_source = RefsSource.SERVICES
self._show_tooltips = True
self._download_xml_is_active = False self._download_xml_is_active = False
builder = get_builder(UI_RESOURCES_PATH + "epg.glade", handlers) 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._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._update_on_start_switch = builder.get_object("update_on_start_switch")
self._epg_dat_source_box = builder.get_object("epg_dat_source_box") 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 # Setting the last size of the dialog window
window_size = self._settings.get("epg_tool_window_size") window_size = self._settings.get("epg_tool_window_size")
if window_size: if window_size:
@@ -188,14 +198,14 @@ class EpgDialog:
try: try:
self.download_epg_from_stb() self.download_epg_from_stb()
except OSError as e: 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 return
yield True yield True
try: try:
refs = EPG.get_epg_refs(self._epg_dat_path_entry.get_text() + "epg.dat") refs = EPG.get_epg_refs(self._epg_dat_path_entry.get_text() + "epg.dat")
except FileNotFoundError as e: 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 return
yield True yield True
@@ -225,7 +235,7 @@ class EpgDialog:
s_types = (BqServiceType.MARKER.value, BqServiceType.IPTV.value) s_types = (BqServiceType.MARKER.value, BqServiceType.IPTV.value)
filtered = filter(None, [srvs.get(ref) for ref in refs]) if refs else filter( 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()) 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() self.update_source_count_info()
def init_xml_source(self, refs): def init_xml_source(self, refs):
@@ -274,7 +284,7 @@ class EpgDialog:
path = tfp.name.rstrip(".gz") path = tfp.name.rstrip(".gz")
except (HTTPError, URLError) as e: 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: else:
try: try:
with open(path, "wb") as f_out: with open(path, "wb") as f_out:
@@ -282,7 +292,7 @@ class EpgDialog:
shutil.copyfileobj(f, f_out) shutil.copyfileobj(f, f_out)
os.remove(tfp.name) os.remove(tfp.name)
except Exception as e: except Exception as e:
raise ValueError("{} {}".format(get_message("Unpacking data error."), e)) raise ValueError(f"{get_message('Unpacking data error.')} {e}")
finally: finally:
self._download_xml_is_active = False self._download_xml_is_active = False
self.update_active_header_elements(True) self.update_active_header_elements(True)
@@ -291,7 +301,7 @@ class EpgDialog:
s_refs, info = ChannelsParser.get_refs_from_xml(path) s_refs, info = ChannelsParser.get_refs_from_xml(path)
yield True yield True
except Exception as e: except Exception as e:
raise ValueError("{} {}".format(get_message("XML parsing error:"), e)) raise ValueError(f"{get_message('XML parsing error:')} {e}")
else: else:
if refs: if refs:
s_refs = filter(lambda x: x.num in refs, s_refs) s_refs = filter(lambda x: x.num in refs, s_refs)
@@ -300,7 +310,7 @@ class EpgDialog:
self.update_source_count_info() self.update_source_count_info()
yield True yield True
def on_key_release(self, view, event): def on_key_press(self, view, event):
""" Handling keystrokes """ """ Handling keystrokes """
key_code = event.hardware_keycode key_code = event.hardware_keycode
if not KeyboardKey.value_exist(key_code): if not KeyboardKey.value_exist(key_code):
@@ -348,7 +358,7 @@ class EpgDialog:
for row in self._services_model: for row in self._services_model:
name = re.sub("\\W+", "", str(row[0])).upper() name = re.sub("\\W+", "", str(row[0])).upper()
name = name.translate(tr) if use_cyrillic else name name = name.translate(tr) if use_cyrillic else name
source[name] = row[1] source[name] = row
success_count = 0 success_count = 0
not_founded = {} not_founded = {}
@@ -378,7 +388,7 @@ class EpgDialog:
get_message("Count of successfully configured services:"), get_message("Count of successfully configured services:"),
success_count), Gtk.MessageType.INFO) 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 row[Column.FAV_TYPE] != BqServiceType.IPTV.value:
if not show_error: if not show_error:
self.show_info_message(get_message("Not allowed in this context!"), Gtk.MessageType.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 = row[Column.FAV_ID]
fav_id_data = fav_id.split(":") 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) new_fav_id = ":".join(fav_id_data)
service = self._services.pop(fav_id, None) service = self._services.pop(fav_id, None)
if service: if service:
self._services[new_fav_id] = service self._services[new_fav_id] = service
row[Column.FAV_ID] = new_fav_id row[Column.FAV_ID] = new_fav_id
row[Column.FAV_LOCKED] = EPG_ICON 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): def on_filter_toggled(self, button: Gtk.ToggleButton):
self._filter_bar.set_search_mode(button.get_active()) 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() model, paths = self._source_view.get_selection().get_selected_rows()
self._current_ref.clear() self._current_ref.clear()
if paths: if paths:
self._current_ref.append(model[paths][1]) self._current_ref.append(model[paths][:])
def on_assign_ref(self, item=None): def on_assign_ref(self, item=None):
if self._current_ref: if self._current_ref:
@@ -481,7 +492,7 @@ class EpgDialog:
# ***************** Drag-and-drop *********************# # ***************** Drag-and-drop *********************#
def init_drag_and_drop(self): def init_drag_and_drop(self):
""" Enable drag-and-drop """ """ Enable drag-and-drop. """
target = [] target = []
self._source_view.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK, target, Gdk.DragAction.COPY) self._source_view.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK, target, Gdk.DragAction.COPY)
self._source_view.drag_source_add_text_targets() self._source_view.drag_source_add_text_targets()
@@ -494,17 +505,22 @@ class EpgDialog:
if selection.count_selected_rows() > 1: if selection.count_selected_rows() > 1:
view.do_toggle_cursor_row(view) 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() model, paths = view.get_selection().get_selected_rows()
if paths: if paths:
val = model.get_value(model.get_iter(paths), 1) s_data = model[paths][:]
data.set_text(val, -1) 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) path, pos = view.get_dest_row_at_pos(x, y)
model = view.get_model() model = view.get_model()
self.assign_data(model[path], data.get_text()) data = data.get_text()
self.update_epg_count() if data:
self.assign_data(model[path], data.split("::::"))
self.update_epg_count()
return False return False
# ***************** Options *********************# # ***************** Options *********************#

View File

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

View File

@@ -469,7 +469,7 @@ class FtpClientBox(Gtk.HBox):
resp = "2" resp = "2"
try: try:
GLib.idle_add(self._app._wait_dialog.show) GLib.idle_add(self._app.wait_dialog.show)
uris = data.get_uris() uris = data.get_uris()
if self._settings.is_darwin and len(uris) == 1: if self._settings.is_darwin and len(uris) == 1:
@@ -488,7 +488,7 @@ class FtpClientBox(Gtk.HBox):
else: else:
resp = self._ftp.send_file(path.name, str(path.parent) + "/", callback=self.update_ftp_info) resp = self._ftp.send_file(path.name, str(path.parent) + "/", callback=self.update_ftp_info)
finally: finally:
GLib.idle_add(self._app._wait_dialog.hide) GLib.idle_add(self._app.wait_dialog.hide)
if resp and resp[0] == "2": if resp and resp[0] == "2":
itr = self._ftp_model.get_iter_first() itr = self._ftp_model.get_iter_first()
if itr: if itr:
@@ -507,7 +507,7 @@ class FtpClientBox(Gtk.HBox):
def on_file_drag_data_received(self, view, context, x, y, data, info, time): 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) + "/" cur_path = self._file_model.get_value(self._file_model.get_iter_first(), self.Column.ATTR) + "/"
try: try:
GLib.idle_add(self._app._wait_dialog.show) GLib.idle_add(self._app.wait_dialog.show)
uris = data.get_uris() uris = data.get_uris()
if self._settings.is_darwin and len(uris) == 1: if self._settings.is_darwin and len(uris) == 1:
@@ -525,7 +525,7 @@ class FtpClientBox(Gtk.HBox):
except OSError as e: except OSError as e:
log(e) log(e)
finally: finally:
GLib.idle_add(self._app._wait_dialog.hide) GLib.idle_add(self._app.wait_dialog.hide)
self.init_file_data(cur_path) self.init_file_data(cur_path)
Gtk.drag_finish(context, True, False, time) Gtk.drag_finish(context, True, False, time)
@@ -564,6 +564,10 @@ class FtpClientBox(Gtk.HBox):
self.on_ftp_file_remove() self.on_ftp_file_remove()
elif self._file_view.is_focus(): elif self._file_view.is_focus():
self.on_file_remove() 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): def on_view_press(self, view, event):
if event.get_event_type() == Gdk.EventType.BUTTON_PRESS and event.button == Gdk.BUTTON_PRIMARY: 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"> <object class="GtkImage" id="cancel_image">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="stock">gtk-cancel</property> <property name="stock">gtk-close</property>
</object> </object>
</child> </child>
</object> </object>
@@ -268,6 +268,33 @@ Author: Dmitriy Yefremov
<property name="skip_taskbar_hint">True</property> <property name="skip_taskbar_hint">True</property>
<property name="skip_pager_hint">True</property> <property name="skip_pager_hint">True</property>
<signal name="response" handler="on_response" swapped="no"/> <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"> <child internal-child="vbox">
<object class="GtkBox" id="iptv_list_configuration_dialog_box"> <object class="GtkBox" id="iptv_list_configuration_dialog_box">
<property name="can_focus">False</property> <property name="can_focus">False</property>
@@ -278,48 +305,6 @@ Author: Dmitriy Yefremov
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="valign">center</property> <property name="valign">center</property>
<property name="layout_style">end</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> </object>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
@@ -873,6 +858,34 @@ Author: Dmitriy Yefremov
<child type="titlebar"> <child type="titlebar">
<placeholder/> <placeholder/>
</child> </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"> <child internal-child="vbox">
<object class="GtkBox" id="iptv_dialog_box"> <object class="GtkBox" id="iptv_dialog_box">
<property name="can_focus">False</property> <property name="can_focus">False</property>
@@ -882,49 +895,6 @@ Author: Dmitriy Yefremov
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="valign">center</property> <property name="valign">center</property>
<property name="layout_style">end</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> </object>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
@@ -938,7 +908,6 @@ Author: Dmitriy Yefremov
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="margin_left">5</property> <property name="margin_left">5</property>
<property name="margin_right">5</property> <property name="margin_right">5</property>
<property name="margin_top">2</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="GtkFrame" id="iptv_dialog_service_data_frame"> <object class="GtkFrame" id="iptv_dialog_service_data_frame">
@@ -1340,60 +1309,60 @@ Author: Dmitriy Yefremov
<property name="position">2</property> <property name="position">2</property>
</packing> </packing>
</child> </child>
<child> </object>
<object class="GtkInfoBar" id="info_bar"> <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="can_focus">False</property>
<property name="show_close_button">True</property> <property name="spacing">6</property>
<signal name="response" handler="on_info_bar_close" swapped="no"/> <property name="layout_style">end</property>
<child internal-child="action_area"> </object>
<object class="GtkButtonBox"> <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="can_focus">False</property>
<property name="spacing">6</property> <property name="halign">start</property>
<property name="layout_style">end</property> <property name="label" translatable="yes">label</property>
<property name="ellipsize">end</property>
</object> </object>
<packing> <packing>
<property name="expand">False</property> <property name="expand">True</property>
<property name="fill">False</property> <property name="fill">True</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="position">0</property> <property name="position">0</property>
</packing> </packing>
</child> </child>
</object> </object>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="fill">True</property> <property name="fill">False</property>
<property name="position">3</property> <property name="position">0</property>
</packing> </packing>
</child> </child>
</object> </object>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="fill">True</property> <property name="fill">True</property>
<property name="position">1</property> <property name="position">2</property>
</packing> </packing>
</child> </child>
</object> </object>

View File

@@ -474,6 +474,8 @@ class IptvListDialog:
self._apply_button = builder.get_object("list_configuration_apply_button") self._apply_button = builder.get_object("list_configuration_apply_button")
self._cancel_button = builder.get_object("cancel_config_list_button") self._cancel_button = builder.get_object("cancel_config_list_button")
self._ok_button = builder.get_object("list_configuration_ok_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
style_provider = Gtk.CssProvider() style_provider = Gtk.CssProvider()
style_provider.load_from_path(UI_RESOURCES_PATH + "style.css") 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() sid_auto = self._sid_auto_check_button.get_active()
nid_default = self._nid_check_button.get_active() nid_default = self._nid_check_button.get_active()
namespace_default = self._namespace_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) 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() 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())) sid = "0" if sid_auto else self._list_sid_entry.get_text()
nid = "0" if nid_default else "{:X}".format(int(self._list_nid_entry.get_text())) tid = "0" if tid_default else f"{int(self._list_tid_entry.get_text()):X}"
namespace = "0" if namespace_default else "{:X}".format(int(self._list_namespace_entry.get_text())) 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): for index, row in enumerate(self._rows):
fav_id = row[Column.FAV_ID] fav_id = row[Column.FAV_ID]
data, sep, desc = fav_id.partition("http") data, sep, desc = fav_id.partition("http")
data = data.split(":") 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" data[1], data[2], data[3], data[4], data[5], data[6] = "010000"
else: else:
data[0], data[1], data[2], data[4], data[5], data[6] = st_type, s_id, srv_type, tid, nid, namespace 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) data = ":".join(data)
new_fav_id = "{}{}{}".format(data, sep, desc) new_fav_id = f"{data}{sep}{desc}"
row[Column.FAV_ID] = new_fav_id row[Column.FAV_ID] = new_fav_id
srv = self._services.pop(fav_id, None) 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)) list(map(lambda r: self._bouquet.append(r[Column.FAV_ID]), self._fav_model))
self._info_bar.set_visible(True) self._info_bar.set_visible(True)
self._ok_button.set_visible(True)
class M3uImportDialog(IptvListDialog): class M3uImportDialog(IptvListDialog):
@@ -636,8 +641,6 @@ class M3uImportDialog(IptvListDialog):
self._dialog.set_title(get_message("Playlist import")) self._dialog.set_title(get_message("Playlist import"))
self._dialog.connect("delete-event", self.on_close) self._dialog.connect("delete-event", self.on_close)
self._apply_button.set_label(get_message("Import")) 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 # Progress
self._progress_bar = Gtk.ProgressBar(visible=False, valign="center") self._progress_bar = Gtk.ProgressBar(visible=False, valign="center")
self._spinner = Gtk.Spinner(active=False) 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_start(self._info_label, False, False, 5)
extra_box.pack_end(self._picon_box, True, True, 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) frame.add(extra_box)
self._data_box.add(frame) self._data_box.add(frame)
@@ -678,7 +681,7 @@ class M3uImportDialog(IptvListDialog):
GLib.idle_add(self._picon_box.set_sensitive, True) GLib.idle_add(self._picon_box.set_sensitive, True)
break break
finally: 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._info_label.set_text, msg)
GLib.idle_add(self._spinner.set_property, "active", False) GLib.idle_add(self._spinner.set_property, "active", False)
@@ -697,6 +700,8 @@ class M3uImportDialog(IptvListDialog):
s_type = params[1] s_type = params[1]
params = params[2:] params = params[2:]
st_type = get_stream_type(self._stream_type_combobox) 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]): for i, s in enumerate(self._services, start=params[0]):
# Skipping markers. # Skipping markers.
@@ -704,7 +709,7 @@ class M3uImportDialog(IptvListDialog):
services.append(s) services.append(s)
continue 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) 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) fav_id = get_fav_id(s.data_id, s.service, self._s_type, params, st_type, s_id, s_type)
if s.picon: if s.picon:
@@ -764,16 +769,16 @@ class M3uImportDialog(IptvListDialog):
@run_idle @run_idle
def on_picon_load_done(self, data, user_data): def on_picon_load_done(self, data, user_data):
try: 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) f = Gio.MemoryInputStream.new_from_data(data)
pixbuf = GdkPixbuf.Pixbuf.new_from_stream_at_scale(f, 220, 132, False, self._cancellable) 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", [], []) pixbuf.savev(path, "png", [], [])
self._picons[user_data] = get_picon_pixbuf(path) self._picons[user_data] = get_picon_pixbuf(path)
except GLib.GError as e: except GLib.GError as e:
self.update_progress(1) self.update_progress(1)
if e.code != Gio.IOErrorEnum.CANCELLED: 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: else:
self.update_progress() self.update_progress()
@@ -789,14 +794,14 @@ class M3uImportDialog(IptvListDialog):
self._progress_bar.set_visible(False) self._progress_bar.set_visible(False)
self._progress_bar.set_fraction(0.0) self._progress_bar.set_fraction(0.0)
self._apply_button.set_sensitive(True) 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 self._is_download = False
gen = self.update_fav_model() gen = self.update_fav_model()
GLib.idle_add(lambda: next(gen, False), priority=GLib.PRIORITY_LOW) GLib.idle_add(lambda: next(gen, False), priority=GLib.PRIORITY_LOW)
def update_fav_model(self): def update_fav_model(self):
services = self._app._services services = self._app.current_services
picons = self._app._picons picons = self._app._picons
model = self._app.fav_view.get_model() model = self._app.fav_view.get_model()
for r in 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 { entry {
@@ -36,3 +37,7 @@ switch slider {
min-height: 1.5em; min-height: 1.5em;
min-width: 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_underline">True</property>
<property name="use_stock">True</property> <property name="use_stock">True</property>
<signal name="activate" handler="on_new_bouquet" object="bouquets_tree_view" swapped="no"/> <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> </object>
</child> </child>
<child> <child>
@@ -355,7 +355,8 @@ Author: Dmitriy Yefremov
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="image">import_bouquet_image</property> <property name="image">import_bouquet_image</property>
<property name="use_stock">False</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> </object>
</child> </child>
<child> <child>
@@ -383,7 +384,7 @@ Author: Dmitriy Yefremov
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="use_stock">True</property> <property name="use_stock">True</property>
<signal name="activate" handler="on_bouquets_cut" object="bouquets_tree_view" swapped="no"/> <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> </object>
</child> </child>
<child> <child>
@@ -395,7 +396,7 @@ Author: Dmitriy Yefremov
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="use_stock">True</property> <property name="use_stock">True</property>
<signal name="activate" handler="on_bouquets_copy" object="bouquets_tree_view" swapped="no"/> <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> </object>
</child> </child>
<child> <child>
@@ -407,7 +408,7 @@ Author: Dmitriy Yefremov
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="use_stock">True</property> <property name="use_stock">True</property>
<signal name="activate" handler="on_bouquets_paste" object="bouquets_tree_view" swapped="no"/> <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> </object>
</child> </child>
<child> <child>
@@ -425,7 +426,7 @@ Author: Dmitriy Yefremov
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="use_stock">True</property> <property name="use_stock">True</property>
<signal name="activate" handler="on_edit" swapped="no"/> <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> </object>
</child> </child>
<child> <child>
@@ -918,7 +919,7 @@ Author: Dmitriy Yefremov
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="use_stock">True</property> <property name="use_stock">True</property>
<signal name="activate" handler="on_to_fav_end_copy" object="services_tree_view" swapped="no"/> <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> </object>
</child> </child>
<child> <child>
@@ -929,7 +930,7 @@ Author: Dmitriy Yefremov
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="use_stock">True</property> <property name="use_stock">True</property>
<signal name="activate" handler="on_to_fav_copy" object="services_tree_view" swapped="no"/> <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> </object>
</child> </child>
<child> <child>
@@ -1033,7 +1034,7 @@ Author: Dmitriy Yefremov
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="use_stock">True</property> <property name="use_stock">True</property>
<signal name="activate" handler="on_services_copy" object="services_tree_view" swapped="no"/> <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> </object>
</child> </child>
<child> <child>
@@ -1044,7 +1045,7 @@ Author: Dmitriy Yefremov
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="use_stock">True</property> <property name="use_stock">True</property>
<signal name="activate" handler="on_edit" swapped="no"/> <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> </object>
</child> </child>
<child> <child>
@@ -1291,7 +1292,7 @@ Author: Dmitriy Yefremov
<object class="GtkLabel" id="app_ver_label"> <object class="GtkLabel" id="app_ver_label">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="label">2.0.0 Alpha2</property> <property name="label">2.0.2 Beta</property>
<attributes> <attributes>
<attribute name="weight" value="bold"/> <attribute name="weight" value="bold"/>
</attributes> </attributes>
@@ -3690,7 +3691,7 @@ Author: Dmitriy Yefremov
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="use_stock">True</property> <property name="use_stock">True</property>
<signal name="activate" handler="on_fav_cut" object="fav_tree_view" swapped="no"/> <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> </object>
</child> </child>
<child> <child>
@@ -3702,7 +3703,7 @@ Author: Dmitriy Yefremov
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="use_stock">True</property> <property name="use_stock">True</property>
<signal name="activate" handler="on_fav_copy" object="fav_tree_view" swapped="no"/> <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> </object>
</child> </child>
<child> <child>
@@ -3714,7 +3715,7 @@ Author: Dmitriy Yefremov
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="use_stock">True</property> <property name="use_stock">True</property>
<signal name="activate" handler="on_fav_paste" object="fav_tree_view" swapped="no"/> <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> </object>
</child> </child>
<child> <child>
@@ -3731,7 +3732,7 @@ Author: Dmitriy Yefremov
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="use_stock">True</property> <property name="use_stock">True</property>
<signal name="activate" handler="on_edit" swapped="no"/> <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> </object>
</child> </child>
<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 .download_dialog import DownloadDialog
from .imports import ImportDialog, import_bouquet from .imports import ImportDialog, import_bouquet
from .iptv import IptvDialog, SearchUnavailableDialog, IptvListConfigurationDialog, YtListImportDialog, M3uImportDialog from .iptv import IptvDialog, SearchUnavailableDialog, IptvListConfigurationDialog, YtListImportDialog, M3uImportDialog
from .main_helper import (insert_marker, move_items, rename, ViewTarget, set_flags, locate_in_services, from .main_helper import *
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 .picons import PiconManager from .picons import PiconManager
from .satellites import SatellitesTool, ServicesUpdateDialog from .satellites import SatellitesTool, ServicesUpdateDialog
from .search import SearchProvider from .search import SearchProvider
from .service_details_dialog import ServiceDetailsDialog, Action 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, from .uicommons import (Gtk, Gdk, UI_RESOURCES_PATH, LOCKED_ICON, HIDE_ICON, IPTV_ICON, MOVE_KEYS, KeyboardKey, Column,
FavClickMode, MOD_MASK, APP_FONT, Page, IS_GNOME_SESSION) FavClickMode, MOD_MASK, APP_FONT, Page, IS_GNOME_SESSION)
@@ -159,6 +155,7 @@ class Application(Gtk.Application):
"on_import_m3u": self.on_import_m3u, "on_import_m3u": self.on_import_m3u,
"on_bouquet_export": self.on_bouquet_export, "on_bouquet_export": self.on_bouquet_export,
"on_export_to_m3u": self.on_export_to_m3u, "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_marker": self.on_insert_marker,
"on_insert_space": self.on_insert_space, "on_insert_space": self.on_insert_space,
"on_fav_press": self.on_fav_press, "on_fav_press": self.on_fav_press,
@@ -429,7 +426,7 @@ class Application(Gtk.Application):
def do_startup(self): def do_startup(self):
Gtk.Application.do_startup(self) Gtk.Application.do_startup(self)
# App menu. # 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 not IS_GNOME_SESSION:
if IS_DARWIN: if IS_DARWIN:
self.set_app_menu(builder.get_object("mac_app_menu")) 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): def on_view_drag_data_received(self, view, drag_context, x, y, data, info, time):
txt = data.get_text() txt = data.get_text()
uris = data.get_uris() uris = data.get_uris()
name, model = get_model_data(view)
if txt: if txt:
name, model = get_model_data(view)
if txt.startswith("file://") and name == self.SERVICE_MODEL_NAME: if txt.startswith("file://") and name == self.SERVICE_MODEL_NAME:
self.on_import_data(urlparse(unquote(txt)).path.strip()) self.on_import_data(urlparse(unquote(txt)).path.strip())
elif name == self.FAV_MODEL_NAME: elif name == self.FAV_MODEL_NAME:
self.receive_selection(view=view, drop_info=view.get_dest_row_at_pos(x, y), data=txt) 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, if uris:
urlparse(unquote(uris[1])).path + os.sep) 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) drag_context.finish(True, False, time)
def on_bq_view_drag_data_received(self, view, drag_context, x, y, data, info, 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 self._bouquets["{}:{}".format(b_row[Column.BQ_NAME], b_row[Column.BQ_TYPE])] = bq
def delete_selection(self, view, *args): 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]: for v in [view, *args]:
v.get_selection().unselect_all() v.get_selection().unselect_all()
def on_settings(self, action, value=None): def on_settings(self, action, value=None):
response = show_settings_dialog(self._main_window, self._settings) dialog = SettingsDialog(self._main_window, self._settings)
if response != Gtk.ResponseType.CANCEL: dialog.show()
if dialog.is_updated():
gen = self.update_settings() gen = self.update_settings()
GLib.idle_add(lambda: next(gen, False), priority=GLib.PRIORITY_LOW) 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) GLib.idle_add(lambda: next(gen, False), priority=GLib.PRIORITY_LOW)
def on_import_data(self, path): 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?" msg = "Combine with the current data?"
if len(self._services_model) > 0 and show_dialog(DialogType.QUESTION, self._main_window, if len(self._services_model) > 0 and show_dialog(DialogType.QUESTION, self._main_window,
msg) == Gtk.ResponseType.OK: msg) == Gtk.ResponseType.OK:
@@ -2932,6 +2944,8 @@ class Application(Gtk.Application):
error_code = info.get("error_code", 0) if info else 0 error_code = info.get("error_code", 0) if info else 0
GLib.idle_add(self._receiver_info_box.set_visible, error_code == 0, priority=GLib.PRIORITY_LOW) GLib.idle_add(self._receiver_info_box.set_visible, error_code == 0, priority=GLib.PRIORITY_LOW)
if error_code < 0: if error_code < 0:
if self._page is Page.CONTROL:
GLib.idle_add(self._control_tool.update_signal, None)
return return
elif error_code == 412: elif error_code == 412:
self._http_api.init() self._http_api.init()
@@ -3352,6 +3366,10 @@ class Application(Gtk.Application):
self.show_error_message("Data loading in progress!") self.show_error_message("Data loading in progress!")
return return
if not len(self._bouquets_model):
self.show_error_message("No bouquets config is loaded. Load or create a new config!")
return
gen_bouquets(self._services_view, self._bouquets_view, self._main_window, g_type, self._s_type, gen_bouquets(self._services_view, self._bouquets_view, self._main_window, g_type, self._s_type,
self.append_bouquet) self.append_bouquet)
@@ -3629,12 +3647,16 @@ def start_app():
try: try:
Settings.get_instance() Settings.get_instance()
except SettingsReadException as e: 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) show_dialog(DialogType.INFO, transient=Gtk.Dialog(), text=msg)
except SettingsException as e: except SettingsException as e:
msg = "{} \n{}".format(e, get_message("All setting were reset. Restart the program!")) msg = f"{e}\n\n{get_message('It is recommended to load the default settings!')}"
show_dialog(DialogType.INFO, transient=Gtk.Dialog(), text=msg) dlg = Gtk.Dialog()
if show_dialog(DialogType.QUESTION, dlg, msg) != Gtk.ResponseType.OK:
return True
Settings.reset_to_default() Settings.reset_to_default()
show_dialog(DialogType.INFO, transient=dlg, text=get_message("All setting were reset. Restart the program!"))
else: else:
app = Application() app = Application()
app.run(sys.argv) 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 os
import shutil import shutil
from collections import defaultdict from collections import defaultdict

View File

@@ -618,10 +618,10 @@ Author: Dmitriy Yefremov
</packing> </packing>
</child> </child>
<child> <child>
<object class="GtkSwitch" id="auto_filer_switch"> <object class="GtkSwitch" id="auto_filter_switch">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">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="valign">center</property>
<property name="margin_right">5</property> <property name="margin_right">5</property>
</object> </object>
@@ -633,7 +633,7 @@ Author: Dmitriy Yefremov
</packing> </packing>
</child> </child>
<child> <child>
<object class="GtkLabel" id="auto_filer_label"> <object class="GtkLabel" id="auto_filter_label">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="label" translatable="yes">Auto</property> <property name="label" translatable="yes">Auto</property>
@@ -675,7 +675,7 @@ Author: Dmitriy Yefremov
<property name="can_focus">False</property> <property name="can_focus">False</property>
<child> <child>
<object class="GtkCheckButton" id="src_filter_button"> <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="can_focus">False</property>
<property name="focus_on_click">False</property> <property name="focus_on_click">False</property>
<property name="receives_default">False</property> <property name="receives_default">False</property>
@@ -705,7 +705,7 @@ Author: Dmitriy Yefremov
<object class="GtkTreeView" id="picons_src_view"> <object class="GtkTreeView" id="picons_src_view">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">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="model">picons_src_sort_model</property>
<property name="enable_grid_lines">horizontal</property> <property name="enable_grid_lines">horizontal</property>
<property name="tooltip_column">0</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)) self._info_bar.connect("response", lambda b, r: b.set_visible(False))
# Filter. # Filter.
self._filter_bar = builder.get_object("filter_bar") 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 = builder.get_object("filter_button")
self._filter_button.bind_property("active", self._filter_bar, "visible") self._filter_button.bind_property("active", self._filter_bar, "visible")
self._filter_button.bind_property("active", self._src_filter_button, "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): def on_picons_view_drag_data_get(self, view, drag_context, data, info, time):
model, path = view.get_selection().get_selected_rows() model, path = view.get_selection().get_selected_rows()
if path: if path:
data.set_uris([Path(model[path][-1]).as_uri(), dest_uri = Path(self._settings.profile_picons_path).as_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): def on_picons_view_drag_drop(self, view, drag_context, x, y, time):
view.stop_emission_by_name("drag_drop") view.stop_emission_by_name("drag_drop")
@@ -357,7 +360,7 @@ class PiconManager(Gtk.Box):
self.update_picons_from_file(view, txt) self.update_picons_from_file(view, txt)
return return
itr_str, sep, src = txt.partition("::::") itr_str, sep, src = txt.partition(self._app.DRAG_SEP)
if src == self._app.BQ_MODEL_NAME: if src == self._app.BQ_MODEL_NAME:
return return
@@ -568,6 +571,7 @@ class PiconManager(Gtk.Box):
dest_path = path or self._settings.profile_picons_path dest_path = path or self._settings.profile_picons_path
settings = Settings(self._settings.settings) settings = Settings(self._settings.settings)
settings.profile_picons_path = f"{dest_path}{SEP}" 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.show_info_message(get_message("Please, wait..."), Gtk.MessageType.INFO)
self.run_func(lambda: upload_data(settings=settings, self.run_func(lambda: upload_data(settings=settings,
download_type=DownloadType.PICONS, download_type=DownloadType.PICONS,
@@ -580,6 +584,7 @@ class PiconManager(Gtk.Box):
path = path or self._settings.profile_picons_path path = path or self._settings.profile_picons_path
settings = Settings(self._settings.settings) settings = Settings(self._settings.settings)
settings.profile_picons_path = path + SEP settings.profile_picons_path = path + SEP
settings.current_profile = self._settings.current_profile
self.run_func(lambda: download_data(settings=settings, self.run_func(lambda: download_data(settings=settings,
download_type=DownloadType.PICONS, download_type=DownloadType.PICONS,
callback=self.append_output, callback=self.append_output,
@@ -937,7 +942,7 @@ class PiconManager(Gtk.Box):
self._filter_button.set_active(not self._filter_button.get_active()) self._filter_button.set_active(not self._filter_button.get_active())
def on_fav_changed(self, view, path, column): 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() model = view.get_model()
self._picons_filter_entry.set_text(model.get_value(model.get_iter(path), Column.FAV_SERVICE)) 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="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Audio Track</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> </object>
</child> </child>
</object> </object>

View File

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

View File

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

View File

@@ -275,6 +275,38 @@ Author: Dmitriy Yefremov
<child type="titlebar"> <child type="titlebar">
<placeholder/> <placeholder/>
</child> </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"> <child internal-child="vbox">
<object class="GtkBox" id="dialog_vbox"> <object class="GtkBox" id="dialog_vbox">
<property name="can_focus">False</property> <property name="can_focus">False</property>
@@ -287,53 +319,6 @@ Author: Dmitriy Yefremov
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="valign">center</property> <property name="valign">center</property>
<property name="layout_style">end</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> </object>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
@@ -1644,6 +1629,9 @@ Author: Dmitriy Yefremov
</child> </child>
</object> </object>
</child> </child>
<action-widgets>
<action-widget response="-6">cancel_button</action-widget>
</action-widgets>
</object> </object>
<object class="GtkListStore" id="transponder_services_liststore"> <object class="GtkListStore" id="transponder_services_liststore">
<columns> <columns>
@@ -1676,6 +1664,24 @@ Author: Dmitriy Yefremov
<child> <child>
<placeholder/> <placeholder/>
</child> </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"> <child internal-child="vbox">
<object class="GtkBox" id="tr_services_dialog_vbox"> <object class="GtkBox" id="tr_services_dialog_vbox">
<property name="can_focus">False</property> <property name="can_focus">False</property>
@@ -1685,34 +1691,6 @@ Author: Dmitriy Yefremov
<object class="GtkButtonBox"> <object class="GtkButtonBox">
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="valign">center</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> </object>
<packing> <packing>
<property name="expand">False</property> <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.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 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 .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): def show_settings_dialog(transient, options):
@@ -50,7 +50,6 @@ class SettingsDialog:
"on_settings_type_changed": self.on_settings_type_changed, "on_settings_type_changed": self.on_settings_type_changed,
"on_reset": self.on_reset, "on_reset": self.on_reset,
"on_response": self.on_response, "on_response": self.on_response,
"apply_settings": self.apply_settings,
"on_connection_test": self.on_connection_test, "on_connection_test": self.on_connection_test,
"on_info_bar_close": self.on_info_bar_close, "on_info_bar_close": self.on_info_bar_close,
"on_set_color_switch": self.on_set_color_switch, "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_add": self.on_icon_theme_add,
"on_icon_theme_remove": self.on_icon_theme_remove} "on_icon_theme_remove": self.on_icon_theme_remove}
# Settings # Settings.
self._ext_settings = settings self._ext_settings = settings
self._settings = Settings(settings.settings) self._settings = Settings(settings.settings)
self._profiles = self._settings.profiles self._profiles = self._settings.profiles
self._s_type = self._settings.setting_type self._s_type = self._settings.setting_type
self._updated = False
builder = get_builder(UI_RESOURCES_PATH + "settings_dialog.glade", handlers) 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._neutrino_radio_button = builder.get_object("neutrino_radio_button")
self._support_ver5_switch = builder.get_object("support_ver5_switch") self._support_ver5_switch = builder.get_object("support_ver5_switch")
self._force_bq_name_switch = builder.get_object("force_bq_name_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._apply_presets_button = builder.get_object("apply_presets_button")
self._transcoding_switch = builder.get_object("transcoding_switch") self._transcoding_switch = builder.get_object("transcoding_switch")
self._edit_preset_switch = builder.get_object("edit_preset_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") self._enable_exp_switch.bind_property("active", builder.get_object("enable_direct_playback_box"), "sensitive")
# Enigma2 only. # 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("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("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("program_frame"), "sensitive")
self._enigma_radio_button.bind_property("active", builder.get_object("experimental_box"), "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_view = builder.get_object("profile_tree_view")
self._profile_add_button = builder.get_object("profile_add_button") self._profile_add_button = builder.get_object("profile_add_button")
self._profile_remove_button = builder.get_object("profile_remove_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. # Style.
self._style_provider = Gtk.CssProvider() self._style_provider = Gtk.CssProvider()
self._style_provider.load_from_path(UI_RESOURCES_PATH + "style.css") self._style_provider.load_from_path(UI_RESOURCES_PATH + "style.css")
@@ -208,6 +210,16 @@ class SettingsDialog:
for el in self._digit_elems: for el in self._digit_elems:
el.get_style_context().add_provider_for_screen(Gdk.Screen.get_default(), self._style_provider, el.get_style_context().add_provider_for_screen(Gdk.Screen.get_default(), self._style_provider,
Gtk.STYLE_PROVIDER_PRIORITY_USER) 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_ui_elements()
self.init_profiles() self.init_profiles()
@@ -233,8 +245,7 @@ class SettingsDialog:
self._neutrino_radio_button.set_active(self._s_type is SettingsType.NEUTRINO_MP) self._neutrino_radio_button.set_active(self._s_type is SettingsType.NEUTRINO_MP)
self.update_picon_paths() self.update_picon_paths()
self.update_title() self.update_title()
http_active = self._support_http_api_switch.get_active() self._click_mode_zap_button.set_sensitive(self._support_http_api_switch.get_active())
self._click_mode_zap_button.set_sensitive(is_enigma_profile and http_active)
self._lang_combo_box.set_active_id(self._ext_settings.language) 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( 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) "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) self._picons_paths_box.set_active(0)
def show(self): def show(self):
self._dialog.run() return self._dialog.run()
def is_updated(self):
return self._updated
def on_response(self, dialog, resp): def on_response(self, dialog, resp):
if resp == Gtk.ResponseType.OK and not self.apply_settings(): if resp == Gtk.ResponseType.ACCEPT:
return self._updated = self.on_save_settings()
dialog.destroy()
self._dialog.destroy()
return resp
def on_field_icon_press(self, entry, icon, event_button): def on_field_icon_press(self, entry, icon, event_button):
update_entry_data(entry, self._dialog, self._settings) 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._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._tooltip_logo_size_button.set_active_id(str(self._settings.tooltip_logo_size))
self._list_font_button.set_font(self._settings.list_font) 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: if self._s_type is SettingsType.ENIGMA_2:
self._enable_exp_switch.set_active(self._settings.is_enable_experimental) self._enable_exp_switch.set_active(self._settings.is_enable_experimental)
self._support_ver5_switch.set_active(self._settings.v5_support) self._support_ver5_switch.set_active(self._settings.v5_support)
self._force_bq_name_switch.set_active(self._settings.force_bq_names) 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_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_update_yt_dl_switch.set_active(self._settings.enable_yt_dl_update)
self._enable_send_to_switch.set_active(self._settings.enable_send_to) 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.satellites_xml_path = self._satellites_xml_field.get_text()
self._settings.picons_path = self._picons_paths_box.get_active_id() 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: if show_dialog(DialogType.QUESTION, self._dialog) != Gtk.ResponseType.OK:
return return False
self.on_apply_profile_settings() self.on_apply_profile_settings()
self._ext_settings.profiles = self._settings.profiles 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.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.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.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: if not IS_LINUX:
self._ext_settings.dark_mode = self._dark_mode_switch.get_active() 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.extra_color = self._extra_color_button.get_rgba().to_string()
self._ext_settings.v5_support = self._support_ver5_switch.get_active() 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.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 = 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_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.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.default_profile = list(filter(lambda r: r[1], self._profile_view.get_model()))[0][0]
self._ext_settings.save() self._ext_settings.save()
return True return True
@run_task @run_task
@@ -594,7 +607,7 @@ class SettingsDialog:
self._ext_settings.picons_paths = tuple(r[0] for r in model) self._ext_settings.picons_paths = tuple(r[0] for r in model)
def on_remove_picon_path(self, button): 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: if show_dialog(DialogType.QUESTION, self._dialog, msg) != Gtk.ResponseType.OK:
return return
@@ -790,15 +803,16 @@ class SettingsDialog:
@run_task @run_task
def unpack_theme(self, src, dst, button): def unpack_theme(self, src, dst, button):
try: try:
os.makedirs(os.path.dirname(dst), exist_ok=True) from shutil import unpack_archive
import subprocess log(f"Unpacking '{src}' started...")
log("Unpacking '{}' started...".format(src)) os.makedirs(os.path.dirname(dst), exist_ok=True)
p = subprocess.Popen(["tar", "-xvf", src, "-C", dst], unpack_archive(src, dst)
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
p.communicate()
log("Unpacking end.") log("Unpacking end.")
except (ValueError, OSError) as e:
msg = f"Unpacking error: {e}"
log(msg)
self.show_info_message(msg, Gtk.MessageType.ERROR)
finally: finally:
self.update_theme_button(button, dst) 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 locale
import os import os
from enum import Enum, IntEnum from enum import Enum, IntEnum
@@ -7,7 +35,7 @@ import gi
gi.require_version("Gtk", "3.0") gi.require_version("Gtk", "3.0")
gi.require_version("Gdk", "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 from app.settings import Settings, SettingsException, IS_DARWIN, GTK_PATH, IS_LINUX
@@ -78,16 +106,22 @@ else:
theme = Gtk.IconTheme.get_default() theme = Gtk.IconTheme.get_default()
theme.append_search_path(UI_RESOURCES_PATH + "icons") 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( def get_icon(name, size, default=None):
"emblem-readonly", 16, 0) else _IMAGE_MISSING try:
LOCKED_ICON = theme.load_icon("changes-prevent-symbolic", 16, 0) if theme.lookup_icon( return theme.load_icon(name, size, 0) if theme.lookup_icon(name, size, 0) else default
"system-lock-screen", 16, 0) else _IMAGE_MISSING except GLib.Error:
HIDE_ICON = theme.load_icon("go-jump", 16, 0) if theme.lookup_icon("go-jump", 16, 0) else _IMAGE_MISSING return default
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 _IMAGE_MISSING = get_icon("image-missing", 16)
DEFAULT_ICON = theme.load_icon("emblem-default", 16, 0) if theme.lookup_icon("emblem-default", 16, 0) else None 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) @lru_cache(maxsize=1)
@@ -263,10 +297,12 @@ if IS_LINUX:
LEFT = 113 LEFT = 113
RIGHT = 114 RIGHT = 114
F2 = 68 F2 = 68
F5 = 71
F7 = 73 F7 = 73
SPACE = 65 SPACE = 65
DELETE = 119 DELETE = 119
BACK_SPACE = 22 BACK_SPACE = 22
RETURN = 36
CTRL_L = 37 CTRL_L = 37
CTRL_R = 105 CTRL_R = 105
# Laptop codes # Laptop codes
@@ -301,10 +337,12 @@ elif IS_DARWIN:
LEFT = 123 LEFT = 123
RIGHT = 123 RIGHT = 123
F2 = 120 F2 = 120
F5 = 96
F7 = 98 F7 = 98
SPACE = 49 SPACE = 49
DELETE = 51 DELETE = 51
BACK_SPACE = 76 BACK_SPACE = 76
RETURN = 36
CTRL_L = 55 CTRL_L = 55
CTRL_R = 55 CTRL_R = 55
# Laptop codes. # Laptop codes.
@@ -337,10 +375,12 @@ else:
LEFT = 37 LEFT = 37
RIGHT = 39 RIGHT = 39
F2 = 113 F2 = 113
F5 = 116
F7 = 118 F7 = 118
SPACE = 32 SPACE = 32
DELETE = 46 DELETE = 46
BACK_SPACE = 8 BACK_SPACE = 8
RETURN = 13
CTRL_L = 17 CTRL_L = 17
CTRL_R = 163 CTRL_R = 163
# Laptop codes. # Laptop codes.

View File

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

View File

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

View File

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

View File

@@ -1258,3 +1258,45 @@ msgstr "Дадаць піконы"
msgid "Logs" msgid "Logs"
msgstr "Логі" 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" msgid "Logs"
msgstr "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

@@ -1233,7 +1233,7 @@ msgid "Mark duplicates"
msgstr "Seleziona duplicati" msgstr "Seleziona duplicati"
msgid "Load only for selected bouquet" msgid "Load only for selected bouquet"
msgstr "Larica solo per i bouquet selezionati" msgstr "Scarica solo per i bouquet selezionati"
msgid "The task is canceled!" msgid "The task is canceled!"
msgstr "Operazione cancellata!" msgstr "Operazione cancellata!"

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. # This file is distributed under the MIT license.
# #
# #
msgid "" msgid ""
msgstr "" msgstr ""
"Last-Translator: wwns\n" "Last-Translator: wwns <https://github.com/wwns>\n"
"Language: pl\n" "Language: pl\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\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" msgid "translator-credits"
msgstr "wwns" msgstr "wwns"
# Main # Main
msgid "File"
msgstr "Plik"
msgid "View"
msgstr "Widok"
msgid "Lock"
msgstr "Zablokuj"
msgid "Service" msgid "Service"
msgstr "Serwis" msgstr "Usługa"
msgid "Package" msgid "Package"
msgstr "Pakiet" msgstr "Pakiet"
@@ -48,7 +44,7 @@ msgid "System"
msgstr "System" msgstr "System"
msgid "Pos" msgid "Pos"
msgstr "Pos" msgstr "Poz"
msgid "Num" msgid "Num"
msgstr "Num" msgstr "Num"
@@ -113,6 +109,9 @@ msgstr "Ustaw domyślną nazwę"
msgid "Insert marker" msgid "Insert marker"
msgstr "Wstaw znacznik" msgstr "Wstaw znacznik"
msgid "Insert space"
msgstr "Wstaw spację"
msgid "Locate in services" msgid "Locate in services"
msgstr "Znajdź w usługach" msgstr "Znajdź w usługach"
@@ -179,6 +178,9 @@ msgstr "Zapisz"
msgid "Search" msgid "Search"
msgstr "Szukaj" msgstr "Szukaj"
msgid "Services"
msgstr "Kanały"
msgid "Services filter" msgid "Services filter"
msgstr "Filtr kanałów" msgstr "Filtr kanałów"
@@ -206,8 +208,8 @@ msgstr "Aktualna ścieżka danych:"
msgid "Data:" msgid "Data:"
msgstr "Dane:" msgstr "Dane:"
msgid "Enigma2 channel and satellite list editor for GNU/Linux." msgid "Enigma2 channel and satellite list editor."
msgstr "Edytor kanałów Enigma2 i listy satelitów dla GNU/Linux." msgstr "Edytor kanałów i list satelitarnych Enigma2."
msgid "Host:" msgid "Host:"
msgstr "Host:" msgstr "Host:"
@@ -222,7 +224,7 @@ msgid "Receive files from receiver"
msgstr "Pobieranie plików z odbiornika" msgstr "Pobieranie plików z odbiornika"
msgid "Receiver IP:" msgid "Receiver IP:"
msgstr "Odbiornik IP:" msgstr "Adres IP odbiornika:"
msgid "Remove unused bouquets" msgid "Remove unused bouquets"
msgstr "Usuń nieużywany bouquet" msgstr "Usuń nieużywany bouquet"
@@ -252,22 +254,7 @@ msgid "User bouquet files:"
msgstr "Pliki bukietu użytkownika:" msgstr "Pliki bukietu użytkownika:"
msgid "Extra:" msgid "Extra:"
msgstr "Dodatkowe" 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?"
# Filter bar # Filter bar
msgid "Only free" msgid "Only free"
@@ -280,6 +267,9 @@ msgid "All types"
msgstr "Wszystkie typy" msgstr "Wszystkie typy"
# Streams player # Streams player
msgid "Play"
msgstr "Odtwarzaj"
msgid "Stop playback" msgid "Stop playback"
msgstr "Zatrzymaj odtwarzanie" msgstr "Zatrzymaj odtwarzanie"
@@ -311,8 +301,8 @@ msgstr "Format nazw pikon:"
msgid "Resize:" msgid "Resize:"
msgstr "Zmień rozmiar:" msgstr "Zmień rozmiar:"
msgid "Current picons path:" msgid "Current picons path"
msgstr "Aktualna ścieżka pikon:" msgstr "Aktualna ścieżka pikon"
msgid "Receiver picons path:" msgid "Receiver picons path:"
msgstr "Ścieżka pikon odbiornika:" msgstr "Ścieżka pikon odbiornika:"
@@ -390,12 +380,6 @@ msgid "Remove selection"
msgstr "Usuń wybrane" msgstr "Usuń wybrane"
# Service details dialog # 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:" msgid "Service data:"
msgstr "Dane usług:" msgstr "Dane usług:"
@@ -467,7 +451,7 @@ msgid "Preferences"
msgstr "Preferencje" msgstr "Preferencje"
msgid "Profile:" msgid "Profile:"
msgstr "Profil:" msgstr "Profile:"
msgid "Timeout between commands in seconds" msgid "Timeout between commands in seconds"
msgstr "Limit czasu między poleceniami w sekundach" msgstr "Limit czasu między poleceniami w sekundach"
@@ -481,6 +465,9 @@ msgstr "Login:"
msgid "Options" msgid "Options"
msgstr "Opcje" msgstr "Opcje"
msgid "Rename"
msgstr "Zmień nazwę"
msgid "Password:" msgid "Password:"
msgstr "Hasło:" msgstr "Hasło:"
@@ -497,13 +484,13 @@ msgid "Picons path:"
msgstr "Ścieżka pikon:" msgstr "Ścieżka pikon:"
msgid "Network settings:" msgid "Network settings:"
msgstr "Ustawienia sieci:" msgstr "Ustawienia połaczenia:"
msgid "STB file paths:" msgid "STB file paths:"
msgstr "Ścieżki do plików w STB:" msgstr "Ścieżki do plików w STB:"
msgid "Local file paths:" msgid "Local file paths:"
msgstr "Lokalne ścieżki plików:" msgstr "Lokalne ścieżki do plików:"
# Dialogs messages # Dialogs messages
msgid "Error. No bouquet is selected!" msgid "Error. No bouquet is selected!"
@@ -539,6 +526,9 @@ msgstr "Wybierz tylko jeden element!"
msgid "No png file is selected!" msgid "No png file is selected!"
msgstr "Nie wybrano pliku png!" msgstr "Nie wybrano pliku png!"
msgid "No profile selected!"
msgstr "Nie wybroano profilu !"
msgid "No reference is present!" msgid "No reference is present!"
msgstr "Brak referencji!" msgstr "Brak referencji!"
@@ -606,6 +596,15 @@ msgstr "Brak danych do zapisania!"
msgid "Network" msgid "Network"
msgstr "Sieć" msgstr "Sieć"
msgid "Paths"
msgstr "Ścieżki"
msgid "Program"
msgstr "Program"
msgid "Backup:"
msgstr "Kopia:"
msgid "Backup" msgid "Backup"
msgstr "Kopia" msgstr "Kopia"
@@ -621,11 +620,26 @@ msgstr "Przywróć bukiety"
msgid "Restore all" msgid "Restore all"
msgstr "Przywrócić wszystko" 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" msgid "Select"
msgstr "Wybierz" msgstr "Wybierz"
msgid "About" msgid "About"
msgstr "Wersja" msgstr "O programie"
msgid "Exit" msgid "Exit"
msgstr "Wyjście" msgstr "Wyjście"
@@ -633,15 +647,6 @@ msgstr "Wyjście"
msgid "Tools" msgid "Tools"
msgstr "Narzędzia" msgstr "Narzędzia"
msgid "Cut"
msgstr "Wytnij"
msgid "Paste"
msgstr "Wklej"
msgid "Insert space"
msgstr "Wstaw spację"
# Import # Import
msgid "Import" msgid "Import"
msgstr "Importuj" msgstr "Importuj"
@@ -664,12 +669,27 @@ msgstr "Usuń wszystkie nieużywane"
msgid "Test" msgid "Test"
msgstr "Test" msgstr "Test"
msgid "Details"
msgstr "Właściwości"
msgid "Test connection" msgid "Test connection"
msgstr "Testuj połączenie" 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)" msgid "Switch(zap) the channel(Ctrl + Z)"
msgstr "Przełącz(zap) kanał(Ctrl + Z)" msgstr "Przełącz(zap) kanał(Ctrl + Z)"
@@ -770,11 +790,26 @@ msgstr "Import listy odtwarzania"
msgid "Getting link error:" msgid "Getting link error:"
msgstr "Błąd pobierania łącza:" msgstr "Błąd pobierania łącza:"
msgid "Extra"
msgstr "Ekstra"
msgid "Apply profile settings"
msgstr "Zastosuj ustawienia profilu"
msgid "Settings type:" msgid "Settings type:"
msgstr "Ustawienia dla:" msgstr "Ustawienia dla:"
msgid "Set default" 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" 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" 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" msgid "Watch the channel in the program"
msgstr "Obejrzyj kanał w programie" msgstr "Obejrzyj kanał w programie"
msgid "Receiver info" msgid "Zap and Play"
msgstr "Informacje o odbiorniku" msgstr "Przełącz i Odtwórz"
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 "Drag or paste the link here" msgid "Drag or paste the link here"
msgstr "Przeciągnij lub wklej tutaj link" 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!" msgid "A bouquet with that name exists!"
msgstr "Istnieje bukiet o tej nazwie!" 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:" msgid "Channels:"
msgstr "Kanały:" msgstr "Kanały:"
msgid "Remove all picons from the receiver" msgid "Sample rate (Hz):"
msgstr "Usuń wszystkie pikony z odbiornika" msgstr "Częstotliwość próbkowania (Hz):"
msgid "Download from the receiver" msgid "Play streams mode:"
msgstr "Pobierz z odbiornika" msgstr "Tryb odtwarzania strumieni:"
msgid "The Neutrino has only experimental support. Not all features are supported!" msgid "Built-in player"
msgstr "Neutrino ma jedynie wsparcie eksperymentalne. Nie wszystkie funkcje są obsługiwane!" 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!" msgid "Some images may have problems displaying the favorites list!"
msgstr "Niektóre obrazy mogą mieć problemy z wyświetlaniem listy ulubionych!" 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" msgid "Appearance"
msgstr "Wygląd" msgstr "Wygląd"
msgid "Enable Dark Mode"
msgstr "Włącz tryb ciemny"
msgid "Enable Themes support" msgid "Enable Themes support"
msgstr "Włącz obsługę motywów" msgstr "Włącz obsługę motywów"
msgid "EXPERIMENTAL!"
msgstr "EKSPERYMENTALNE!"
msgid "Gtk3 Theme:" msgid "Gtk3 Theme:"
msgstr "Gtk3 motyw:" msgstr "Gtk3 motyw:"
@@ -846,159 +988,346 @@ msgstr "Motyw ikon:"
msgid "Gtk3 Themes and Icons:" msgid "Gtk3 Themes and Icons:"
msgstr "Gtk3 motywy i ikony:" msgstr "Gtk3 motywy i ikony:"
msgid "Save and restart the program to apply the settings." msgid "Deleting data..."
msgstr "Zapisz i uruchom ponownie program, aby zastosować ustawienia." msgstr "Usuwanie danych…"
# Extra msgid "Download from the receiver"
msgid "Extra" msgstr "Pobierz z odbiornika"
msgstr "Ekstra"
msgid "Enable alternate bouquet file naming" msgid "Remove all picons from the receiver"
msgstr "Włącz alternatywne nazewnictwo plików bukietów" msgstr "Usuń wszystkie pikony z odbiornika"
msgid "Allows you to name bouquet files using their names." msgid "Service reference"
msgstr "Pozwala nazwać pliki bukietów przy użyciu ich nazw." msgstr "Odniesienie do usługi"
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 "Enable support for" msgid "Enable support for"
msgstr "Włącz obsługę" 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" msgid "Auto-check for updates"
msgstr "Automatyczne sprawdzanie aktualizacji" msgstr "Automatyczne sprawdzanie aktualizacji"
msgid "Enable direct playback bar" msgid "Filter services"
msgstr "Włącz pasek bezpośredniego odtwarzania" msgstr "Filtruj usługi"
#Program msgid "Filter services in the main list."
msgid "Program" msgstr "Filtruj usługi na głównej liście."
msgstr "Program"
msgid "Language:" msgid "Destination:"
msgstr "Język:" msgstr "Miejsce docelowe:"
msgid "Load the last open configuration at program startup" msgid "EXPERIMENTAL!"
msgstr "Załaduj ostatnią otwartą konfigurację podczas uruchamiania programu" msgstr "EKSPERYMENTALNE!"
msgid "Show short info as hints in the main services list" msgid "Sorting data..."
msgstr "Pokaż krótkie informacje jako wskazówki na głównej liście usług" msgstr "Sortowanie danych…"
msgid "Show detailed info as hints in the bouquet list" msgid ""
msgstr "Pokaż szczegółowe informacje jako wskazówki na liście bukietów" "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" msgid ""
msgstr "Ustaw kolor tła dla usług" "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:" msgid "Remove from the receiver"
msgstr "Oznacz jako nowy:" msgstr "Usuń z odbiornika"
msgid "With an extra name in the bouquet:" msgid "Screenshot"
msgstr "Z dodatkową nazwą w bukiecie:" msgstr "Zrzut ekranu"
msgid "Backup:" msgid "Video"
msgstr "Kopia:" msgstr "Opcje wideo"
msgid "Before saving" msgid "The Neutrino has only experimental support. Not all features are supported!"
msgstr "Przed zapisaniem" msgstr "Neutrino ma jedynie wsparcie eksperymentalne. Nie wszystkie funkcje są obsługiwane!"
msgid "Before downloading from the receiver" msgid "Enable experimental features"
msgstr "Przed pobraniem z odbiornika" msgstr "Włącz funkcje eksperymentalne"
#Streaming msgid "Can't Playback!"
msgid "Streaming" msgstr "Nie można odtworzyć!"
msgstr "Transmisja"
msgid "Record to disk:" msgid "Enable Dark Mode"
msgstr "Nagrywanie na dysk:" msgstr "Włącz tryb ciemny"
msgid "Activate transcoding" msgid "Extract..."
msgstr "Aktywuj transkodowanie" msgstr "Rozpakuj…"
msgid "Presets:" msgid "Unsupported format!"
msgstr "Ustawienia wstępne:" msgstr "Format nieobsługiwany!"
msgid "720p TV/device" msgid "Combine with the current data?"
msgstr "Dla urządzeń z obsługą rozdzielczości 720p" msgstr "Połączyć z aktualnymi danymi?"
msgid "1080p TV/device" msgid "Importing data done!"
msgstr "Dla urządzeń z obsługą rozdzielczości 1080p" msgstr "Importowanie danych zakończone!"
msgid "Video options:" msgid "Current service"
msgstr "Opcje wideo:" msgstr "Bieżąca usługa"
msgid "Width (px):" msgid "Open folder"
msgstr "Szerokość (px):" msgstr "Otwórz folder"
msgid "Height (px):" msgid "Open archive"
msgstr "Wysokość (px):" msgstr "Otwórz archiwum"
msgid "Codec:" msgid "Import from Web"
msgstr "Kodek:" msgstr "Importuj z sieci"
msgid "Audio options:" msgid "Control"
msgstr "Opcje audio:" msgstr "Kontrola"
msgid "Services" msgid "Timers"
msgstr "Kanały" msgstr "Timery"
msgid "Sample rate (Hz):" msgid "Timer"
msgstr "Częstotliwość próbkowania (Hz):" msgstr "Timer"
msgid "Play streams mode:" msgid "Add timer"
msgstr "Odtwarzaj tryb strumieni:" msgstr "Dodaj timer"
msgid "Bulit-in player" msgid "Hr."
msgstr "Wbudowany odtwarzacz" msgstr "Hr."
msgid "VLC media player" msgid "Min."
msgstr "Odtwarzacz multimedialny VLC" msgstr "Min."
msgid "Only get m3u file" msgid "Power"
msgstr "Tylko pobierz plik m3u" msgstr "Włącz"
# Paths msgid "Standby"
msgid "Paths" msgstr "Czuwanie"
msgstr "Ścieżki"
msgid "Make profile folder as default for the additional data" msgid "Wake Up"
msgstr "Ustaw folder profilu jako domyślny dla dodatkowych danych" 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." 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." 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" msgid "Logs"
msgstr "Журнал" 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" "Project-Id-Version: DemonEditor\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-04-16 15:59+0300\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" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\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" "Language-Team: \n"
"X-Generator: Poedit 2.4.1\n" "X-Generator: Poedit 3.0\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Language: tr\n" "Language: tr\n"
@@ -206,8 +206,8 @@ msgstr "Mevcut veri yolu:"
msgid "Data:" msgid "Data:"
msgstr "Veri:" msgstr "Veri:"
msgid "Enigma2 channel and satellite list editor for GNU/Linux." msgid "Enigma2 channel and satellite list editor."
msgstr "GNU/Linux için Enigma2 kanalı ve uydu listesi editörü." msgstr "Enigma2 kanal ve uydu listesi düzenleyicisi."
msgid "Host:" msgid "Host:"
msgstr "Ana bilgisayar:" msgstr "Ana bilgisayar:"
@@ -299,8 +299,8 @@ msgstr "Piconların adı biçimi:"
msgid "Resize:" msgid "Resize:"
msgstr "Yeniden boyutlandır:" msgstr "Yeniden boyutlandır:"
msgid "Current picons path:" msgid "Current picons path"
msgstr "Geçerli picon yolları:" msgstr "Mevcut piconların yolu"
msgid "Receiver picons path:" msgid "Receiver picons path:"
msgstr "Alıcı picon yolu:" msgstr "Alıcı picon yolu:"
@@ -1269,3 +1269,63 @@ msgstr "Yalnızca seçilen buket için yükle"
msgid "The task is canceled!" msgid "The task is canceled!"
msgstr "Görev iptal edildi!" 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."