mirror of
https://github.com/DYefremov/DemonEditor.git
synced 2026-05-08 11:37:16 +02:00
Compare commits
168 Commits
2.0.2-b1
...
0.4.8-macO
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb5afb0206 | ||
|
|
115f3960a7 | ||
|
|
6d37da072e | ||
|
|
99c3b1d194 | ||
|
|
43afaf77b8 | ||
|
|
38aabb1b94 | ||
|
|
ef501f1557 | ||
|
|
4679f9379c | ||
|
|
b2ea39f8a6 | ||
|
|
638be67425 | ||
|
|
9ca5a597d5 | ||
|
|
d95ba7336f | ||
|
|
c78b18ddb7 | ||
|
|
92984c5fa6 | ||
|
|
ca65f64a4f | ||
|
|
78dcccbd51 | ||
|
|
f984d10c82 | ||
|
|
c4ea451f52 | ||
|
|
36ec6d5079 | ||
|
|
91706c722f | ||
|
|
4ef8c4d186 | ||
|
|
f9e92b28d0 | ||
|
|
832bab91a4 | ||
|
|
951c99338f | ||
|
|
ee91eb9413 | ||
|
|
912c38825b | ||
|
|
de4d012784 | ||
|
|
351ce81e94 | ||
|
|
3a0f096a6c | ||
|
|
29088ec19e | ||
|
|
4c144951f0 | ||
|
|
dae6ad765a | ||
|
|
b934407d7e | ||
|
|
3fb5b82cc6 | ||
|
|
ba3ad9a9ef | ||
|
|
7a4620a374 | ||
|
|
174634ecbc | ||
|
|
73ae57d07b | ||
|
|
055a700586 | ||
|
|
04203240a7 | ||
|
|
a433e01b65 | ||
|
|
8f591a8b9a | ||
|
|
dcc217b0de | ||
|
|
d06334b0af | ||
|
|
6957a960ca | ||
|
|
9fe328b54e | ||
|
|
b3dc9b72c9 | ||
|
|
b6a4d46227 | ||
|
|
53776bdf62 | ||
|
|
ba9ba4129f | ||
|
|
a2411ba86e | ||
|
|
a6d8573999 | ||
|
|
7510d42fb9 | ||
|
|
036e666c9b | ||
|
|
c9c962e129 | ||
|
|
ea71af9462 | ||
|
|
0a5b51de6e | ||
|
|
8cb413ec92 | ||
|
|
5dfb702484 | ||
|
|
0cab4e1238 | ||
|
|
85f5c37f28 | ||
|
|
3df6d7bba0 | ||
|
|
e45c56f4cc | ||
|
|
7d03631924 | ||
|
|
7b9ec6a4b1 | ||
|
|
d640210ab0 | ||
|
|
f7e8283355 | ||
|
|
f93c81de19 | ||
|
|
e1804755d2 | ||
|
|
1cf56639c1 | ||
|
|
943b4c540f | ||
|
|
4602c51c01 | ||
|
|
a84cc7727f | ||
|
|
250e03af5d | ||
|
|
2c5f8eb0ed | ||
|
|
6f4ff4c97d | ||
|
|
ee29659739 | ||
|
|
8a1496a84c | ||
|
|
23c3035162 | ||
|
|
a506356547 | ||
|
|
0c284fb0d9 | ||
|
|
b437385325 | ||
|
|
c60bba5535 | ||
|
|
1c2d0ab9ea | ||
|
|
f35f7fbc8a | ||
|
|
42aaad291f | ||
|
|
9c8c617393 | ||
|
|
98fc963fa1 | ||
|
|
fbb5cd0352 | ||
|
|
5abe3de3b6 | ||
|
|
0b3f26ab84 | ||
|
|
2666146b5e | ||
|
|
be90b518c9 | ||
|
|
adeae58488 | ||
|
|
b204f042ee | ||
|
|
79d0e9d256 | ||
|
|
4dcfde8b53 | ||
|
|
42f687020b | ||
|
|
14bf79dbf9 | ||
|
|
f660beef16 | ||
|
|
99d17b36c3 | ||
|
|
3113fadcca | ||
|
|
67a394359d | ||
|
|
1acb7fdd81 | ||
|
|
dced81581c | ||
|
|
6a52988f1a | ||
|
|
4a1d714604 | ||
|
|
2e12e1ec87 | ||
|
|
4c6336e75f | ||
|
|
b7d0ba7f4b | ||
|
|
405e07bbc4 | ||
|
|
6ded67147b | ||
|
|
4a0e2acd9c | ||
|
|
5876f70884 | ||
|
|
3cb4f1095d | ||
|
|
af46c2fb1d | ||
|
|
cbcdf19be6 | ||
|
|
f326a9c723 | ||
|
|
53888a45dc | ||
|
|
c2d3cb7673 | ||
|
|
9d4b507559 | ||
|
|
2993fcd7f7 | ||
|
|
5bea9887db | ||
|
|
dd0edfc811 | ||
|
|
5bf6500809 | ||
|
|
d05da3f44c | ||
|
|
b251ce8b69 | ||
|
|
df36860239 | ||
|
|
6f27040164 | ||
|
|
4d488dd224 | ||
|
|
c728a59e92 | ||
|
|
98341064d3 | ||
|
|
fc00b25fd2 | ||
|
|
638f33ac5a | ||
|
|
88167912b3 | ||
|
|
450d7f4c72 | ||
|
|
24729c064c | ||
|
|
df3c2a3938 | ||
|
|
44bf8b96ff | ||
|
|
6b86db4aa4 | ||
|
|
bf9ad139e5 | ||
|
|
20fc199d02 | ||
|
|
e0a22f72fc | ||
|
|
8cadc47da5 | ||
|
|
499ca31992 | ||
|
|
e198f0b1e6 | ||
|
|
a43ac0de02 | ||
|
|
b14e6fac16 | ||
|
|
2dcc9a85b5 | ||
|
|
7ce9ba0db2 | ||
|
|
fc56b047a1 | ||
|
|
78dc62d46e | ||
|
|
20e7ee3478 | ||
|
|
ffa144367f | ||
|
|
237d09a711 | ||
|
|
272cbdeb2f | ||
|
|
f9191a7465 | ||
|
|
f22abe1d87 | ||
|
|
b94c08284a | ||
|
|
e303f25f99 | ||
|
|
b80dcb7d74 | ||
|
|
63c5df0ef6 | ||
|
|
c69888a72d | ||
|
|
07606077e5 | ||
|
|
e1f63bfed7 | ||
|
|
c0865beb3c | ||
|
|
05eff28b75 | ||
|
|
6d2150b731 |
@@ -1,11 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Version=1.0
|
||||
Name=DemonEditor
|
||||
Comment=Channels and satellites list editor for Enigma2
|
||||
Comment[ru]=Редактор списка каналов и спутников для Enigma2
|
||||
Icon=demon-editor
|
||||
Exec=bash -c 'cd $(dirname %k) && ./start.py'
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=Utility;Application;
|
||||
StartupNotify=false
|
||||
63
DemonEditor.spec
Normal file
63
DemonEditor.spec
Normal file
@@ -0,0 +1,63 @@
|
||||
import os
|
||||
import distutils.util
|
||||
|
||||
EXE_NAME = 'start.py'
|
||||
DIR_PATH = os.getcwd()
|
||||
COMPILING_PLATFORM = distutils.util.get_platform()
|
||||
PATH_EXE = [os.path.join(DIR_PATH, EXE_NAME)]
|
||||
STRIP = True
|
||||
|
||||
block_cipher = None
|
||||
|
||||
ui_files = [('app/ui/*.glade', 'ui'),
|
||||
('app/ui/*.css', 'ui'),
|
||||
('app/ui/*.ui', 'ui'),
|
||||
('app/ui/lang*', 'share/locale'),
|
||||
('app/ui/icons*', 'share/icons')
|
||||
]
|
||||
|
||||
a = Analysis([EXE_NAME],
|
||||
pathex=PATH_EXE,
|
||||
binaries=None,
|
||||
datas=ui_files,
|
||||
hiddenimports=[],
|
||||
hookspath=[],
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
win_no_prefer_redirects=False,
|
||||
win_private_assemblies=False,
|
||||
cipher=block_cipher)
|
||||
|
||||
pyz = PYZ(a.pure,
|
||||
a.zipped_data,
|
||||
cipher=block_cipher)
|
||||
|
||||
exe = EXE(pyz,
|
||||
a.scripts,
|
||||
exclude_binaries=True,
|
||||
name='DemonEditor',
|
||||
debug=False,
|
||||
strip=STRIP,
|
||||
upx=True,
|
||||
console=False)
|
||||
|
||||
coll = COLLECT(exe,
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
strip=STRIP,
|
||||
upx=True,
|
||||
name='DemonEditor')
|
||||
|
||||
app = BUNDLE(coll,
|
||||
name='DemonEditor.app',
|
||||
icon='icon.icns',
|
||||
bundle_identifier=None,
|
||||
info_plist={
|
||||
'NSPrincipalClass': 'NSApplication',
|
||||
'CFBundleName': 'DemonEditor',
|
||||
'CFBundleDisplayName': 'DemonEditor',
|
||||
'CFBundleGetInfoString': "Enigma2 channel and satellites editor",
|
||||
'CFBundleShortVersionString': "0.4.8 Pre-alpha",
|
||||
'NSHumanReadableCopyright': u"Copyright © 2020, Dmitriy Yefremov"
|
||||
})
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018-2019 Dmitriy Yefremov
|
||||
Copyright (c) 2018-2020 Dmitriy Yefremov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
98
README.md
98
README.md
@@ -1,61 +1,73 @@
|
||||
# <img src="app/ui/icons/hicolor/96x96/apps/demon-editor.png" width="32" /> DemonEditor
|
||||
|
||||
## Enigma2 channel and satellites list editor for GNU/Linux.
|
||||
Experimental support of Neutrino-MP or others on the same basis (BPanther, etc).
|
||||
Focused on the convenience of working in lists from the keyboard. The mouse is also fully supported (Drag and Drop etc)
|
||||
|
||||
[](LICENSE)
|
||||
## Enigma2 channel and satellites list editor for macOS (experimental).
|
||||
**The functionality and performance of this version may be different from the Linux version!
|
||||
Not all features can be supported and tested!**
|
||||
### Main features of the program:
|
||||
* Editing bouquets, channels, satellites.
|
||||
* Import function.
|
||||
* Backup function.
|
||||
* Extended support of IPTV.
|
||||
* Support of picons.
|
||||
* Downloading of picons and updating of satellites (transponders) from the Internet.
|
||||
* Downloading of picons and updating of satellites (transponders) from the web.
|
||||
* Import to bouquet(Neutrino WEBTV) from m3u.
|
||||
* Export of bouquets with IPTV services in m3u.
|
||||
* Assignment of EPGs from DVB or XML for IPTV services (only Enigma2, experimental).
|
||||
* Preview (playback) of IPTV or other streams directly from the bouquet list (should be installed [VLC](https://www.videolan.org/vlc/)).
|
||||
|
||||
### Keyboard shortcuts:
|
||||
* **Ctrl + Insert** - copies the selected channels from the main list to the the bouquet beginning
|
||||
or inserts (creates) a new bouquet.
|
||||
* **Ctrl + BackSpace** - copies the selected channels from the main list to the bouquet end.
|
||||
* **Ctrl + X** - only in bouquet list. **Ctrl + C** - only in services list.
|
||||
#### Keyboard shortcuts:
|
||||
* **⌘ + X** - only in bouquet list.
|
||||
* **⌘ + C** - only in services list.
|
||||
Clipboard is **"rubber"**. There is an accumulation before the insertion!
|
||||
* **Ctrl + E** - edit.
|
||||
* **Ctrl + R, F2** - rename.
|
||||
* **Ctrl + S, T** in Satellites edit tool for create satellite or transponder.
|
||||
* **Ctrl + L** - parental lock.
|
||||
* **Ctrl + H** - hide/skip.
|
||||
* **Ctrl + P** - start play IPTV or other stream in the bouquet list.
|
||||
* **Ctrl + Z** - switch(**zap**) the channel(works when the HTTP API is enabled, Enigma2 only).
|
||||
* **Ctrl + W** - switch to the channel and watch in the program.
|
||||
* **Space** - select/deselect.
|
||||
* **Left/Right** - remove selection.
|
||||
* **Ctrl + Up, Down, PageUp, PageDown, Home, End** - move selected items in the list.
|
||||
* **Ctrl + O** - (re)load user data from current dir.
|
||||
* **Ctrl + D** - load data from receiver.
|
||||
* **Ctrl + U/B** upload data/bouquets to receiver.
|
||||
|
||||
* **⌘ + E** - edit.
|
||||
* **⌘ + R, F2** - rename.
|
||||
* **⌘ + S, T** in Satellites edit tool for create satellite or transponder.
|
||||
* **⌘ + L** - parental lock.
|
||||
* **⌘ + H** - hide/skip.
|
||||
* **⌘ + P** - start play IPTV or other stream in the bouquet list.
|
||||
* **⌘ + Z** - switch(**zap**) the channel(works when the HTTP API is enabled, Enigma2 only).
|
||||
* **⌘ + W** - switch to the channel and watch in the program.
|
||||
* **⌘ + Up/Down** - move selected items in the list.
|
||||
* **⌘ + O** - (re)load user data from current dir.
|
||||
* **⌘ + D** - load data from receiver.
|
||||
* **⌘ + U/B** - upload data/bouquets to receiver.
|
||||
* **⌘ + F** - show/hide search bar.
|
||||
* **⇧ + ⌘ + F** - show/hide filter bar.
|
||||
* **Left/Right** - remove selection.
|
||||
|
||||
For multiple mouse selection (including Drag and Drop), press and hold the **⌘** key!
|
||||
|
||||
### Minimum requirements:
|
||||
Python >= 3.5.2 and GTK+ >= 3.16 with PyGObject bindings, python3-requests.
|
||||
|
||||
### Launching:
|
||||
To start the program, in most cases it is enough to download the archive, unpack and run it by
|
||||
double clicking on DemonEditor.desktop in the root directory, or launching from the console
|
||||
with the command: ```./start.py```
|
||||
Extra folders can be deleted, excluding the *app* folder and root files like *DemonEditor.desktop* and *start.py*!
|
||||
|
||||
Python >= **3.5**, GTK+ >= **3.16**, pygobject3, adwaita-icon-theme, python3-requests.
|
||||
#### Installation:
|
||||
```brew install python3 gtk+3 pygobject3 adwaita-icon-theme```
|
||||
```pip3 install requests```
|
||||
#### Optional:
|
||||
```brew install wget imagemagick```
|
||||
```pip3 install pyobjc```
|
||||
#### Launching:
|
||||
To start the program, just download the archive, unpack and run it from the terminal with the command: ```./start.py```
|
||||
### Building standalone application:
|
||||
Install [PyInstaller](https://www.pyinstaller.org/) with the command from the terminal:
|
||||
```pip3 install pyinstaller```
|
||||
and in th root dir run command:
|
||||
```pyinstaller DemonEditor.spec```
|
||||
### Standalone package:
|
||||
Users of the **64-bit version of the OS** can download a ready-made package from [here](https://github.com/DYefremov/DemonEditor/raw/experimental-mac/dist/DemonEditor.app.zip).
|
||||
Just unpack and run. Recommended copy the bundle to the **Application** directory.
|
||||
Perhaps in the security settings it will be necessary to allow the launch of this application!
|
||||
### Note:
|
||||
To create a simple **debian package**, you can use the *build-deb.sh.*
|
||||
Users of **LTS** versions of [Ubuntu](https://ubuntu.com/) or those based on them can use [PPA](https://launchpad.net/~dmitriy-yefremov/+archive/ubuntu/demon-editor) repository.
|
||||
|
||||
The program is tested only with [openATV](https://www.opena.tv/) image and **Formuler F1** receiver in my favourite Linux distributions
|
||||
(the latest versions of [Linux Mint](https://linuxmint.com/) 18.* and 19* MATE 64-bit)!
|
||||
THIS SOFTWARE COMES WITH ABSOLUTELY NO WARRANTY.
|
||||
AUTHOR IS NOT LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY CONNECTION WITH THIS SOFTWARE.
|
||||
This package may contain components distributed under the GPL [v3](http://www.gnu.org/licenses/gpl-3.0.html) or lower license.
|
||||
By downloading this package you agree to the terms of this [license](http://www.gnu.org/licenses/gpl-3.0.html) and the possible inconvenience associated with this!
|
||||
|
||||
**The package may not contain all the latest changes!**
|
||||
### Important:
|
||||
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!** If you need full set of the data, including *[satellites, terrestrial, cables].xml* (current files will be overwritten),
|
||||
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.
|
||||
|
||||
@@ -6,28 +6,22 @@ from gi.repository import GLib
|
||||
|
||||
_LOG_FILE = "demon-editor.log"
|
||||
_DATE_FORMAT = "%d-%m-%y %H:%M:%S"
|
||||
_LOGGER_NAME = "main_logger"
|
||||
_USE_LOG = False
|
||||
_LOGGER_NAME = None
|
||||
|
||||
|
||||
def init_logger():
|
||||
global _USE_LOG
|
||||
_USE_LOG = True
|
||||
global _LOGGER_NAME
|
||||
_LOGGER_NAME = "main_logger"
|
||||
logging.Logger(_LOGGER_NAME)
|
||||
logging.basicConfig(level=logging.INFO,
|
||||
format="%(asctime)s %(message)s",
|
||||
datefmt=_DATE_FORMAT,
|
||||
handlers=[logging.FileHandler(_LOG_FILE),
|
||||
logging.StreamHandler()])
|
||||
handlers=[logging.FileHandler(_LOG_FILE), logging.StreamHandler()])
|
||||
log("Logging is enabled.", level=logging.INFO)
|
||||
|
||||
|
||||
def get_logger():
|
||||
return logging.getLogger(_LOGGER_NAME)
|
||||
|
||||
|
||||
def log(message, level=logging.ERROR):
|
||||
get_logger().log(level, message) if _USE_LOG else print(message)
|
||||
logging.getLogger(_LOGGER_NAME).log(level, message)
|
||||
|
||||
|
||||
def run_idle(func):
|
||||
|
||||
@@ -10,19 +10,20 @@ from http.client import RemoteDisconnected
|
||||
from telnetlib import Telnet
|
||||
from urllib.error import HTTPError, URLError
|
||||
from urllib.parse import urlencode
|
||||
from urllib.request import urlopen, HTTPPasswordMgrWithDefaultRealm, HTTPBasicAuthHandler, \
|
||||
build_opener, install_opener, Request
|
||||
from urllib.request import (urlopen, HTTPPasswordMgrWithDefaultRealm, HTTPBasicAuthHandler, build_opener,
|
||||
install_opener, Request)
|
||||
|
||||
from app.commons import log, run_task
|
||||
from app.settings import SettingsType
|
||||
|
||||
_BQ_FILES_LIST = ("tv", "radio", # enigma 2
|
||||
"myservices.xml", "bouquets.xml", "ubouquets.xml") # neutrino
|
||||
BQ_FILES_LIST = ("tv", "radio", # enigma 2
|
||||
"myservices.xml", "bouquets.xml", "ubouquets.xml") # neutrino
|
||||
|
||||
_DATA_FILES_LIST = ("lamedb", "lamedb5", "services.xml", "blacklist", "whitelist",)
|
||||
DATA_FILES_LIST = ("lamedb", "lamedb5", "blacklist", "whitelist",)
|
||||
|
||||
_SAT_XML_FILE = "satellites.xml"
|
||||
_WEBTV_XML_FILE = "webtv.xml"
|
||||
STC_XML_FILE = ("satellites.xml", "terrestrial.xml", "cables.xml")
|
||||
WEB_TV_XML_FILE = ("webtv.xml",)
|
||||
PICONS_SUF = (".jpg", ".png")
|
||||
|
||||
|
||||
class DownloadType(Enum):
|
||||
@@ -41,9 +42,15 @@ class HttpRequestType(Enum):
|
||||
STREAM = "stream.m3u?ref="
|
||||
STREAM_CURRENT = "streamcurrent.m3u"
|
||||
CURRENT = "getcurrent"
|
||||
PLAY = "mediaplayerplay?file=4097:0:1:0:0:0:0:0:0:0:"
|
||||
TEST = None
|
||||
TOKEN = "session"
|
||||
PLAY = "mediaplayerplay?file="
|
||||
PLAYER_LIST = "mediaplayerlist?path=playlist"
|
||||
PLAYER_PLAY = "mediaplayercmd?command=play"
|
||||
PLAYER_NEXT = "mediaplayercmd?command=next"
|
||||
PLAYER_PREV = "mediaplayercmd?command=previous"
|
||||
PLAYER_STOP = "mediaplayercmd?command=stop"
|
||||
PLAYER_REMOVE = "mediaplayerremove?file="
|
||||
|
||||
|
||||
class TestException(Exception):
|
||||
@@ -60,43 +67,33 @@ def download_data(*, settings, download_type=DownloadType.ALL, callback=print):
|
||||
callback("FTP OK.\n")
|
||||
save_path = settings.data_local_path
|
||||
os.makedirs(os.path.dirname(save_path), exist_ok=True)
|
||||
files = []
|
||||
# bouquets
|
||||
if download_type is DownloadType.ALL or download_type is DownloadType.BOUQUETS:
|
||||
ftp.cwd(settings.services_path)
|
||||
ftp.dir(files.append)
|
||||
file_list = _BQ_FILES_LIST + _DATA_FILES_LIST if download_type is DownloadType.ALL else _BQ_FILES_LIST
|
||||
for file in files:
|
||||
name = str(file).strip()
|
||||
if name.endswith(file_list):
|
||||
name = name.split()[-1]
|
||||
download_file(ftp, name, save_path, callback)
|
||||
# satellites.xml and webtv
|
||||
if download_type in (DownloadType.ALL, DownloadType.SATELLITES, DownloadType.WEBTV):
|
||||
ftp.cwd(settings.satellites_xml_path)
|
||||
files.clear()
|
||||
ftp.dir(files.append)
|
||||
file_list = BQ_FILES_LIST + DATA_FILES_LIST if download_type is DownloadType.ALL else BQ_FILES_LIST
|
||||
for file in filter(lambda f: f.endswith(file_list), ftp.nlst()):
|
||||
download_file(ftp, file, save_path, callback)
|
||||
# *.xml and webtv
|
||||
if download_type in (DownloadType.ALL, DownloadType.SATELLITES):
|
||||
download_xml(ftp, save_path, settings.satellites_xml_path, STC_XML_FILE, callback)
|
||||
if download_type in (DownloadType.ALL, DownloadType.WEBTV):
|
||||
download_xml(ftp, save_path, settings.satellites_xml_path, WEB_TV_XML_FILE, callback)
|
||||
|
||||
for file in files:
|
||||
name = str(file).strip()
|
||||
if download_type in (DownloadType.ALL, DownloadType.SATELLITES) and name.endswith(_SAT_XML_FILE):
|
||||
download_file(ftp, _SAT_XML_FILE, save_path, callback)
|
||||
if download_type in (DownloadType.ALL, DownloadType.WEBTV) and name.endswith(_WEBTV_XML_FILE):
|
||||
download_file(ftp, _WEBTV_XML_FILE, save_path, callback)
|
||||
if download_type is DownloadType.PICONS:
|
||||
picons_path = settings.picons_local_path
|
||||
os.makedirs(os.path.dirname(picons_path), exist_ok=True)
|
||||
download_picons(ftp, settings.picons_path, picons_path, callback)
|
||||
# epg.dat
|
||||
if download_type is DownloadType.EPG:
|
||||
stb_path = settings.services_path
|
||||
epg_options = settings.epg_options
|
||||
if epg_options:
|
||||
stb_path = epg_options.epg_dat_stb_path or stb_path
|
||||
save_path = epg_options.epg_dat_path or save_path
|
||||
stb_path = epg_options.get("epg_dat_stb_path", stb_path)
|
||||
save_path = epg_options.get("epg_dat_path", save_path)
|
||||
|
||||
ftp.cwd(stb_path)
|
||||
ftp.dir(files.append)
|
||||
for file in files:
|
||||
name = str(file).strip()
|
||||
if name.endswith("epg.dat"):
|
||||
name = name.split()[-1]
|
||||
download_file(ftp, name, save_path, callback)
|
||||
for file in filter(lambda f: f.endswith("epg.dat"), ftp.nlst()):
|
||||
download_file(ftp, file, save_path, callback)
|
||||
|
||||
callback("\nDone.\n")
|
||||
|
||||
@@ -146,23 +143,23 @@ def upload_data(*, settings, download_type=DownloadType.ALL, remove_unused=False
|
||||
services_path = settings.services_path
|
||||
|
||||
if download_type is DownloadType.SATELLITES:
|
||||
upload_xml(ftp, data_path, sat_xml_path, _SAT_XML_FILE, callback)
|
||||
upload_xml(ftp, data_path, sat_xml_path, STC_XML_FILE, callback)
|
||||
|
||||
if s_type is SettingsType.NEUTRINO_MP and download_type is DownloadType.WEBTV:
|
||||
upload_xml(ftp, data_path, sat_xml_path, _WEBTV_XML_FILE, callback)
|
||||
upload_xml(ftp, data_path, sat_xml_path, WEB_TV_XML_FILE, callback)
|
||||
|
||||
if download_type is DownloadType.BOUQUETS:
|
||||
ftp.cwd(services_path)
|
||||
upload_bouquets(ftp, data_path, remove_unused, callback)
|
||||
|
||||
if download_type is DownloadType.ALL:
|
||||
upload_xml(ftp, data_path, sat_xml_path, _SAT_XML_FILE, callback)
|
||||
upload_xml(ftp, data_path, sat_xml_path, STC_XML_FILE, callback)
|
||||
if s_type is SettingsType.NEUTRINO_MP:
|
||||
upload_xml(ftp, data_path, sat_xml_path, _WEBTV_XML_FILE, callback)
|
||||
upload_xml(ftp, data_path, sat_xml_path, WEB_TV_XML_FILE, callback)
|
||||
|
||||
ftp.cwd(services_path)
|
||||
upload_bouquets(ftp, data_path, remove_unused, callback)
|
||||
upload_files(ftp, data_path, _DATA_FILES_LIST, callback)
|
||||
upload_files(ftp, data_path, DATA_FILES_LIST, callback)
|
||||
|
||||
if download_type is DownloadType.PICONS:
|
||||
upload_picons(ftp, settings.picons_local_path, settings.picons_path, callback)
|
||||
@@ -189,12 +186,12 @@ def upload_data(*, settings, download_type=DownloadType.ALL, remove_unused=False
|
||||
def upload_bouquets(ftp, data_path, remove_unused, callback):
|
||||
if remove_unused:
|
||||
remove_unused_bouquets(ftp, callback)
|
||||
upload_files(ftp, data_path, _BQ_FILES_LIST, callback)
|
||||
upload_files(ftp, data_path, BQ_FILES_LIST, callback)
|
||||
|
||||
|
||||
def upload_files(ftp, data_path, file_list, callback):
|
||||
for file_name in os.listdir(data_path):
|
||||
if file_name == _SAT_XML_FILE or file_name == _WEBTV_XML_FILE:
|
||||
if file_name in STC_XML_FILE or file_name in WEB_TV_XML_FILE:
|
||||
continue
|
||||
if file_name.endswith(file_list):
|
||||
send_file(file_name, data_path, ftp, callback)
|
||||
@@ -210,12 +207,21 @@ def remove_unused_bouquets(ftp, callback):
|
||||
callback("Deleting file: {}. Status: {}\n".format(name, ftp.delete(name)))
|
||||
|
||||
|
||||
def upload_xml(ftp, data_path, xml_path, xml_file, callback):
|
||||
""" Used for transfer satellites.xml or webtv.xml files """
|
||||
def upload_xml(ftp, data_path, xml_path, xml_files, callback):
|
||||
""" Used for transfer *.xml files. """
|
||||
ftp.cwd(xml_path)
|
||||
send_file(xml_file, data_path, ftp, callback)
|
||||
for xml_file in xml_files:
|
||||
send_file(xml_file, data_path, ftp, callback)
|
||||
|
||||
|
||||
def download_xml(ftp, data_path, xml_path, xml_files, callback):
|
||||
""" Used for download *.xml files. """
|
||||
ftp.cwd(xml_path)
|
||||
list(map(lambda f: download_file(ftp, f, data_path, callback), (f for f in ftp.nlst() if f.endswith(xml_files))))
|
||||
|
||||
|
||||
# ***************** Picons *******************#
|
||||
|
||||
def upload_picons(ftp, src, dest, callback):
|
||||
try:
|
||||
ftp.cwd(dest)
|
||||
@@ -223,17 +229,49 @@ def upload_picons(ftp, src, dest, callback):
|
||||
if str(e).startswith("550"):
|
||||
ftp.mkd(dest) # if not exist
|
||||
ftp.cwd(dest)
|
||||
|
||||
delete_picons(ftp, callback)
|
||||
|
||||
for file_name in os.listdir(src):
|
||||
if file_name.endswith(PICONS_SUF):
|
||||
send_file(file_name, src, ftp, callback)
|
||||
|
||||
|
||||
def download_picons(ftp, src, dest, callback):
|
||||
try:
|
||||
ftp.cwd(src)
|
||||
except error_perm as e:
|
||||
callback(str(e))
|
||||
return
|
||||
|
||||
for file in filter(lambda f: f.endswith(PICONS_SUF), ftp.nlst()):
|
||||
download_file(ftp, file, dest, callback)
|
||||
|
||||
|
||||
def delete_picons(ftp, callback, dest=None):
|
||||
if dest:
|
||||
try:
|
||||
ftp.cwd(dest)
|
||||
except error_perm as e:
|
||||
callback(str(e))
|
||||
return
|
||||
|
||||
files = []
|
||||
ftp.dir(files.append)
|
||||
picons_suf = (".jpg", ".png")
|
||||
for file in files:
|
||||
name = str(file).strip()
|
||||
if name.endswith(picons_suf):
|
||||
if name.endswith(PICONS_SUF):
|
||||
name = name.split()[-1]
|
||||
ftp.delete(name)
|
||||
for file_name in os.listdir(src):
|
||||
if file_name.endswith(picons_suf):
|
||||
send_file(file_name, src, ftp, callback)
|
||||
callback("Delete file: {}. Status: {}\n".format(name, ftp.delete(name)))
|
||||
|
||||
|
||||
def remove_picons(*, settings, callback, done_callback=None):
|
||||
with FTP(host=settings.host, user=settings.user, passwd=settings.password) as ftp:
|
||||
ftp.encoding = "utf-8"
|
||||
callback("FTP OK.\n")
|
||||
delete_picons(ftp, callback, settings.picons_path)
|
||||
if done_callback:
|
||||
done_callback()
|
||||
|
||||
|
||||
def download_file(ftp, name, save_path, callback):
|
||||
@@ -243,7 +281,12 @@ def download_file(ftp, name, save_path, callback):
|
||||
|
||||
def send_file(file_name, path, ftp, callback):
|
||||
""" Opens the file in binary mode and transfers into receiver """
|
||||
with open(path + file_name, "rb") as f:
|
||||
file_src = path + file_name
|
||||
if not os.path.isfile(file_src):
|
||||
log("Uploading file: '{}'. File not found. Skipping.".format(file_src))
|
||||
return
|
||||
|
||||
with open(file_src, "rb") as f:
|
||||
callback("Uploading file: {}. Status: {}\n".format(file_name, str(ftp.storbinary("STOR " + file_name, f))))
|
||||
|
||||
|
||||
@@ -298,7 +341,7 @@ class HttpAPI:
|
||||
from concurrent.futures import ThreadPoolExecutor as PoolExecutor
|
||||
self._executor = PoolExecutor(max_workers=self.__MAX_WORKERS)
|
||||
|
||||
def send(self, req_type, ref, callback=print):
|
||||
def send(self, req_type, ref, callback=print, ref_prefix=""):
|
||||
if self._shutdown:
|
||||
return
|
||||
|
||||
@@ -306,11 +349,14 @@ class HttpAPI:
|
||||
|
||||
if req_type is HttpRequestType.ZAP or req_type is HttpRequestType.STREAM:
|
||||
url += urllib.parse.quote(ref)
|
||||
elif req_type is HttpRequestType.PLAY:
|
||||
url += urllib.parse.quote(ref).replace("%3A", "%253A")
|
||||
elif req_type is HttpRequestType.PLAY or req_type is HttpRequestType.PLAYER_REMOVE:
|
||||
url += "{}{}".format(ref_prefix, urllib.parse.quote(ref).replace("%3A", "%253A"))
|
||||
|
||||
def done_callback(f):
|
||||
callback(f.result())
|
||||
|
||||
future = self._executor.submit(get_response, req_type, url, self._data)
|
||||
future.add_done_callback(lambda f: callback(f.result()))
|
||||
future.add_done_callback(done_callback)
|
||||
|
||||
@run_task
|
||||
def init(self):
|
||||
@@ -334,10 +380,13 @@ def get_response(req_type, url, data=None):
|
||||
try:
|
||||
with urlopen(Request(url, data=data), timeout=10) as f:
|
||||
if req_type is HttpRequestType.STREAM or req_type is HttpRequestType.STREAM_CURRENT:
|
||||
return f.read().decode("utf-8")
|
||||
return {"m3u": f.read().decode("utf-8")}
|
||||
elif req_type is HttpRequestType.CURRENT:
|
||||
for el in ETree.fromstring(f.read().decode("utf-8")).iter("e2event"):
|
||||
return {el.tag: el.text for el in el.iter()} # return first[current] event from the list
|
||||
elif req_type is HttpRequestType.PLAYER_LIST:
|
||||
return [{el.tag: el.text for el in el.iter()} for el in
|
||||
ETree.fromstring(f.read().decode("utf-8")).iter("e2file")]
|
||||
else:
|
||||
return {el.tag: el.text for el in ETree.fromstring(f.read().decode("utf-8")).iter()}
|
||||
except HTTPError as e:
|
||||
|
||||
@@ -33,9 +33,9 @@ def get_bouquets(path, s_type):
|
||||
|
||||
|
||||
@run_task
|
||||
def write_bouquets(path, bouquets, s_type):
|
||||
def write_bouquets(path, bouquets, s_type, force_bq_names=False):
|
||||
if s_type is SettingsType.ENIGMA_2:
|
||||
write_enigma_bouquets(path, bouquets)
|
||||
write_enigma_bouquets(path, bouquets, force_bq_names)
|
||||
elif s_type is SettingsType.NEUTRINO_MP:
|
||||
write_neutrino_bouquets(path, bouquets)
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
""" Module for parsing bouquets """
|
||||
""" Module for working with Enigma2 bouquets. """
|
||||
import re
|
||||
from collections import Counter
|
||||
|
||||
from app.commons import log
|
||||
from app.eparser.ecommons import BqServiceType, BouquetService, Bouquets, Bouquet, BqType
|
||||
|
||||
_TV_ROOT_FILE_NAME = "bouquets.tv"
|
||||
@@ -13,7 +15,12 @@ def get_bouquets(path):
|
||||
BqType.RADIO.value)
|
||||
|
||||
|
||||
def write_bouquets(path, bouquets):
|
||||
def write_bouquets(path, bouquets, force_bq_names=False):
|
||||
""" Creating and writing bouquets files.
|
||||
|
||||
If "force_bq_names" then naming the files using the name of the bouquet.
|
||||
Some images may have problems displaying the favorites list!
|
||||
"""
|
||||
srv_line = '#SERVICE 1:7:{}:0:0:0:0:0:0:0:FROM BOUQUET "userbouquet.{}.{}" ORDER BY bouquet\n'
|
||||
line = []
|
||||
pattern = re.compile("[^\\w_()]+")
|
||||
@@ -23,12 +30,12 @@ def write_bouquets(path, bouquets):
|
||||
line.clear()
|
||||
line.append("#NAME {}\n".format(bqs.name))
|
||||
|
||||
for bq in bqs.bouquets:
|
||||
for index, bq in enumerate(bqs.bouquets):
|
||||
bq_name = bq.name
|
||||
if bq_name == "Favourites (TV)" or bq_name == "Favourites (Radio)":
|
||||
bq_name = _DEFAULT_BOUQUET_NAME
|
||||
else:
|
||||
bq_name = re.sub(pattern, "_", bq.name)
|
||||
bq_name = re.sub(pattern, "_", bq.name) if force_bq_names else "de{0:02d}".format(index)
|
||||
line.append(srv_line.format(2 if bq.type == BqType.RADIO.value else 1, bq_name, bq.type))
|
||||
write_bouquet(path + "userbouquet.{}.{}".format(bq_name, bq.type), bq.name, bq.services, current_marker)
|
||||
|
||||
@@ -60,7 +67,7 @@ def write_bouquet(path, name, services, current_marker):
|
||||
|
||||
|
||||
def to_bouquet_id(srv):
|
||||
""" Creates bouquet channel id """
|
||||
""" Creates bouquet channel id. """
|
||||
data_type = srv.data_id
|
||||
if data_type and len(data_type) > 4:
|
||||
data_type = int(srv.data_id.split(":")[4])
|
||||
@@ -69,7 +76,7 @@ def to_bouquet_id(srv):
|
||||
|
||||
|
||||
def get_bouquet(path, name, bq_type):
|
||||
""" Parsing services ids from bouquet file """
|
||||
""" Parsing services ids from bouquet file. """
|
||||
with open(path + "userbouquet.{}.{}".format(name, bq_type), encoding="utf-8", errors="replace") as file:
|
||||
chs_list = file.read()
|
||||
services = []
|
||||
@@ -77,16 +84,16 @@ def get_bouquet(path, name, bq_type):
|
||||
for ch in srvs[1:]:
|
||||
ch_data = ch.strip().split(":")
|
||||
if ch_data[1] == "64":
|
||||
marker_data = ch.split("#DESCRIPTION", 1)
|
||||
services.append(BouquetService(marker_data[1].strip(), BqServiceType.MARKER, ch, ch_data[2]))
|
||||
m_data, sep, desc = ch.partition("#DESCRIPTION")
|
||||
services.append(BouquetService(desc.strip() if desc else "", BqServiceType.MARKER, ch, ch_data[2]))
|
||||
elif "http" in ch:
|
||||
stream_data = ch.split("#DESCRIPTION", 1)
|
||||
services.append(BouquetService(stream_data[-1].strip(":").strip(), BqServiceType.IPTV, ch, 0))
|
||||
stream_data, sep, desc = ch.partition("#DESCRIPTION")
|
||||
services.append(BouquetService(desc.lstrip(":").strip() if desc else "", BqServiceType.IPTV, ch, 0))
|
||||
else:
|
||||
fav_id = "{}:{}:{}:{}".format(ch_data[3], ch_data[4], ch_data[5], ch_data[6])
|
||||
name = None
|
||||
if len(ch_data) == 12:
|
||||
name, desc = str(ch_data[-1]).split("\n#DESCRIPTION")
|
||||
name, sep, desc = str(ch_data[-1]).partition("\n#DESCRIPTION")
|
||||
services.append(BouquetService(name, BqServiceType.DEFAULT, fav_id.upper(), 0))
|
||||
|
||||
return srvs[0].lstrip("#NAME").strip(), services
|
||||
@@ -98,6 +105,8 @@ def parse_bouquets(path, bq_name, bq_type):
|
||||
bouquets = None
|
||||
nm_sep = "#NAME"
|
||||
bq_pattern = re.compile(".*userbouquet\\.+(.*)\\.+[tv|radio].*")
|
||||
b_names = set()
|
||||
real_b_names = Counter()
|
||||
|
||||
for line in lines:
|
||||
if nm_sep in line:
|
||||
@@ -106,8 +115,21 @@ def parse_bouquets(path, bq_name, bq_type):
|
||||
if bouquets and "#SERVICE" in line:
|
||||
name = re.match(bq_pattern, line)
|
||||
if name:
|
||||
b_name, services = get_bouquet(path, name.group(1), bq_type)
|
||||
bouquets[2].append(Bouquet(name=b_name,
|
||||
b_name = name.group(1)
|
||||
if b_name in b_names:
|
||||
log("The list of bouquets contains duplicate [{}] names!".format(b_name))
|
||||
else:
|
||||
b_names.add(b_name)
|
||||
|
||||
rb_name, services = get_bouquet(path, b_name, bq_type)
|
||||
if rb_name in real_b_names:
|
||||
log("Bouquet file 'userbouquet.{}.{}' has duplicate name: {}".format(b_name, bq_type, rb_name))
|
||||
real_b_names[rb_name] += 1
|
||||
rb_name = "{} {}".format(rb_name, real_b_names[rb_name])
|
||||
else:
|
||||
real_b_names[rb_name] = 0
|
||||
|
||||
bouquets[2].append(Bouquet(name=rb_name,
|
||||
type=bq_type,
|
||||
services=services,
|
||||
locked=None,
|
||||
|
||||
260
app/settings.py
260
app/settings.py
@@ -2,14 +2,19 @@ import copy
|
||||
import json
|
||||
import locale
|
||||
import os
|
||||
import sys
|
||||
from enum import Enum, IntEnum
|
||||
from functools import lru_cache
|
||||
from pathlib import Path
|
||||
from pprint import pformat
|
||||
from textwrap import dedent
|
||||
|
||||
CONFIG_PATH = str(Path.home()) + "/.config/demon-editor/"
|
||||
HOME_PATH = str(Path.home())
|
||||
CONFIG_PATH = HOME_PATH + "/.config/demon-editor/"
|
||||
CONFIG_FILE = CONFIG_PATH + "config.json"
|
||||
DATA_PATH = "data/"
|
||||
DATA_PATH = HOME_PATH + "/DemonEditor/data/"
|
||||
|
||||
IS_DARWIN = sys.platform == "darwin"
|
||||
|
||||
|
||||
class Defaults(Enum):
|
||||
@@ -18,6 +23,7 @@ class Defaults(Enum):
|
||||
BACKUP_BEFORE_DOWNLOADING = True
|
||||
BACKUP_BEFORE_SAVE = True
|
||||
V5_SUPPORT = False
|
||||
FORCE_BQ_NAMES = False
|
||||
HTTP_API_SUPPORT = False
|
||||
ENABLE_YT_DL = False
|
||||
ENABLE_SEND_TO = False
|
||||
@@ -25,6 +31,21 @@ class Defaults(Enum):
|
||||
NEW_COLOR = "rgb(255,230,204)"
|
||||
EXTRA_COLOR = "rgb(179,230,204)"
|
||||
FAV_CLICK_MODE = 0
|
||||
PLAY_STREAMS_MODE = 1 if IS_DARWIN else 0
|
||||
PROFILE_FOLDER_DEFAULT = False
|
||||
RECORDS_PATH = DATA_PATH + "records/"
|
||||
ACTIVATE_TRANSCODING = False
|
||||
ACTIVE_TRANSCODING_PRESET = "720p TV/device"
|
||||
|
||||
|
||||
def get_settings():
|
||||
os.makedirs(os.path.dirname(CONFIG_PATH), exist_ok=True)
|
||||
|
||||
if not os.path.isfile(CONFIG_FILE) or os.stat(CONFIG_FILE).st_size == 0:
|
||||
write_settings(get_default_settings())
|
||||
|
||||
with open(CONFIG_FILE, "r") as config_file:
|
||||
return json.load(config_file)
|
||||
|
||||
|
||||
def get_default_settings(profile_name="default"):
|
||||
@@ -42,14 +63,32 @@ def get_default_settings(profile_name="default"):
|
||||
"use_colors": Defaults.USE_COLORS.value,
|
||||
"new_color": Defaults.NEW_COLOR.value,
|
||||
"extra_color": Defaults.EXTRA_COLOR.value,
|
||||
"fav_click_mode": Defaults.FAV_CLICK_MODE.value
|
||||
"fav_click_mode": Defaults.FAV_CLICK_MODE.value,
|
||||
"profile_folder_is_default": Defaults.PROFILE_FOLDER_DEFAULT.value,
|
||||
"records_path": Defaults.RECORDS_PATH.value
|
||||
}
|
||||
|
||||
|
||||
def set_local_paths(settings, profile_name):
|
||||
settings["data_local_path"] = "{}{}/".format(settings["data_local_path"], profile_name)
|
||||
settings["picons_local_path"] = "{}{}/".format(settings["picons_local_path"], profile_name)
|
||||
settings["backup_local_path"] = "{}{}/".format(settings["backup_local_path"], profile_name)
|
||||
def get_default_transcoding_presets():
|
||||
return {"720p TV/device": {"vcodec": "h264", "vb": "1500", "width": "1280", "height": "720", "acodec": "mp3",
|
||||
"ab": "192", "channels": "2", "samplerate": "44100", "scodec": "none"},
|
||||
"1080p TV/device": {"vcodec": "h264", "vb": "3500", "width": "1920", "height": "1080", "acodec": "mp3",
|
||||
"ab": "192", "channels": "2", "samplerate": "44100", "scodec": "none"}}
|
||||
|
||||
|
||||
def write_settings(config):
|
||||
with open(CONFIG_FILE, "w") as config_file:
|
||||
json.dump(config, config_file, indent=" ")
|
||||
|
||||
|
||||
def set_local_paths(settings, profile_name, data_path=DATA_PATH, use_profile_folder=False):
|
||||
settings["data_local_path"] = "{}{}/".format(data_path, profile_name)
|
||||
if use_profile_folder:
|
||||
settings["picons_local_path"] = "{}{}/{}/".format(data_path, profile_name, "picons")
|
||||
settings["backup_local_path"] = "{}{}/{}/".format(data_path, profile_name, "backup")
|
||||
else:
|
||||
settings["picons_local_path"] = "{}{}/{}/".format(data_path, "picons", profile_name)
|
||||
settings["backup_local_path"] = "{}{}/{}/".format(data_path, "backup", profile_name)
|
||||
|
||||
|
||||
class SettingsType(IntEnum):
|
||||
@@ -86,6 +125,13 @@ class SettingsException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class PlayStreamsMode(IntEnum):
|
||||
""" Behavior mode when opening streams. """
|
||||
BUILT_IN = 0
|
||||
VLC = 1
|
||||
M3U = 2
|
||||
|
||||
|
||||
class Settings:
|
||||
__INSTANCE = None
|
||||
__VERSION = 1
|
||||
@@ -99,7 +145,9 @@ class Settings:
|
||||
self._settings = settings
|
||||
self._current_profile = self._settings.get("default_profile", "default")
|
||||
self._profiles = self._settings.get("profiles", {"default": SettingsType.ENIGMA_2.get_default_settings()})
|
||||
self._cp_settings = self._profiles.get(self._current_profile) # Current profile settings
|
||||
self._cp_settings = self._profiles.get(self._current_profile, None) # Current profile settings
|
||||
if not self._cp_settings:
|
||||
raise SettingsException("Error reading settings [current profile].")
|
||||
|
||||
def __str__(self):
|
||||
return dedent(""" Current profile: {}
|
||||
@@ -123,7 +171,10 @@ class Settings:
|
||||
def reset(self, force_write=False):
|
||||
for k, v in self.setting_type.get_default_settings().items():
|
||||
self._cp_settings[k] = v
|
||||
set_local_paths(self._cp_settings, self._current_profile)
|
||||
|
||||
def_path = self.default_data_path
|
||||
def_path += "enigma2/" if self.setting_type is SettingsType.ENIGMA_2 else "neutrino/"
|
||||
set_local_paths(self._cp_settings, self._current_profile, def_path, self.profile_folder_is_default)
|
||||
|
||||
if force_write:
|
||||
self.save()
|
||||
@@ -188,21 +239,7 @@ class Settings:
|
||||
def setting_type(self, s_type):
|
||||
self._cp_settings["setting_type"] = s_type.value
|
||||
|
||||
@property
|
||||
def language(self):
|
||||
return self._settings.get("language", locale.getlocale()[0] or "en_US")
|
||||
|
||||
@language.setter
|
||||
def language(self, value):
|
||||
self._settings["language"] = value
|
||||
|
||||
@property
|
||||
def load_last_config(self):
|
||||
return self._settings.get("load_last_config", False)
|
||||
|
||||
@load_last_config.setter
|
||||
def load_last_config(self, value):
|
||||
self._settings["load_last_config"] = value
|
||||
# ******* Network ******** #
|
||||
|
||||
@property
|
||||
def host(self):
|
||||
@@ -332,14 +369,6 @@ class Settings:
|
||||
def satellites_xml_path(self, value):
|
||||
self._cp_settings["satellites_xml_path"] = value
|
||||
|
||||
@property
|
||||
def data_local_path(self):
|
||||
return self._cp_settings.get("data_local_path", self.get_default("data_local_path"))
|
||||
|
||||
@data_local_path.setter
|
||||
def data_local_path(self, value):
|
||||
self._cp_settings["data_local_path"] = value
|
||||
|
||||
@property
|
||||
def picons_path(self):
|
||||
return self._cp_settings.get("picons_path", self.get_default("picons_path"))
|
||||
@@ -348,6 +377,32 @@ class Settings:
|
||||
def picons_path(self, value):
|
||||
self._cp_settings["picons_path"] = value
|
||||
|
||||
# ***** Local paths ***** #
|
||||
|
||||
@property
|
||||
def profile_folder_is_default(self):
|
||||
return self._settings.get("profile_folder_is_default", Defaults.PROFILE_FOLDER_DEFAULT.value)
|
||||
|
||||
@profile_folder_is_default.setter
|
||||
def profile_folder_is_default(self, value):
|
||||
self._settings["profile_folder_is_default"] = value
|
||||
|
||||
@property
|
||||
def default_data_path(self):
|
||||
return self._settings.get("default_data_path", DATA_PATH)
|
||||
|
||||
@default_data_path.setter
|
||||
def default_data_path(self, value):
|
||||
self._settings["default_data_path"] = value
|
||||
|
||||
@property
|
||||
def data_local_path(self):
|
||||
return self._cp_settings.get("data_local_path", self.get_default("data_local_path"))
|
||||
|
||||
@data_local_path.setter
|
||||
def data_local_path(self, value):
|
||||
self._cp_settings["data_local_path"] = value
|
||||
|
||||
@property
|
||||
def picons_local_path(self):
|
||||
return self._cp_settings.get("picons_local_path", self.get_default("picons_local_path"))
|
||||
@@ -364,7 +419,60 @@ class Settings:
|
||||
def backup_local_path(self, value):
|
||||
self._cp_settings["backup_local_path"] = value
|
||||
|
||||
# ***** Program settings *****
|
||||
@property
|
||||
def records_path(self):
|
||||
return self._settings.get("records_path", Defaults.RECORDS_PATH.value)
|
||||
|
||||
@records_path.setter
|
||||
def records_path(self, value):
|
||||
self._settings["records_path"] = value
|
||||
|
||||
# ******** Streaming ********* #
|
||||
|
||||
@property
|
||||
def activate_transcoding(self):
|
||||
return self._settings.get("activate_transcoding", Defaults.ACTIVATE_TRANSCODING.value)
|
||||
|
||||
@activate_transcoding.setter
|
||||
def activate_transcoding(self, value):
|
||||
self._settings["activate_transcoding"] = value
|
||||
|
||||
@property
|
||||
def active_preset(self):
|
||||
return self._settings.get("active_preset", Defaults.ACTIVE_TRANSCODING_PRESET.value)
|
||||
|
||||
@active_preset.setter
|
||||
def active_preset(self, value):
|
||||
self._settings["active_preset"] = value
|
||||
|
||||
@property
|
||||
def transcoding_presets(self):
|
||||
return self._settings.get("transcoding_presets", get_default_transcoding_presets())
|
||||
|
||||
@transcoding_presets.setter
|
||||
def transcoding_presets(self, value):
|
||||
self._settings["transcoding_presets"] = value
|
||||
|
||||
@property
|
||||
def play_streams_mode(self):
|
||||
return PlayStreamsMode(self._settings.get("play_streams_mode", Defaults.PLAY_STREAMS_MODE.value))
|
||||
|
||||
@play_streams_mode.setter
|
||||
def play_streams_mode(self, value):
|
||||
self._settings["play_streams_mode"] = value
|
||||
|
||||
# *********** EPG ************ #
|
||||
|
||||
@property
|
||||
def epg_options(self):
|
||||
""" Options used by the EPG dialog. """
|
||||
return self._cp_settings.get("epg_options", None)
|
||||
|
||||
@epg_options.setter
|
||||
def epg_options(self, value):
|
||||
self._cp_settings["epg_options"] = value
|
||||
|
||||
# ***** Program settings ***** #
|
||||
|
||||
@property
|
||||
def backup_before_save(self):
|
||||
@@ -390,6 +498,14 @@ class Settings:
|
||||
def v5_support(self, value):
|
||||
self._settings["v5_support"] = value
|
||||
|
||||
@property
|
||||
def force_bq_names(self):
|
||||
return self._settings.get("force_bq_names", Defaults.FORCE_BQ_NAMES.value)
|
||||
|
||||
@force_bq_names.setter
|
||||
def force_bq_names(self, value):
|
||||
self._settings["force_bq_names"] = value
|
||||
|
||||
@property
|
||||
def http_api_support(self):
|
||||
return self._settings.get("http_api_support", Defaults.HTTP_API_SUPPORT.value)
|
||||
@@ -446,21 +562,79 @@ class Settings:
|
||||
def fav_click_mode(self, value):
|
||||
self._settings["fav_click_mode"] = value
|
||||
|
||||
@property
|
||||
def language(self):
|
||||
return self._settings.get("language", locale.getlocale()[0] or "en_US")
|
||||
|
||||
def get_settings():
|
||||
os.makedirs(os.path.dirname(CONFIG_PATH), exist_ok=True) # create dir if not exist
|
||||
os.makedirs(os.path.dirname(DATA_PATH), exist_ok=True)
|
||||
@language.setter
|
||||
def language(self, value):
|
||||
self._settings["language"] = value
|
||||
|
||||
if not os.path.isfile(CONFIG_FILE) or os.stat(CONFIG_FILE).st_size == 0:
|
||||
write_settings(get_default_settings())
|
||||
@property
|
||||
def load_last_config(self):
|
||||
return self._settings.get("load_last_config", False)
|
||||
|
||||
with open(CONFIG_FILE, "r") as config_file:
|
||||
return json.load(config_file)
|
||||
@load_last_config.setter
|
||||
def load_last_config(self, value):
|
||||
self._settings["load_last_config"] = value
|
||||
|
||||
@property
|
||||
def show_srv_hints(self):
|
||||
""" Show short info as hints in the main services list. """
|
||||
return self._settings.get("show_srv_hints", True)
|
||||
|
||||
def write_settings(config):
|
||||
with open(CONFIG_FILE, "w") as config_file:
|
||||
json.dump(config, config_file, indent=" ")
|
||||
@show_srv_hints.setter
|
||||
def show_srv_hints(self, value):
|
||||
self._settings["show_srv_hints"] = value
|
||||
|
||||
@property
|
||||
def show_bq_hints(self):
|
||||
""" Show detailed info as hints in the bouquet list. """
|
||||
return self._settings.get("show_bq_hints", True)
|
||||
|
||||
@show_bq_hints.setter
|
||||
def show_bq_hints(self, value):
|
||||
self._settings["show_bq_hints"] = value
|
||||
|
||||
# *********** Appearance *********** #
|
||||
|
||||
@property
|
||||
def is_themes_support(self):
|
||||
return self._settings.get("is_themes_support", False)
|
||||
|
||||
@is_themes_support.setter
|
||||
def is_themes_support(self, value):
|
||||
self._settings["is_themes_support"] = value
|
||||
|
||||
@property
|
||||
def theme(self):
|
||||
return self._settings.get("theme", "Default")
|
||||
|
||||
@theme.setter
|
||||
def theme(self, value):
|
||||
self._settings["theme"] = value
|
||||
|
||||
@property
|
||||
@lru_cache(1)
|
||||
def themes_path(self):
|
||||
return "{}/.themes/".format(HOME_PATH)
|
||||
|
||||
@property
|
||||
def icon_theme(self):
|
||||
return self._settings.get("icon_theme", "Adwaita")
|
||||
|
||||
@icon_theme.setter
|
||||
def icon_theme(self, value):
|
||||
self._settings["icon_theme"] = value
|
||||
|
||||
@property
|
||||
@lru_cache(1)
|
||||
def icon_themes_path(self):
|
||||
return "{}/.icons/".format(HOME_PATH)
|
||||
|
||||
@property
|
||||
def is_darwin(self):
|
||||
return IS_DARWIN
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
from urllib.request import urlopen
|
||||
|
||||
from app.commons import run_task, log
|
||||
from app.commons import run_task, log, _DATE_FORMAT
|
||||
from app.settings import PlayStreamsMode
|
||||
|
||||
|
||||
class Player:
|
||||
__VLC_INSTANCE = None
|
||||
__PLAY_STREAMS_MODE = PlayStreamsMode.BUILT_IN
|
||||
|
||||
def __init__(self, rewind_callback, position_callback, error_callback, playing_callback):
|
||||
try:
|
||||
@@ -44,6 +51,10 @@ class Player:
|
||||
cls.__VLC_INSTANCE = Player(rewind_callback, position_callback, error_callback, playing_callback)
|
||||
return cls.__VLC_INSTANCE
|
||||
|
||||
@staticmethod
|
||||
def get_play_mode():
|
||||
return Player.__PLAY_STREAMS_MODE
|
||||
|
||||
@run_task
|
||||
def play(self, mrl=None):
|
||||
if mrl:
|
||||
@@ -103,5 +114,157 @@ class Player:
|
||||
self._player.set_fullscreen(full)
|
||||
|
||||
|
||||
class HttpPlayer:
|
||||
""" Simple wrapper for VLC media player to interact over http. """
|
||||
|
||||
__VLC_INSTANCE = None
|
||||
__PLAY_STREAMS_MODE = PlayStreamsMode.VLC
|
||||
|
||||
class Commands(Enum):
|
||||
STATUS = "http://127.0.0.1:{}/requests/status.xml"
|
||||
PLAY = "http://127.0.0.1:{}/requests/status.xml?command=in_play&input={}"
|
||||
STOP = "http://127.0.0.1:{}/requests/status.xml?command=pl_stop"
|
||||
CLEAR = "http://127.0.0.1:{}/requests/status.xml?command=pl_empty"
|
||||
|
||||
def __init__(self, exe, port, is_darwin):
|
||||
from concurrent.futures import ThreadPoolExecutor as PoolExecutor
|
||||
|
||||
self._executor = PoolExecutor(max_workers=1)
|
||||
self._cmd = [exe, "--no-stats", "--verbose=-1", "--extraintf", "http", "--http-port", port, "--quiet"]
|
||||
if not is_darwin:
|
||||
self._cmd.append("--one-instance")
|
||||
|
||||
self._p = None
|
||||
self._state = None
|
||||
self._port = port
|
||||
|
||||
@classmethod
|
||||
def get_instance(cls, settings):
|
||||
if not cls.__VLC_INSTANCE:
|
||||
import shutil
|
||||
|
||||
is_darwin = settings.is_darwin
|
||||
# TODO Add options[vlc_exe and port] to the settings!
|
||||
exe = "/Applications/VLC.app/Contents/MacOS/VLC" if is_darwin else "/usr/bin/vlc"
|
||||
if shutil.which(exe) is None:
|
||||
raise ImportError
|
||||
cls.__VLC_INSTANCE = HttpPlayer(exe=exe, port=str(9090), is_darwin=is_darwin)
|
||||
return cls.__VLC_INSTANCE
|
||||
|
||||
@staticmethod
|
||||
def get_play_mode():
|
||||
return HttpPlayer.__PLAY_STREAMS_MODE
|
||||
|
||||
@run_task
|
||||
def play(self, mrl=None):
|
||||
if not self._p or self._p and self._p.poll() is not None:
|
||||
self._p = subprocess.Popen(self._cmd + [mrl], preexec_fn=os.setsid)
|
||||
self._p.communicate()
|
||||
else:
|
||||
self._executor.submit(self.open_command, self.Commands.CLEAR)
|
||||
self._executor.submit(self.open_command, self.Commands.PLAY, mrl)
|
||||
|
||||
def open_command(self, command, url=None):
|
||||
if command is self.Commands.PLAY:
|
||||
url = self.Commands.PLAY.value.format(self._port, url)
|
||||
else:
|
||||
url = command.value.format(self._port)
|
||||
|
||||
try:
|
||||
with urlopen(url, timeout=5) as f:
|
||||
self._state = command
|
||||
except Exception as e:
|
||||
log("{}[open_command, {}] error: {}".format(__class__.__name__, command, e))
|
||||
|
||||
def stop(self):
|
||||
if self._state is self.Commands.PLAY:
|
||||
self._executor.submit(self.open_command, self.Commands.STOP)
|
||||
|
||||
def pause(self):
|
||||
pass
|
||||
|
||||
def set_time(self, time):
|
||||
pass
|
||||
|
||||
@run_task
|
||||
def release(self):
|
||||
if self._p and self._p.poll() is None:
|
||||
import signal
|
||||
# Good explanation here: https://stackoverflow.com/a/4791612
|
||||
os.killpg(os.getpgid(self._p.pid), signal.SIGTERM)
|
||||
|
||||
def is_playing(self):
|
||||
return self._state is self.Commands.PLAY
|
||||
|
||||
def set_full_screen(self, full):
|
||||
pass
|
||||
|
||||
|
||||
class Recorder:
|
||||
__VLC_REC_INSTANCE = None
|
||||
|
||||
_CMD = "sout=#std{{access=file,mux=ts,dst={}.ts}}"
|
||||
_TR_CMD = "sout=#transcode{{{}}}:file{{mux=mp4,dst={}.mp4}}"
|
||||
|
||||
def __init__(self, settings):
|
||||
try:
|
||||
from app.tools import vlc
|
||||
from app.tools.vlc import EventType
|
||||
except OSError as e:
|
||||
log("{}: Load library error: {}".format(__class__.__name__, e))
|
||||
raise ImportError
|
||||
else:
|
||||
self._settings = settings
|
||||
self._is_record = False
|
||||
args = "--quiet {}".format("" if sys.platform == "darwin" else "--no-xlib")
|
||||
self._recorder = vlc.Instance(args).media_player_new()
|
||||
|
||||
@classmethod
|
||||
def get_instance(cls, settings):
|
||||
if not cls.__VLC_REC_INSTANCE:
|
||||
cls.__VLC_REC_INSTANCE = Recorder(settings)
|
||||
return cls.__VLC_REC_INSTANCE
|
||||
|
||||
@run_task
|
||||
def record(self, url, name):
|
||||
if self._recorder:
|
||||
self._recorder.stop()
|
||||
|
||||
path = self._settings.records_path
|
||||
os.makedirs(os.path.dirname(path), exist_ok=True)
|
||||
d_now = datetime.now().strftime(_DATE_FORMAT)
|
||||
path = "{}{}_{}".format(path, name.replace(" ", "_"), d_now.replace(" ", "_"))
|
||||
cmd = self.get_transcoding_cmd(path) if self._settings.activate_transcoding else self._CMD.format(path)
|
||||
media = self._recorder.get_instance().media_new(url, cmd)
|
||||
media.get_mrl()
|
||||
|
||||
self._recorder.set_media(media)
|
||||
self._is_record = True
|
||||
self._recorder.play()
|
||||
log("Record started {}".format(d_now))
|
||||
|
||||
@run_task
|
||||
def stop(self):
|
||||
self._recorder.stop()
|
||||
self._is_record = False
|
||||
log("Recording stopped.")
|
||||
|
||||
def is_record(self):
|
||||
return self._is_record
|
||||
|
||||
@run_task
|
||||
def release(self):
|
||||
if self._recorder:
|
||||
self._recorder.stop()
|
||||
self._recorder.release()
|
||||
self._is_record = False
|
||||
log("Recording stopped. Releasing...")
|
||||
|
||||
def get_transcoding_cmd(self, path):
|
||||
presets = self._settings.transcoding_presets
|
||||
prs = presets.get(self._settings.active_preset)
|
||||
return self._TR_CMD.format(",".join("{}={}".format(k, v) for k, v in prs.items()), path)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pass
|
||||
|
||||
@@ -125,7 +125,7 @@ class ProviderParser(HTMLParser):
|
||||
_POSITION_PATTERN = re.compile("at\s\d+\..*(?:E|W)']")
|
||||
_ONID_TID_PATTERN = re.compile("^\d+-\d+.*")
|
||||
_TRANSPONDER_FREQUENCY_PATTERN = re.compile("^\d+ [HVLR]+")
|
||||
_DOMAIN = "https://www.lyngsat.com"
|
||||
_DOMAIN = "http://www.lyngsat.com"
|
||||
_TV_DOMAIN = _DOMAIN + "/tvchannels/"
|
||||
_RADIO_DOMAIN = _DOMAIN + "/radiochannels/"
|
||||
_PKG_DOMAIN = _DOMAIN + "/packages/"
|
||||
|
||||
@@ -99,6 +99,7 @@ class SatellitesParser(HTMLParser):
|
||||
return list(map(get_sat, filter(lambda x: all(x) and len(x) == 5, self._rows)))
|
||||
elif self._source is SatelliteSource.LYNGSAT:
|
||||
extra_pattern = re.compile("^https://www\.lyngsat\.com/[\w-]+\.html")
|
||||
base_url = "https://www.lyngsat.com/"
|
||||
sats = []
|
||||
current_pos = "0"
|
||||
for row in filter(lambda x: len(x) in (5, 7, 8), self._rows):
|
||||
@@ -106,8 +107,8 @@ class SatellitesParser(HTMLParser):
|
||||
if r_len == 7:
|
||||
current_pos = self.parse_position(row[2])
|
||||
name = row[1].rsplit("/")[-1].rstrip(".html").replace("-", " ")
|
||||
sats.append((name, current_pos, row[5], row[1], False)) # coupled [all in one] satellites
|
||||
sats.append((row[4], current_pos, row[5], row[3], False))
|
||||
sats.append((name, current_pos, row[5], base_url + row[1], False)) # [all in one] satellites
|
||||
sats.append((row[4], current_pos, row[5], base_url + row[3], False))
|
||||
if r_len == 8: # for a very limited number of satellites
|
||||
data = list(filter(None, row))
|
||||
urls = set()
|
||||
@@ -121,9 +122,9 @@ class SatellitesParser(HTMLParser):
|
||||
current_pos = self.parse_position(data[1])
|
||||
for url in urls:
|
||||
name = url.rsplit("/")[-1].rstrip(".html").replace("-", " ")
|
||||
sats.append((name, current_pos, sat_type, url, False))
|
||||
sats.append((name, current_pos, sat_type, base_url + url, False))
|
||||
elif r_len == 5:
|
||||
sats.append((row[2], current_pos, row[3], row[1], False))
|
||||
sats.append((row[2], current_pos, row[3], base_url + row[1], False))
|
||||
return sats
|
||||
|
||||
def get_satellite(self, sat):
|
||||
|
||||
@@ -67,7 +67,7 @@ class YouTube:
|
||||
|
||||
if fmts:
|
||||
urls = {Quality[i["itag"]]: i["url"] for i in
|
||||
filter(lambda i: i.get("itag", -1) in Quality, fmts)}
|
||||
filter(lambda i: i.get("itag", -1) in Quality, fmts) if "url" in i}
|
||||
|
||||
if urls and title:
|
||||
return urls, title.replace("+", " ")
|
||||
@@ -121,7 +121,8 @@ class PlayListParser(HTMLParser):
|
||||
|
||||
ct = resp.get("contents", None)
|
||||
if ct:
|
||||
for d in [(d["title"]["simpleText"], d["videoId"]) for d in flat("playlistVideoRenderer", ct)]:
|
||||
for d in [(d.get("title", {}).get("simpleText", ""),
|
||||
d.get("videoId", "")) for d in flat("playlistVideoRenderer", ct)]:
|
||||
self._playlist.append(d)
|
||||
self._is_script = False
|
||||
|
||||
|
||||
143
app/ui/app_menu_bar.ui
Normal file
143
app/ui/app_menu_bar.ui
Normal file
@@ -0,0 +1,143 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<menu id="app-menu">
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">About</attribute>
|
||||
<attribute name="action">app.on_about_app</attribute>
|
||||
</item>
|
||||
</section>
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Settings</attribute>
|
||||
<attribute name="action">app.on_settings</attribute>
|
||||
</item>
|
||||
</section>
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Exit</attribute>
|
||||
<attribute name="action">app.on_close_app</attribute>
|
||||
</item>
|
||||
</section>
|
||||
</menu>
|
||||
<menu id="menu_bar">
|
||||
<submenu>
|
||||
<attribute name="label" translatable="yes">File</attribute>
|
||||
<section>
|
||||
<submenu>
|
||||
<attribute name="label" translatable="yes">Import</attribute>
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Bouquet</attribute>
|
||||
<attribute name="action">app.on_import_bouquet</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Bouquets and services</attribute>
|
||||
<attribute name="action">app.on_import_bouquets</attribute>
|
||||
</item>
|
||||
</section>
|
||||
</submenu>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">New empty configuration</attribute>
|
||||
<attribute name="action">app.on_new_configuration</attribute>
|
||||
</item>
|
||||
</section>
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Open</attribute>
|
||||
<attribute name="action">app.on_data_open</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Save</attribute>
|
||||
<attribute name="action">app.on_data_save</attribute>
|
||||
</item>
|
||||
</section>
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">FTP-transfer</attribute>
|
||||
<attribute name="action">app.on_download</attribute>
|
||||
</item>
|
||||
</section>
|
||||
</submenu>
|
||||
<submenu>
|
||||
<attribute name="label" translatable="yes">Edit</attribute>
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Lock</attribute>
|
||||
<attribute name="action">app.on_locked</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Hide</attribute>
|
||||
<attribute name="action">app.on_hide</attribute>
|
||||
</item>
|
||||
</section>
|
||||
</submenu>
|
||||
<submenu>
|
||||
<attribute name="label" translatable="yes">View</attribute>
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Search</attribute>
|
||||
<attribute name="action">win.search</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Filter</attribute>
|
||||
<attribute name="action">win.filter</attribute>
|
||||
</item>
|
||||
</section>
|
||||
</submenu>
|
||||
<submenu>
|
||||
<attribute name="label" translatable="yes">Tools</attribute>
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Satellites editor</attribute>
|
||||
<attribute name="action">app.on_satellite_editor_show</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Picons manager</attribute>
|
||||
<attribute name="action">app.on_picons_manager_show</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Backups</attribute>
|
||||
<attribute name="action">app.on_backup_tool_show</attribute>
|
||||
</item>
|
||||
</section>
|
||||
<section id="telnet_section">
|
||||
</section>
|
||||
</submenu>
|
||||
<submenu>
|
||||
<attribute name="label" translatable="yes">IPTV</attribute>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Add IPTV or stream service</attribute>
|
||||
<attribute name="action">app.on_iptv</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Import YouTube playlist</attribute>
|
||||
<attribute name="action">app.on_import_yt_list</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Import m3u</attribute>
|
||||
<attribute name="action">app.on_import_m3u</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Export to m3u</attribute>
|
||||
<attribute name="action">app.on_export_to_m3u</attribute>
|
||||
</item>
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">EPG configuration</attribute>
|
||||
<attribute name="action">app.on_epg_list_configuration</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">List configuration</attribute>
|
||||
<attribute name="action">app.on_iptv_list_configuration</attribute>
|
||||
</item>
|
||||
</section>
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">Remove all unavailable</attribute>
|
||||
<attribute name="action">app.on_remove_all_unavailable</attribute>
|
||||
</item>
|
||||
</section>
|
||||
</submenu>
|
||||
</menu>
|
||||
</interface>
|
||||
@@ -10,7 +10,7 @@ from app.commons import run_idle
|
||||
from app.settings import SettingsType
|
||||
from app.ui.dialogs import show_dialog, DialogType
|
||||
from app.ui.main_helper import append_text_to_tview
|
||||
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, KeyboardKey
|
||||
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, KeyboardKey, MOD_MASK
|
||||
|
||||
|
||||
class RestoreType(Enum):
|
||||
@@ -175,7 +175,7 @@ class BackupDialog:
|
||||
if not KeyboardKey.value_exist(key_code):
|
||||
return
|
||||
key = KeyboardKey(key_code)
|
||||
ctrl = event.state & Gdk.ModifierType.CONTROL_MASK
|
||||
ctrl = event.state & MOD_MASK
|
||||
|
||||
if key is KeyboardKey.DELETE:
|
||||
self.on_remove(view)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018 Dmitriy Yefremov
|
||||
Copyright (c) 2018-2020 Dmitriy Yefremov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -31,8 +31,14 @@ Author: Dmitriy Yefremov
|
||||
<!-- interface-license-type mit -->
|
||||
<!-- interface-name DemonEditor -->
|
||||
<!-- interface-description Enigma2 channel and satellites list editor for GNU/Linux. -->
|
||||
<!-- interface-copyright 2018 Dmitriy Yefremov -->
|
||||
<!-- interface-copyright 2018-2020 Dmitriy Yefremov -->
|
||||
<!-- interface-authors Dmitriy Yefremov -->
|
||||
<object class="GtkImage" id="details_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">emblem-important-symbolic</property>
|
||||
<property name="icon_size">1</property>
|
||||
</object>
|
||||
<object class="GtkListStore" id="main_list_store">
|
||||
<columns>
|
||||
<!-- column-name date -->
|
||||
@@ -41,131 +47,89 @@ Author: Dmitriy Yefremov
|
||||
<column type="gboolean"/>
|
||||
</columns>
|
||||
</object>
|
||||
<object class="GtkMenu" id="popup_menu">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="restore_bouquets_popup_menu_item">
|
||||
<property name="label" translatable="yes">Restore bouquets</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_stock">False</property>
|
||||
<signal name="activate" handler="on_restore_bouquets" swapped="no"/>
|
||||
<accelerator key="r" signal="activate" modifiers="Primary"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="restore_all_popup_menu_item">
|
||||
<property name="label" translatable="yes">Restore all</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_stock">False</property>
|
||||
<signal name="activate" handler="on_restore_all" swapped="no"/>
|
||||
<accelerator key="e" signal="activate" modifiers="Primary"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparatorMenuItem" id="popup_menu_separator">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="remove_popup_menu_item">
|
||||
<property name="label">gtk-remove</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="activate" handler="on_remove" swapped="no"/>
|
||||
<accelerator key="Delete" signal="activate"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkImage" id="remove_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">user-trash-symbolic</property>
|
||||
<property name="icon_size">1</property>
|
||||
</object>
|
||||
<object class="GtkImage" id="restore_all_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">edit-select-all-symbolic</property>
|
||||
<property name="icon_size">1</property>
|
||||
</object>
|
||||
<object class="GtkImage" id="restore_bouquets_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">document-revert-symbolic</property>
|
||||
<property name="icon_size">1</property>
|
||||
</object>
|
||||
<object class="GtkWindow" id="dialog_window">
|
||||
<property name="width_request">560</property>
|
||||
<property name="height_request">320</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="title" translatable="yes">Backups</property>
|
||||
<property name="modal">True</property>
|
||||
<property name="window_position">center-on-parent</property>
|
||||
<property name="destroy_with_parent">True</property>
|
||||
<property name="icon_name">document-revert</property>
|
||||
<property name="gravity">center</property>
|
||||
<signal name="check-resize" handler="on_resize" swapped="no"/>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar" id="header_bar">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="title" translatable="yes">Backups</property>
|
||||
<property name="spacing">2</property>
|
||||
<property name="show_close_button">True</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="header_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">2</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="restore_bouquets_header_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Restore bouquets</property>
|
||||
<signal name="clicked" handler="on_restore_bouquets" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="restore_bouquets_header_button_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">document-revert</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="restore_all_header_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Restore all</property>
|
||||
<signal name="clicked" handler="on_restore_all" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="restore_all_header_button_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">edit-select-all</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparator">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="remove_header_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Remove</property>
|
||||
<signal name="clicked" handler="on_remove" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="remove_button_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">user-trash</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="info_check_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="draw_indicator">False</property>
|
||||
<signal name="toggled" handler="on_info_button_toggled" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="info_check_button_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-dialog-info</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="main_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">1</property>
|
||||
<property name="margin_right">1</property>
|
||||
<property name="margin_top">1</property>
|
||||
<property name="margin_bottom">1</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">5</property>
|
||||
<child>
|
||||
<object class="GtkPaned" id="main_paned">
|
||||
<property name="visible">True</property>
|
||||
@@ -249,6 +213,106 @@ Author: Dmitriy Yefremov
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">15</property>
|
||||
<property name="margin_right">15</property>
|
||||
<child>
|
||||
<object class="GtkButtonBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="margin_top">10</property>
|
||||
<property name="margin_bottom">10</property>
|
||||
<property name="layout_style">expand</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="restore_bouquets_header_button">
|
||||
<property name="label" translatable="yes">Restore bouquets</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="image">restore_bouquets_image</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="clicked" handler="on_restore_bouquets" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="restore_all_header_button">
|
||||
<property name="label" translatable="yes">Restore all</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="image">restore_all_image</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="clicked" handler="on_restore_all" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="remove_header_button">
|
||||
<property name="label" translatable="yes">Remove</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="image">remove_image</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="clicked" handler="on_remove" swapped="no"/>
|
||||
<accelerator key="Delete" signal="clicked"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="info_check_button">
|
||||
<property name="label" translatable="yes">Details</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="image">details_image</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<property name="draw_indicator">False</property>
|
||||
<signal name="toggled" handler="on_info_button_toggled" swapped="no"/>
|
||||
<accelerator key="i" signal="clicked" modifiers="Primary"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkInfoBar" id="info_bar">
|
||||
<property name="can_focus">False</property>
|
||||
@@ -299,57 +363,4 @@ Author: Dmitriy Yefremov
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkImage" id="restore_popup_menu_item_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-revert-to-saved</property>
|
||||
</object>
|
||||
<object class="GtkImage" id="restore_popup_menu_item_image2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-select-all</property>
|
||||
</object>
|
||||
<object class="GtkMenu" id="popup_menu">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="restore_bouquets_popup_menu_item">
|
||||
<property name="label" translatable="yes">Restore bouquets</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="image">restore_popup_menu_item_image</property>
|
||||
<property name="use_stock">False</property>
|
||||
<signal name="activate" handler="on_restore_bouquets" swapped="no"/>
|
||||
<accelerator key="r" signal="activate" modifiers="GDK_CONTROL_MASK"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="restore_all_popup_menu_item">
|
||||
<property name="label" translatable="yes">Restore all</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="image">restore_popup_menu_item_image2</property>
|
||||
<property name="use_stock">False</property>
|
||||
<signal name="activate" handler="on_restore_all" swapped="no"/>
|
||||
<accelerator key="e" signal="activate" modifiers="GDK_CONTROL_MASK"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparatorMenuItem" id="popup_menu_separator">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="remove_popup_menu_item">
|
||||
<property name="label">gtk-remove</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="activate" handler="on_remove" swapped="no"/>
|
||||
<accelerator key="Delete" signal="activate"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
|
||||
34
app/ui/default_style.css
Normal file
34
app/ui/default_style.css
Normal file
@@ -0,0 +1,34 @@
|
||||
* {
|
||||
-GtkDialog-action-area-border: 5em;
|
||||
}
|
||||
|
||||
entry {
|
||||
min-height: 2em;
|
||||
}
|
||||
|
||||
button {
|
||||
min-height: 1.5em;
|
||||
padding: 0.1em;
|
||||
}
|
||||
|
||||
spinbutton {
|
||||
min-height: 1.5em;
|
||||
}
|
||||
|
||||
toolbutton {
|
||||
padding: 0.1em;
|
||||
}
|
||||
|
||||
spinner {
|
||||
padding-left: 1em;
|
||||
padding-right: 1em;
|
||||
}
|
||||
|
||||
infobar {
|
||||
min-height: 2em;
|
||||
}
|
||||
|
||||
switch slider {
|
||||
min-height: 1.5em;
|
||||
min-width: 1.5em;
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018 Dmitriy Yefremov
|
||||
Copyright (c) 2018-2020 Dmitriy Yefremov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -26,12 +26,12 @@ THE SOFTWARE.
|
||||
Author: Dmitriy Yefremov
|
||||
|
||||
-->
|
||||
<interface>
|
||||
<interface domain="demon-editor">
|
||||
<requires lib="gtk+" version="3.16"/>
|
||||
<!-- interface-license-type mit -->
|
||||
<!-- interface-name DemonEditor -->
|
||||
<!-- interface-description Enigma2 channel and satellites list editor for GNU/Linux. -->
|
||||
<!-- interface-copyright 2018 Dmitriy Yefremov -->
|
||||
<!-- interface-description Enigma2 channel and satellites list editor for macOS. -->
|
||||
<!-- interface-copyright 2018-2020 Dmitriy Yefremov -->
|
||||
<!-- interface-authors Dmitriy Yefremov -->
|
||||
<object class="GtkAboutDialog" id="about_dialog">
|
||||
<property name="can_focus">False</property>
|
||||
@@ -40,11 +40,12 @@ Author: Dmitriy Yefremov
|
||||
<property name="icon_name">system-help</property>
|
||||
<property name="type_hint">normal</property>
|
||||
<property name="program_name">DemonEditor</property>
|
||||
<property name="version">0.4.7 Pre-alpha</property>
|
||||
<property name="version">0.4.8 Pre-alpha</property>
|
||||
<property name="copyright">2018-2020 Dmitriy Yefremov
|
||||
</property>
|
||||
<property name="comments" translatable="yes">Enigma2 channel and satellites list editor for GNU/Linux</property>
|
||||
<property name="website">https://dyefremov.github.io/DemonEditor/</property>
|
||||
<property name="comments" translatable="yes">Enigma2 channel and satellites list editor for MacOS.
|
||||
(Experimental)</property>
|
||||
<property name="website">https://github.com/DYefremov/DemonEditor/tree/experimental-mac</property>
|
||||
<property name="license" translatable="yes">Это приложение распространяется без каких-либо гарантий.
|
||||
Подробнее в <a href="http://opensource.org/licenses/mit-license.php">The MIT License (MIT)</a>.</property>
|
||||
<property name="authors">Dmitriy Yefremov
|
||||
@@ -97,7 +98,6 @@ Author: Dmitriy Yefremov
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="always_show_image">True</property>
|
||||
</object>
|
||||
</child>
|
||||
<child type="action">
|
||||
@@ -107,7 +107,6 @@ Author: Dmitriy Yefremov
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="always_show_image">True</property>
|
||||
</object>
|
||||
</child>
|
||||
<child internal-child="vbox">
|
||||
@@ -194,6 +193,8 @@ Author: Dmitriy Yefremov
|
||||
<object class="GtkLabel" id="wait_dialog_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">10</property>
|
||||
<property name="margin_right">10</property>
|
||||
<property name="label" translatable="yes">Loading data...</property>
|
||||
</object>
|
||||
<packing>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
""" Common module for showing dialogs """
|
||||
import locale
|
||||
import gettext
|
||||
from enum import Enum
|
||||
from functools import lru_cache
|
||||
|
||||
@@ -52,12 +52,17 @@ class WaitDialog:
|
||||
builder, dialog = get_dialog_from_xml(DialogType.WAIT, transient)
|
||||
self._dialog = dialog
|
||||
self._dialog.set_transient_for(transient)
|
||||
if text is not None:
|
||||
builder.get_object("wait_dialog_label").set_text(text)
|
||||
self._label = builder.get_object("wait_dialog_label")
|
||||
self._default_text = text or self._label.get_text()
|
||||
|
||||
def show(self):
|
||||
def show(self, text=None):
|
||||
self.set_text(text)
|
||||
self._dialog.show()
|
||||
|
||||
@run_idle
|
||||
def set_text(self, text):
|
||||
self._label.set_text(get_message(text or self._default_text))
|
||||
|
||||
@run_idle
|
||||
def hide(self):
|
||||
self._dialog.hide()
|
||||
@@ -81,10 +86,11 @@ def show_dialog(dialog_type: DialogType, transient, text=None, settings=None, ac
|
||||
return get_about_dialog(transient)
|
||||
|
||||
|
||||
def get_chooser_dialog(transient, settings, pattern, name):
|
||||
def get_chooser_dialog(transient, settings, name, patterns):
|
||||
file_filter = Gtk.FileFilter()
|
||||
file_filter.add_pattern(pattern)
|
||||
file_filter.set_name(name)
|
||||
for p in patterns:
|
||||
file_filter.add_pattern(p)
|
||||
|
||||
return show_dialog(dialog_type=DialogType.CHOOSER,
|
||||
transient=transient,
|
||||
@@ -94,17 +100,21 @@ def get_chooser_dialog(transient, settings, pattern, name):
|
||||
|
||||
|
||||
def get_file_chooser_dialog(transient, text, settings, action_type, file_filter):
|
||||
dialog = Gtk.FileChooserDialog(get_message(text) if text else "", transient,
|
||||
action_type if action_type is not None else Gtk.FileChooserAction.SELECT_FOLDER,
|
||||
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK),
|
||||
use_header_bar=IS_GNOME_SESSION)
|
||||
dialog = Gtk.FileChooserNative()
|
||||
dialog.set_title(get_message(text) if text else "")
|
||||
dialog.set_transient_for(transient)
|
||||
dialog.set_action(action_type if action_type is not None else Gtk.FileChooserAction.SELECT_FOLDER)
|
||||
dialog.set_create_folders(False)
|
||||
dialog.set_modal(True)
|
||||
|
||||
if file_filter is not None:
|
||||
dialog.add_filter(file_filter)
|
||||
|
||||
path = settings.data_local_path
|
||||
dialog.set_current_folder(path)
|
||||
response = dialog.run()
|
||||
if response == Gtk.ResponseType.OK:
|
||||
|
||||
if response == Gtk.ResponseType.ACCEPT:
|
||||
if dialog.get_filename():
|
||||
path = dialog.get_filename()
|
||||
if action_type is not Gtk.FileChooserAction.OPEN:
|
||||
@@ -163,7 +173,7 @@ def get_dialog_from_xml(dialog_type, transient, use_header=0, title=""):
|
||||
|
||||
def get_message(message):
|
||||
""" returns translated message """
|
||||
return locale.dgettext(TEXT_DOMAIN, message)
|
||||
return gettext.dgettext(TEXT_DOMAIN, message)
|
||||
|
||||
|
||||
@lru_cache(maxsize=5)
|
||||
|
||||
505
app/ui/download_dialog.glade
Normal file → Executable file
505
app/ui/download_dialog.glade
Normal file → Executable file
@@ -3,7 +3,7 @@
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018 Dmitriy Yefremov
|
||||
Copyright (c) 2018-2020 Dmitriy Yefremov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -30,12 +30,25 @@ Author: Dmitriy Yefremov
|
||||
<requires lib="gtk+" version="3.16"/>
|
||||
<!-- interface-license-type mit -->
|
||||
<!-- interface-name DemonEditor -->
|
||||
<!-- interface-description Enigma2 channel and satellites list editor for GNU/Linux. -->
|
||||
<!-- interface-copyright 2018 Dmitriy Yefremov -->
|
||||
<!-- interface-description Enigma2 channel and satellites list editor for macOS. -->
|
||||
<!-- interface-copyright 2018-2020 Dmitriy Yefremov -->
|
||||
<!-- interface-authors Dmitriy Yefremov -->
|
||||
<object class="GtkImage" id="download_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">network-receive-symbolic</property>
|
||||
<property name="icon_size">1</property>
|
||||
</object>
|
||||
<object class="GtkImage" id="send_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">network-transmit-symbolic</property>
|
||||
<property name="icon_size">1</property>
|
||||
</object>
|
||||
<object class="GtkWindow" id="download_dialog_window">
|
||||
<property name="width_request">500</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="title" translatable="yes">FTP-transfer</property>
|
||||
<property name="resizable">False</property>
|
||||
<property name="modal">True</property>
|
||||
<property name="window_position">center-on-parent</property>
|
||||
@@ -43,251 +56,30 @@ Author: Dmitriy Yefremov
|
||||
<property name="skip_taskbar_hint">True</property>
|
||||
<property name="skip_pager_hint">True</property>
|
||||
<property name="gravity">center</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar" id="header_bar">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="title" translatable="yes">FTP-transfer</property>
|
||||
<property name="spacing">5</property>
|
||||
<property name="show_close_button">True</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="header_left_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">2</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="receive_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Receive</property>
|
||||
<signal name="clicked" handler="on_receive" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="receive_button_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-goto-bottom</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="send_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Send</property>
|
||||
<signal name="clicked" handler="on_send" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="send_button_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-goto-top</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="options_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Options</property>
|
||||
<signal name="clicked" handler="on_settings" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-properties</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="main_dialog_box">
|
||||
<property name="visible">True</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="orientation">vertical</property>
|
||||
<property name="spacing">2</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="selection_data_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="margin_top">10</property>
|
||||
<property name="margin_bottom">5</property>
|
||||
<property name="spacing">5</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label10">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkRadioButton" id="all_radio_button">
|
||||
<property name="label" translatable="yes">All</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<property name="group">satellites_radio_button</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkRadioButton" id="bouquets_radio_button">
|
||||
<property name="label" translatable="yes">Bouquets</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<property name="group">satellites_radio_button</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkRadioButton" id="satellites_radio_button">
|
||||
<property name="label" translatable="yes">Satellites</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<property name="group">all_radio_button</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkRadioButton" id="webtv_radio_button">
|
||||
<property name="label" translatable="yes">WebTV</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<property name="group">all_radio_button</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="margin_top">5</property>
|
||||
<property name="margin_bottom">5</property>
|
||||
<property name="spacing">5</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Profile:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="profile_combo_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="focus_on_click">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="margin_top">1</property>
|
||||
<property name="margin_bottom">1</property>
|
||||
<property name="active">0</property>
|
||||
<property name="has_frame">False</property>
|
||||
<property name="has_entry">True</property>
|
||||
<signal name="changed" handler="on_profile_changed" swapped="no"/>
|
||||
<child internal-child="entry">
|
||||
<object class="GtkEntry">
|
||||
<property name="can_focus">True</property>
|
||||
<property name="has_tooltip">True</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="margin_top">1</property>
|
||||
<property name="margin_bottom">1</property>
|
||||
<property name="editable">False</property>
|
||||
<property name="has_frame">False</property>
|
||||
<property name="max_width_chars">9</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkFrame" id="main_settings_box_frame">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">5</property>
|
||||
<property name="margin_right">5</property>
|
||||
<property name="margin_left">10</property>
|
||||
<property name="margin_right">10</property>
|
||||
<property name="margin_top">10</property>
|
||||
<property name="margin_bottom">5</property>
|
||||
<property name="label_xalign">0.019999999552965164</property>
|
||||
<property name="shadow_type">in</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="main_settings_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">5</property>
|
||||
<property name="margin_right">5</property>
|
||||
<property name="margin_left">10</property>
|
||||
<property name="margin_right">10</property>
|
||||
<property name="margin_top">5</property>
|
||||
<property name="margin_bottom">5</property>
|
||||
<property name="orientation">vertical</property>
|
||||
@@ -441,8 +233,8 @@ Author: Dmitriy Yefremov
|
||||
<object class="GtkFrame" id="settings_frame">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">5</property>
|
||||
<property name="margin_right">5</property>
|
||||
<property name="margin_left">10</property>
|
||||
<property name="margin_right">10</property>
|
||||
<property name="margin_top">5</property>
|
||||
<property name="margin_bottom">5</property>
|
||||
<property name="label_xalign">0.019999999552965164</property>
|
||||
@@ -451,8 +243,9 @@ Author: Dmitriy Yefremov
|
||||
<object class="GtkGrid" id="settings_grid">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">5</property>
|
||||
<property name="margin_right">5</property>
|
||||
<property name="margin_left">10</property>
|
||||
<property name="margin_right">10</property>
|
||||
<property name="margin_top">5</property>
|
||||
<property name="margin_bottom">5</property>
|
||||
<property name="row_spacing">2</property>
|
||||
<property name="column_spacing">2</property>
|
||||
@@ -620,6 +413,9 @@ Author: Dmitriy Yefremov
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<style>
|
||||
<class name="group"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
@@ -629,6 +425,229 @@ Author: Dmitriy Yefremov
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkFrame">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">10</property>
|
||||
<property name="margin_right">10</property>
|
||||
<property name="label_xalign">0</property>
|
||||
<property name="shadow_type">in</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="selection_data_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="margin_top">10</property>
|
||||
<property name="margin_bottom">5</property>
|
||||
<property name="spacing">5</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label10">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xalign">0</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkRadioButton" id="all_radio_button">
|
||||
<property name="label" translatable="yes">All</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<property name="group">satellites_radio_button</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkRadioButton" id="bouquets_radio_button">
|
||||
<property name="label" translatable="yes">Bouquets</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<property name="group">satellites_radio_button</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkRadioButton" id="satellites_radio_button">
|
||||
<property name="label" translatable="yes">Satellites</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<property name="group">all_radio_button</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkRadioButton" id="webtv_radio_button">
|
||||
<property name="label" translatable="yes">WebTV</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="draw_indicator">True</property>
|
||||
<property name="group">all_radio_button</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="margin_top">5</property>
|
||||
<property name="margin_bottom">5</property>
|
||||
<property name="spacing">5</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Profile:</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="profile_combo_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="focus_on_click">False</property>
|
||||
<property name="active">0</property>
|
||||
<property name="has_frame">False</property>
|
||||
<signal name="changed" handler="on_profile_changed" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="options_button">
|
||||
<property name="label" translatable="yes">Options</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Options</property>
|
||||
<property name="valign">center</property>
|
||||
<signal name="clicked" handler="on_settings" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label_item">
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButtonBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="margin_left">20</property>
|
||||
<property name="margin_right">20</property>
|
||||
<property name="margin_top">10</property>
|
||||
<property name="margin_bottom">10</property>
|
||||
<property name="homogeneous">True</property>
|
||||
<property name="layout_style">expand</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="receive_button">
|
||||
<property name="label" translatable="yes">Receive</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Receive</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="image">download_image</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="clicked" handler="on_receive" 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="send_button">
|
||||
<property name="label" translatable="yes">Send</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Send</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="image">send_image</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="clicked" handler="on_send" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">6</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkExpander" id="expander">
|
||||
<property name="visible">True</property>
|
||||
@@ -665,7 +684,7 @@ Author: Dmitriy Yefremov
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">4</property>
|
||||
<property name="position">7</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
@@ -721,13 +740,17 @@ Author: Dmitriy Yefremov
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">5</property>
|
||||
<property name="position">8</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkSizeGroup" id="settings_size_group">
|
||||
<widgets>
|
||||
<widget name="ftp_radio_button"/>
|
||||
<widget name="http_radio_button"/>
|
||||
<widget name="telnet_radio_button"/>
|
||||
</widgets>
|
||||
</object>
|
||||
</interface>
|
||||
|
||||
@@ -96,7 +96,7 @@ class DownloadDialog:
|
||||
elif self._satellites_radio_button.get_active():
|
||||
download_type = DownloadType.SATELLITES
|
||||
elif self._webtv_radio_button.get_active():
|
||||
download_type = DownloadType.WEB_TV
|
||||
download_type = DownloadType.WEBTV
|
||||
return download_type
|
||||
|
||||
def destroy(self):
|
||||
@@ -140,6 +140,7 @@ class DownloadDialog:
|
||||
if active in self._settings.profiles:
|
||||
self._settings.current_profile = active
|
||||
self._profile_combo_box.set_active_id(active)
|
||||
self._s_type = self._settings.setting_type
|
||||
self.init_ui_settings()
|
||||
|
||||
def on_info_bar_close(self, bar=None, resp=None):
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018-2019 Dmitriy Yefremov
|
||||
Copyright (c) 2018-2020 Dmitriy Yefremov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -31,8 +31,20 @@ Author: Dmitriy Yefremov
|
||||
<!-- interface-license-type mit -->
|
||||
<!-- interface-name DemonEditor -->
|
||||
<!-- interface-description Enigma2 channel and satellites list editor for GNU/Linux. -->
|
||||
<!-- interface-copyright 2018-2019 Dmitriy Yefremov -->
|
||||
<!-- interface-copyright 2018-2020 Dmitriy Yefremov -->
|
||||
<!-- interface-authors Dmitriy Yefremov -->
|
||||
<object class="GtkImage" id="apply_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">document-save-symbolic</property>
|
||||
<property name="icon_size">1</property>
|
||||
</object>
|
||||
<object class="GtkImage" id="auto_config_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">edit-select-all-symbolic</property>
|
||||
<property name="icon_size">1</property>
|
||||
</object>
|
||||
<object class="GtkListStore" id="bouquet_list_store">
|
||||
<columns>
|
||||
<!-- column-name num -->
|
||||
@@ -75,10 +87,16 @@ Author: Dmitriy Yefremov
|
||||
<property name="image">copy_image</property>
|
||||
<property name="use_stock">False</property>
|
||||
<signal name="activate" handler="on_copy_ref" swapped="no"/>
|
||||
<accelerator key="c" signal="activate" modifiers="GDK_CONTROL_MASK"/>
|
||||
<accelerator key="c" signal="activate"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkImage" id="filter_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">edit-find-replace-symbolic</property>
|
||||
<property name="icon_size">1</property>
|
||||
</object>
|
||||
<object class="GtkImage" id="insert_link_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
@@ -100,7 +118,7 @@ Author: Dmitriy Yefremov
|
||||
<property name="image">insert_link_image</property>
|
||||
<property name="use_stock">False</property>
|
||||
<signal name="activate" handler="on_assign_ref" swapped="no"/>
|
||||
<accelerator key="v" signal="activate" modifiers="GDK_CONTROL_MASK"/>
|
||||
<accelerator key="v" signal="activate"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
@@ -130,6 +148,12 @@ Author: Dmitriy Yefremov
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkImage" id="save_to_xml_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">document-save-as-symbolic</property>
|
||||
<property name="icon_size">1</property>
|
||||
</object>
|
||||
<object class="GtkListStore" id="services_list_store">
|
||||
<columns>
|
||||
<!-- column-name service -->
|
||||
@@ -559,58 +583,104 @@ Author: Dmitriy Yefremov
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkImage" id="update_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">emblem-synchronizing-symbolic</property>
|
||||
<property name="icon_size">1</property>
|
||||
</object>
|
||||
<object class="GtkWindow" id="epg_dialog_window">
|
||||
<property name="width_request">480</property>
|
||||
<property name="height_request">320</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="title" translatable="yes">EPG</property>
|
||||
<property name="modal">True</property>
|
||||
<property name="window_position">center-on-parent</property>
|
||||
<property name="default_width">480</property>
|
||||
<property name="default_height">240</property>
|
||||
<property name="default_height">320</property>
|
||||
<property name="destroy_with_parent">True</property>
|
||||
<property name="icon_name">gtk-index</property>
|
||||
<property name="skip_taskbar_hint">True</property>
|
||||
<property name="skip_pager_hint">True</property>
|
||||
<property name="gravity">center</property>
|
||||
<signal name="check-resize" handler="on_resize" swapped="no"/>
|
||||
<signal name="delete-event" handler="on_close_dialog" swapped="no"/>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar" id="header_bar">
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="main_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="title" translatable="yes">EPG</property>
|
||||
<property name="subtitle" translatable="yes">List configuration</property>
|
||||
<property name="spacing">2</property>
|
||||
<property name="show_close_button">True</property>
|
||||
<property name="margin_left">1</property>
|
||||
<property name="margin_right">1</property>
|
||||
<property name="margin_bottom">1</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="left_header_box">
|
||||
<object class="GtkBox" id="main_actions_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">2</property>
|
||||
<property name="margin_left">15</property>
|
||||
<property name="margin_right">15</property>
|
||||
<property name="margin_top">10</property>
|
||||
<property name="margin_bottom">10</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="apply_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Apply</property>
|
||||
<signal name="clicked" handler="on_apply" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="apply_button_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-apply</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSeparator">
|
||||
<object class="GtkButtonBox" id="left_action_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="layout_style">expand</property>
|
||||
<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">Apply</property>
|
||||
<property name="image">apply_image</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="clicked" handler="on_apply" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="update_button">
|
||||
<property name="label" translatable="yes">Update</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Update</property>
|
||||
<property name="image">update_image</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="clicked" handler="on_update" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="filter_button">
|
||||
<property name="label" translatable="yes">Filter</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Filter</property>
|
||||
<property name="image">filter_image</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="toggled" handler="on_filter_toggled" swapped="no"/>
|
||||
<accelerator key="f" signal="clicked" modifiers="GDK_SHIFT_MASK | GDK_CONTROL_MASK"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
@@ -618,20 +688,11 @@ Author: Dmitriy Yefremov
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="update_button">
|
||||
<child type="center">
|
||||
<object class="GtkLabel" id="list_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Update</property>
|
||||
<signal name="clicked" handler="on_update" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="update_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-refresh</property>
|
||||
</object>
|
||||
</child>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">List configuration</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
@@ -640,110 +701,106 @@ Author: Dmitriy Yefremov
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="filter_button">
|
||||
<object class="GtkButtonBox" id="right_action_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Filter</property>
|
||||
<signal name="toggled" handler="on_filter_toggled" swapped="no"/>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="layout_style">expand</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="filter_button_image">
|
||||
<object class="GtkButton" id="auto_config_button">
|
||||
<property name="label" translatable="yes">Auto</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-spell-check</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="right_header_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">2</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="auto_config_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Auto configuration by service names.</property>
|
||||
<signal name="clicked" handler="on_auto_configuration" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="auto_config_button_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-find-and-replace</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Auto configuration by service names.</property>
|
||||
<property name="image">auto_config_image</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="clicked" handler="on_auto_configuration" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="save_to_xml_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="tooltip_text" translatable="yes">Save list to xml.</property>
|
||||
<property name="image">save_to_xml_image</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="clicked" handler="on_save_to_xml" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkMenuButton" id="options_menu_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="direction">none</property>
|
||||
<property name="popover">options_popover</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">2</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="options_button_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="tooltip_text" translatable="yes">Options</property>
|
||||
<property name="icon_name">applications-system-symbolic</property>
|
||||
<property name="icon_size">1</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Options</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="save_to_xml_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Save list to xml.</property>
|
||||
<signal name="clicked" handler="on_save_to_xml" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="save_to_xml_button_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-save-as</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkMenuButton" id="options_menu_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="direction">none</property>
|
||||
<property name="popover">options_popover</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="options_button_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="tooltip_text" translatable="yes">Options</property>
|
||||
<property name="stock">gtk-properties</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">1</property>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="main_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkSearchBar" id="filter_bar">
|
||||
<property name="visible">True</property>
|
||||
@@ -752,7 +809,7 @@ Author: Dmitriy Yefremov
|
||||
<object class="GtkSearchEntry" id="filter_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="primary_icon_name">tools-check-spelling</property>
|
||||
<property name="primary_icon_name">edit-find-replace-symbolic</property>
|
||||
<property name="primary_icon_activatable">False</property>
|
||||
<property name="primary_icon_sensitive">False</property>
|
||||
<signal name="search-changed" handler="on_filter_changed" swapped="no"/>
|
||||
@@ -861,13 +918,14 @@ Author: Dmitriy Yefremov
|
||||
<property name="height_request">24</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">2</property>
|
||||
<property name="margin_left">5</property>
|
||||
<property name="spacing">2</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-properties</property>
|
||||
<property name="icon_name">document-properties-symbolic</property>
|
||||
<property name="icon_size">1</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
@@ -889,6 +947,7 @@ Author: Dmitriy Yefremov
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="source_info_box">
|
||||
<property name="height_request">26</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">center</property>
|
||||
@@ -1142,16 +1201,17 @@ Author: Dmitriy Yefremov
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="bouquet_info_bar_box">
|
||||
<property name="height_request">24</property>
|
||||
<property name="height_request">26</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">2</property>
|
||||
<property name="margin_left">5</property>
|
||||
<property name="spacing">2</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-properties</property>
|
||||
<property name="icon_name">document-properties-symbolic</property>
|
||||
<property name="icon_size">1</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
@@ -1188,7 +1248,9 @@ Author: Dmitriy Yefremov
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">2</property>
|
||||
<property name="stock">gtk-index</property>
|
||||
<property name="icon_size">1</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
|
||||
@@ -15,7 +15,7 @@ from app.eparser.ecommons import BouquetService, BqServiceType
|
||||
from app.tools.epg import EPG, ChannelsParser
|
||||
from app.ui.dialogs import get_message, show_dialog, DialogType
|
||||
from .main_helper import on_popup_menu, update_entry_data
|
||||
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, TEXT_DOMAIN, Column, EPG_ICON, KeyboardKey
|
||||
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, TEXT_DOMAIN, Column, EPG_ICON, KeyboardKey, MOD_MASK
|
||||
|
||||
|
||||
class RefsSource(Enum):
|
||||
@@ -279,7 +279,7 @@ class EpgDialog:
|
||||
if not KeyboardKey.value_exist(key_code):
|
||||
return
|
||||
key = KeyboardKey(key_code)
|
||||
ctrl = event.state & Gdk.ModifierType.CONTROL_MASK
|
||||
ctrl = event.state & MOD_MASK
|
||||
|
||||
if ctrl and key is KeyboardKey.C:
|
||||
self.on_copy_ref()
|
||||
@@ -486,7 +486,7 @@ class EpgDialog:
|
||||
epg_dat_path = self._settings.data_local_path + "epg/"
|
||||
self._epg_dat_path_entry.set_text(epg_dat_path)
|
||||
default_epg_data_stb_path = "/etc/enigma2"
|
||||
epg_options = self._settings.get("epg_options")
|
||||
epg_options = self._settings.epg_options
|
||||
if epg_options:
|
||||
self._refs_source = RefsSource.XML if epg_options.get("xml_source", False) else RefsSource.SERVICES
|
||||
self._xml_radiobutton.set_active(self._refs_source is RefsSource.XML)
|
||||
@@ -506,15 +506,14 @@ class EpgDialog:
|
||||
os.makedirs(os.path.dirname(self._epg_dat_path_entry.get_text()), exist_ok=True)
|
||||
|
||||
def on_options_save(self, item=None):
|
||||
epg_options = {"xml_source": self._xml_radiobutton.get_active(),
|
||||
"use_web_source": self._use_web_source_switch.get_active(),
|
||||
"local_path_to_xml": self._xml_chooser_button.get_filename(),
|
||||
"url_to_xml": self._url_to_xml_entry.get_text(),
|
||||
"enable_filtering": self._enable_filtering_switch.get_active(),
|
||||
"epg_dat_path": self._epg_dat_path_entry.get_text(),
|
||||
"epg_dat_stb_path": self._epg_dat_stb_path_entry.get_text(),
|
||||
"epg_data_update_on_start": self._update_on_start_switch.get_active()}
|
||||
self._settings.add("epg_options", epg_options)
|
||||
self._settings.epg_options = {"xml_source": self._xml_radiobutton.get_active(),
|
||||
"use_web_source": self._use_web_source_switch.get_active(),
|
||||
"local_path_to_xml": self._xml_chooser_button.get_filename(),
|
||||
"url_to_xml": self._url_to_xml_entry.get_text(),
|
||||
"enable_filtering": self._enable_filtering_switch.get_active(),
|
||||
"epg_dat_path": self._epg_dat_path_entry.get_text(),
|
||||
"epg_dat_stb_path": self._epg_dat_stb_path_entry.get_text(),
|
||||
"epg_data_update_on_start": self._update_on_start_switch.get_active()}
|
||||
|
||||
def on_resize(self, window):
|
||||
if self._settings:
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018-2019 Dmitriy Yefremov
|
||||
Copyright (c) 2018-2020 Dmitriy Yefremov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -26,13 +26,25 @@ THE SOFTWARE.
|
||||
Author: Dmitriy Yefremov
|
||||
|
||||
-->
|
||||
<interface>
|
||||
<interface domain="demon-editor">
|
||||
<requires lib="gtk+" version="3.16"/>
|
||||
<!-- interface-css-provider-path style.css -->
|
||||
<!-- interface-license-type mit -->
|
||||
<!-- interface-name DemonEditor -->
|
||||
<!-- interface-description Enigma2 channel and satellites list editor for GNU/Linux. -->
|
||||
<!-- interface-copyright 2018-2019 Dmitriy Yefremov -->
|
||||
<!-- interface-description Enigma2 channel and satellites list editor for macOS. -->
|
||||
<!-- interface-copyright 2018-2020 Dmitriy Yefremov -->
|
||||
<!-- interface-authors Dmitriy Yefremov -->
|
||||
<object class="GtkImage" id="details_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">emblem-important-symbolic</property>
|
||||
</object>
|
||||
<object class="GtkImage" id="import_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">document-revert-symbolic-rtl</property>
|
||||
<property name="icon_size">1</property>
|
||||
</object>
|
||||
<object class="GtkListStore" id="main_list_store">
|
||||
<columns>
|
||||
<!-- column-name name -->
|
||||
@@ -82,6 +94,7 @@ Author: Dmitriy Yefremov
|
||||
</object>
|
||||
<object class="GtkWindow" id="dialog_window">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="title" translatable="yes">Import</property>
|
||||
<property name="modal">True</property>
|
||||
<property name="window_position">center-on-parent</property>
|
||||
<property name="default_width">480</property>
|
||||
@@ -90,51 +103,8 @@ Author: Dmitriy Yefremov
|
||||
<property name="type_hint">dialog</property>
|
||||
<property name="gravity">center</property>
|
||||
<signal name="check-resize" handler="on_resize" swapped="no"/>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar" id="header_bar">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="title" translatable="yes">Import</property>
|
||||
<property name="subtitle" translatable="yes">Bouquets and services</property>
|
||||
<property name="spacing">2</property>
|
||||
<property name="show_close_button">True</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="import_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Import</property>
|
||||
<signal name="clicked" handler="on_import" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="import_button_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-revert-to-saved</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="info_check_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="draw_indicator">False</property>
|
||||
<signal name="toggled" handler="on_info_button_toggled" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="info_check_button_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-dialog-info</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="main_box">
|
||||
@@ -159,8 +129,8 @@ Author: Dmitriy Yefremov
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_top">2</property>
|
||||
<property name="margin_bottom">2</property>
|
||||
<property name="margin_top">5</property>
|
||||
<property name="margin_bottom">5</property>
|
||||
<property name="label" translatable="yes">Bouquets</property>
|
||||
</object>
|
||||
<packing>
|
||||
@@ -258,8 +228,8 @@ Author: Dmitriy Yefremov
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_top">2</property>
|
||||
<property name="margin_bottom">2</property>
|
||||
<property name="margin_top">5</property>
|
||||
<property name="margin_bottom">5</property>
|
||||
<property name="label" translatable="yes">Bouquet details</property>
|
||||
</object>
|
||||
<packing>
|
||||
@@ -335,6 +305,62 @@ Author: Dmitriy Yefremov
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButtonBox" id="actions_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="margin_left">15</property>
|
||||
<property name="margin_right">15</property>
|
||||
<property name="margin_top">5</property>
|
||||
<property name="margin_bottom">5</property>
|
||||
<property name="layout_style">start</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="import_button">
|
||||
<property name="label" translatable="yes">Import</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Bouquets and services</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="image">import_image</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="clicked" handler="on_import" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="info_check_button">
|
||||
<property name="label" translatable="yes">Details</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="tooltip_text" translatable="yes">Details</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="image">details_image</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<property name="draw_indicator">False</property>
|
||||
<signal name="toggled" handler="on_info_button_toggled" swapped="no"/>
|
||||
<accelerator key="i" signal="clicked"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
<property name="secondary">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkInfoBar" id="info_bar">
|
||||
<property name="can_focus">False</property>
|
||||
@@ -380,7 +406,7 @@ Author: Dmitriy Yefremov
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
|
||||
@@ -30,7 +30,7 @@ def import_bouquet(transient, model, path, settings, services, appender):
|
||||
elif bq_type is BqType.WEBTV:
|
||||
f_pattern = "webtv.xml"
|
||||
|
||||
file_path = get_chooser_dialog(transient, settings, f_pattern, "bouquet files")
|
||||
file_path = get_chooser_dialog(transient, settings, "bouquet files", (f_pattern,))
|
||||
if file_path == Gtk.ResponseType.CANCEL:
|
||||
return
|
||||
|
||||
|
||||
@@ -33,6 +33,35 @@ Author: Dmitriy Yefremov
|
||||
<!-- interface-description Enigma2 channel and satellites list editor for GNU/Linux. -->
|
||||
<!-- interface-copyright 2018-2019 Dmitriy Yefremov -->
|
||||
<!-- interface-authors Dmitriy Yefremov -->
|
||||
<object class="GtkImage" id="remove_selection_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">edit-undo</property>
|
||||
</object>
|
||||
<object class="GtkMenu" id="yt_popup_menu">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="select_all_popup_item">
|
||||
<property name="label">gtk-select-all</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="activate" handler="on_select_all" object="yt_list_view" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="unselect_all_popup_item">
|
||||
<property name="label" translatable="yes">Remove selection</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="image">remove_selection_image</property>
|
||||
<property name="use_stock">False</property>
|
||||
<signal name="activate" handler="on_unselect_all" object="yt_list_view" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkDialog" id="search_unavailable_streams_dialog">
|
||||
<property name="use-header-bar">1</property>
|
||||
<property name="width_request">320</property>
|
||||
@@ -243,7 +272,6 @@ Author: Dmitriy Yefremov
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="always_show_image">True</property>
|
||||
</object>
|
||||
</child>
|
||||
<child type="action">
|
||||
@@ -252,7 +280,6 @@ Author: Dmitriy Yefremov
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="clicked" handler="on_save" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
@@ -263,7 +290,6 @@ Author: Dmitriy Yefremov
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="clicked" handler="on_save" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
@@ -739,7 +765,6 @@ Author: Dmitriy Yefremov
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="always_show_image">True</property>
|
||||
</object>
|
||||
</child>
|
||||
<child type="action">
|
||||
@@ -749,7 +774,6 @@ Author: Dmitriy Yefremov
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="clicked" handler="on_apply" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
@@ -1221,35 +1245,6 @@ Author: Dmitriy Yefremov
|
||||
<action-widget response="-6">close_config_list_button</action-widget>
|
||||
</action-widgets>
|
||||
</object>
|
||||
<object class="GtkImage" id="remove_selection_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">edit-undo</property>
|
||||
</object>
|
||||
<object class="GtkMenu" id="yt_popup_menu">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="select_all_popup_item">
|
||||
<property name="label">gtk-select-all</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="activate" handler="on_select_all" object="yt_list_view" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="unselect_all_popup_item">
|
||||
<property name="label" translatable="yes">Remove selection</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="image">remove_selection_image</property>
|
||||
<property name="use_stock">False</property>
|
||||
<signal name="activate" handler="on_unselect_all" object="yt_list_view" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkListStore" id="yt_liststore">
|
||||
<columns>
|
||||
<!-- column-name title -->
|
||||
@@ -1279,9 +1274,21 @@ Author: Dmitriy Yefremov
|
||||
</row>
|
||||
</data>
|
||||
</object>
|
||||
<object class="GtkImage" id="yt_receive_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">network-receive-symbolic</property>
|
||||
<property name="icon_size">1</property>
|
||||
</object>
|
||||
<object class="GtkImage" id="yt_import_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">document-revert-symbolic-rtl</property>
|
||||
</object>
|
||||
<object class="GtkWindow" id="yt_import_dialog_window">
|
||||
<property name="width_request">480</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="title" translatable="yes">YouTube</property>
|
||||
<property name="resizable">False</property>
|
||||
<property name="modal">True</property>
|
||||
<property name="window_position">center-on-parent</property>
|
||||
@@ -1290,82 +1297,110 @@ Author: Dmitriy Yefremov
|
||||
<property name="skip_taskbar_hint">True</property>
|
||||
<property name="skip_pager_hint">True</property>
|
||||
<property name="gravity">center</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar" id="yt_header_bar">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="title" translatable="yes">YouTube</property>
|
||||
<property name="subtitle" translatable="yes">Playlist import</property>
|
||||
<property name="spacing">2</property>
|
||||
<property name="show_close_button">True</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="yt_receive_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Receive</property>
|
||||
<signal name="clicked" handler="on_receive" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="yt_receive_button_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-goto-bottom</property>
|
||||
</object>
|
||||
</child>
|
||||
<accelerator key="d" signal="clicked" modifiers="GDK_CONTROL_MASK"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="yt_import_button">
|
||||
<property name="visible">False</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Import</property>
|
||||
<signal name="clicked" handler="on_import" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="yt_import_button_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">insert-link</property>
|
||||
</object>
|
||||
</child>
|
||||
<accelerator key="i" signal="clicked" modifiers="GDK_CONTROL_MASK"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkComboBox" id="yt_quality_combobox">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="tooltip_text" translatable="yes">Desired video quality</property>
|
||||
<property name="model">yt_quality_liststore</property>
|
||||
<property name="active">0</property>
|
||||
<property name="id_column">0</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="yt_quality_renderer"/>
|
||||
<attributes>
|
||||
<attribute name="text">0</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="yt_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="yt_actions_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">15</property>
|
||||
<property name="margin_right">15</property>
|
||||
<property name="margin_top">5</property>
|
||||
<property name="margin_bottom">5</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="yt_receive_button">
|
||||
<property name="label" translatable="yes">Receive</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Receive</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="image">yt_receive_image</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="clicked" handler="on_receive" swapped="no"/>
|
||||
<accelerator key="d" signal="clicked"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child type="center">
|
||||
<object class="GtkLabel" id="playlist_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Playlist import</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButtonBox" id="yt_impotr_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="layout_style">expand</property>
|
||||
<child>
|
||||
<object class="GtkComboBox" id="yt_quality_combobox">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="tooltip_text" translatable="yes">Desired video quality</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="model">yt_quality_liststore</property>
|
||||
<property name="active">0</property>
|
||||
<property name="id_column">0</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="yt_quality_renderer1"/>
|
||||
<attributes>
|
||||
<attribute name="text">0</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="yt_import_button">
|
||||
<property name="label" translatable="yes">Import</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Import</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="image">yt_import_image</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="clicked" handler="on_import" swapped="no"/>
|
||||
<accelerator key="i" signal="clicked"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="yt_url_entry">
|
||||
<property name="visible">True</property>
|
||||
@@ -1380,8 +1415,9 @@ Author: Dmitriy Yefremov
|
||||
<signal name="changed" handler="on_yt_url_entry_changed" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
@@ -1478,7 +1514,7 @@ Author: Dmitriy Yefremov
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="yt_info_bar_box">
|
||||
<property name="height_request">24</property>
|
||||
<property name="height_request">26</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">5</property>
|
||||
<property name="margin_right">10</property>
|
||||
@@ -1492,7 +1528,8 @@ Author: Dmitriy Yefremov
|
||||
<object class="GtkImage" id="yt_count_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-properties</property>
|
||||
<property name="margin_left">5</property>
|
||||
<property name="icon_name">document-properties-symbolic</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
|
||||
@@ -1,23 +1,21 @@
|
||||
import concurrent.futures
|
||||
import glob
|
||||
import os
|
||||
import re
|
||||
import urllib
|
||||
from functools import lru_cache
|
||||
from urllib.error import HTTPError
|
||||
from urllib.parse import urlparse
|
||||
from urllib.request import Request, urlopen
|
||||
|
||||
from gi.repository import GLib
|
||||
|
||||
from app.commons import run_idle, run_task, log
|
||||
from app.commons import run_idle, run_task
|
||||
from app.eparser.ecommons import BqServiceType, Service
|
||||
from app.eparser.iptv import NEUTRINO_FAV_ID_FORMAT, StreamType, ENIGMA2_FAV_ID_FORMAT, get_fav_id, MARKER_FORMAT
|
||||
from app.settings import SettingsType
|
||||
from app.tools.yt import YouTube, PlayListParser
|
||||
from .dialogs import Action, show_dialog, DialogType, get_dialogs_string, get_message
|
||||
from .main_helper import get_base_model, get_iptv_url, on_popup_menu
|
||||
from .uicommons import Gtk, Gdk, TEXT_DOMAIN, UI_RESOURCES_PATH, IPTV_ICON, Column, IS_GNOME_SESSION, KeyboardKey
|
||||
from .uicommons import Gtk, Gdk, TEXT_DOMAIN, UI_RESOURCES_PATH, IPTV_ICON, Column, IS_GNOME_SESSION, KeyboardKey, \
|
||||
get_yt_icon
|
||||
|
||||
_DIGIT_ENTRY_NAME = "digit-entry"
|
||||
_ENIGMA2_REFERENCE = "{}:0:{}:{:X}:{:X}:{:X}:{:X}:0:0:0"
|
||||
@@ -43,22 +41,6 @@ def get_stream_type(box):
|
||||
return StreamType.NONE_REC_2.value
|
||||
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def get_yt_icon(icon_name, size=24):
|
||||
""" Getting YouTube icon. If the icon is not found in the icon themes, the "Info" icon is returned by default! """
|
||||
default_theme = Gtk.IconTheme.get_default()
|
||||
if default_theme.has_icon(icon_name):
|
||||
return default_theme.load_icon(icon_name, size, 0)
|
||||
|
||||
theme = Gtk.IconTheme.new()
|
||||
for theme_name in map(os.path.basename, filter(os.path.isdir, glob.glob("/usr/share/icons/*"))):
|
||||
theme.set_custom_theme(theme_name)
|
||||
if theme.has_icon(icon_name):
|
||||
return theme.load_icon(icon_name, size, 0)
|
||||
|
||||
return default_theme.load_icon("info", size, 0)
|
||||
|
||||
|
||||
class IptvDialog:
|
||||
|
||||
def __init__(self, transient, view, services, bouquet, profile=SettingsType.ENIGMA_2, action=Action.ADD):
|
||||
@@ -575,7 +557,8 @@ class YtListImportDialog:
|
||||
builder.set_translation_domain(TEXT_DOMAIN)
|
||||
builder.add_objects_from_string(get_dialogs_string(_UI_PATH).format(use_header=IS_GNOME_SESSION),
|
||||
("yt_import_dialog_window", "yt_liststore", "yt_quality_liststore",
|
||||
"yt_popup_menu", "remove_selection_image"))
|
||||
"yt_popup_menu", "remove_selection_image", "yt_receive_image",
|
||||
"yt_import_image"))
|
||||
builder.connect_signals(handlers)
|
||||
|
||||
self._dialog = builder.get_object("yt_import_dialog_window")
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
app/ui/lang/pl/LC_MESSAGES/demon-editor.mo
Normal file
BIN
app/ui/lang/pl/LC_MESSAGES/demon-editor.mo
Normal file
Binary file not shown.
Binary file not shown.
BIN
app/ui/lang/tr/LC_MESSAGES/demon-editor.mo
Normal file
BIN
app/ui/lang/tr/LC_MESSAGES/demon-editor.mo
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -362,39 +362,44 @@ def append_picons(picons, model):
|
||||
GLib.idle_add(lambda: next(app, False), priority=GLib.PRIORITY_LOW)
|
||||
|
||||
|
||||
def assign_picon(target, srv_view, fav_view, transient, picons, settings, services):
|
||||
def assign_picon(target, srv_view, fav_view, transient, picons, settings, services, p_path=None):
|
||||
view = srv_view if target is ViewTarget.SERVICES else fav_view
|
||||
model, paths = view.get_selection().get_selected_rows()
|
||||
if not is_only_one_item_selected(paths, transient):
|
||||
return
|
||||
|
||||
response = get_chooser_dialog(transient, settings, "*.png", "png files")
|
||||
if response == Gtk.ResponseType.CANCEL:
|
||||
return
|
||||
if not p_path:
|
||||
p_path = get_chooser_dialog(transient, settings, "*.png files", ("*.png",))
|
||||
if p_path == Gtk.ResponseType.CANCEL:
|
||||
return
|
||||
|
||||
if not str(response).endswith(".png"):
|
||||
if not str(p_path).endswith(".png") or not os.path.isfile(p_path):
|
||||
show_dialog(DialogType.ERROR, transient, text="No png file is selected!")
|
||||
return
|
||||
|
||||
picon_pos = Column.SRV_PICON
|
||||
model = get_base_model(model)
|
||||
itr = model.get_iter(paths)
|
||||
fav_id = model.get_value(itr, Column.SRV_FAV_ID if target is ViewTarget.SERVICES else Column.FAV_ID)
|
||||
picon_id = services.get(fav_id)[Column.SRV_PICON_ID]
|
||||
p_pos = Column.SRV_PICON
|
||||
col_num = Column.SRV_FAV_ID if target is ViewTarget.SERVICES else Column.FAV_ID
|
||||
itrs = [model.get_iter(p) for p in paths]
|
||||
|
||||
if picon_id:
|
||||
if os.path.isfile(response):
|
||||
if target is ViewTarget.SERVICES:
|
||||
f_model = model.get_model()
|
||||
itrs = [f_model.convert_iter_to_child_iter(model.convert_iter_to_child_iter(itr)) for itr in itrs]
|
||||
model = get_base_model(model)
|
||||
|
||||
for itr in itrs:
|
||||
fav_id = model.get_value(itr, col_num)
|
||||
picon_id = services.get(fav_id)[Column.SRV_PICON_ID]
|
||||
|
||||
if picon_id:
|
||||
picons_path = settings.picons_local_path
|
||||
os.makedirs(os.path.dirname(picons_path), exist_ok=True)
|
||||
picon_file = picons_path + picon_id
|
||||
shutil.copy(response, picon_file)
|
||||
shutil.copy(p_path, picon_file)
|
||||
picon = get_picon_pixbuf(picon_file)
|
||||
picons[picon_id] = picon
|
||||
model.set_value(itr, picon_pos, picon)
|
||||
model.set_value(itr, p_pos, picon)
|
||||
if target is ViewTarget.SERVICES:
|
||||
set_picon(fav_id, fav_view.get_model(), picon, Column.FAV_ID, picon_pos)
|
||||
set_picon(fav_id, fav_view.get_model(), picon, Column.FAV_ID, p_pos)
|
||||
else:
|
||||
set_picon(fav_id, get_base_model(srv_view.get_model()), picon, Column.SRV_FAV_ID, picon_pos)
|
||||
set_picon(fav_id, get_base_model(srv_view.get_model()), picon, Column.SRV_FAV_ID, p_pos)
|
||||
|
||||
|
||||
def set_picon(fav_id, model, picon, fav_id_pos, picon_pos):
|
||||
@@ -407,14 +412,19 @@ def set_picon(fav_id, model, picon, fav_id_pos, picon_pos):
|
||||
def remove_picon(target, srv_view, fav_view, picons, settings):
|
||||
view = srv_view if target is ViewTarget.SERVICES else fav_view
|
||||
model, paths = view.get_selection().get_selected_rows()
|
||||
model = get_base_model(model)
|
||||
|
||||
fav_ids = []
|
||||
picon_ids = []
|
||||
picon_pos = Column.SRV_PICON # picon position is equal for services and fav
|
||||
|
||||
for path in paths:
|
||||
itr = model.get_iter(path)
|
||||
itrs = [model.get_iter(p) for p in paths]
|
||||
|
||||
if target is ViewTarget.SERVICES:
|
||||
f_model = model.get_model()
|
||||
itrs = [f_model.convert_iter_to_child_iter(model.convert_iter_to_child_iter(itr)) for itr in itrs]
|
||||
model = get_base_model(model)
|
||||
|
||||
for itr in itrs:
|
||||
model.set_value(itr, picon_pos, None)
|
||||
if target is ViewTarget.SERVICES:
|
||||
fav_ids.append(model.get_value(itr, Column.SRV_FAV_ID))
|
||||
@@ -426,8 +436,10 @@ def remove_picon(target, srv_view, fav_view, picons, settings):
|
||||
else:
|
||||
fav_ids.append(fav_id)
|
||||
|
||||
fav_id_column = Column.FAV_ID if target is ViewTarget.SERVICES else Column.SRV_FAV_ID
|
||||
|
||||
def remove(md, path, it):
|
||||
if md.get_value(it, Column.FAV_ID if target is ViewTarget.SERVICES else Column.SRV_FAV_ID) in fav_ids:
|
||||
if md.get_value(it, fav_id_column) in fav_ids:
|
||||
md.set_value(it, picon_pos, None)
|
||||
if target is ViewTarget.FAV:
|
||||
picon_ids.append(md.get_value(it, Column.SRV_PICON_ID))
|
||||
@@ -488,9 +500,9 @@ def is_only_one_item_selected(paths, transient):
|
||||
return True
|
||||
|
||||
|
||||
def get_picon_pixbuf(path):
|
||||
def get_picon_pixbuf(path, size=32):
|
||||
try:
|
||||
return GdkPixbuf.Pixbuf.new_from_file_at_scale(filename=path, width=32, height=32, preserve_aspect_ratio=True)
|
||||
return GdkPixbuf.Pixbuf.new_from_file_at_scale(path, width=size, height=size, preserve_aspect_ratio=True)
|
||||
except GLib.GError as e:
|
||||
pass
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1319
app/ui/picons_manager.glade
Normal file
1319
app/ui/picons_manager.glade
Normal file
File diff suppressed because it is too large
Load Diff
@@ -6,20 +6,21 @@ import tempfile
|
||||
|
||||
from gi.repository import GLib, GdkPixbuf
|
||||
|
||||
from app.commons import run_idle, run_task
|
||||
from app.connections import upload_data, DownloadType
|
||||
from app.commons import run_idle, run_task, run_with_delay
|
||||
from app.connections import upload_data, DownloadType, download_data, remove_picons
|
||||
from app.settings import SettingsType, Settings
|
||||
from app.tools.picons import PiconsParser, parse_providers, Provider, convert_to
|
||||
from app.settings import SettingsType
|
||||
from app.tools.satellites import SatellitesParser, SatelliteSource
|
||||
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, TEXT_DOMAIN, TV_ICON
|
||||
from .dialogs import show_dialog, DialogType, get_message
|
||||
from .main_helper import update_entry_data, append_text_to_tview, scroll_to, on_popup_menu
|
||||
from .main_helper import update_entry_data, append_text_to_tview, scroll_to, on_popup_menu, get_base_model
|
||||
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, TV_ICON, GTK_PATH, Column
|
||||
|
||||
|
||||
class PiconsDialog:
|
||||
def __init__(self, transient, settings, picon_ids, sat_positions):
|
||||
def __init__(self, transient, settings, picon_ids, sat_positions, app):
|
||||
self._picon_ids = picon_ids
|
||||
self._sat_positions = sat_positions
|
||||
self._app = app
|
||||
self._TMP_DIR = tempfile.gettempdir() + "/"
|
||||
self._BASE_URL = "www.lyngsat.com/packages/"
|
||||
self._PATTERN = re.compile(r"^https://www\.lyngsat\.com/[\w-]+\.html$")
|
||||
@@ -32,31 +33,46 @@ class PiconsDialog:
|
||||
"on_cancel": self.on_cancel,
|
||||
"on_close": self.on_close,
|
||||
"on_send": self.on_send,
|
||||
"on_download": self.on_download,
|
||||
"on_remove": self.on_remove,
|
||||
"on_info_bar_close": self.on_info_bar_close,
|
||||
"on_picons_dir_open": self.on_picons_dir_open,
|
||||
"on_selected_toggled": self.on_selected_toggled,
|
||||
"on_url_changed": self.on_url_changed,
|
||||
"on_picons_filter_changed": self.on_picons_filter_changed,
|
||||
"on_position_edited": self.on_position_edited,
|
||||
"on_notebook_switch_page": self.on_notebook_switch_page,
|
||||
"on_visible_page": self.on_visible_page,
|
||||
"on_convert": self.on_convert,
|
||||
"on_picons_folder_changed": self.on_picons_folder_changed,
|
||||
"on_picons_view_drag_drop": self.on_picons_view_drag_drop,
|
||||
"on_picons_view_drag_data_received": self.on_picons_view_drag_data_received,
|
||||
"on_picons_view_drag_data_get": self.on_picons_view_drag_data_get,
|
||||
"on_picons_view_realize": self.on_picons_view_realize,
|
||||
"on_satellites_view_realize": self.on_satellites_view_realize,
|
||||
"on_satellite_selection": self.on_satellite_selection,
|
||||
"on_select_all": self.on_select_all,
|
||||
"on_unselect_all": self.on_unselect_all,
|
||||
"on_filter_toggled": self.on_filter_toggled,
|
||||
"on_popup_menu": on_popup_menu}
|
||||
|
||||
builder = Gtk.Builder()
|
||||
builder.set_translation_domain(TEXT_DOMAIN)
|
||||
builder.add_from_file(UI_RESOURCES_PATH + "picons_dialog.glade")
|
||||
builder.add_from_file(UI_RESOURCES_PATH + "picons_manager.glade")
|
||||
builder.connect_signals(handlers)
|
||||
|
||||
self._dialog = builder.get_object("picons_dialog")
|
||||
self._dialog.set_transient_for(transient)
|
||||
self._providers_tree_view = builder.get_object("providers_tree_view")
|
||||
self._satellites_tree_view = builder.get_object("satellites_tree_view")
|
||||
self._picons_view = builder.get_object("picons_view")
|
||||
self._providers_view = builder.get_object("providers_view")
|
||||
self._satellites_view = builder.get_object("satellites_view")
|
||||
self._picons_filter_model = builder.get_object("picons_filter_model")
|
||||
self._picons_filter_model.set_visible_func(self.picons_filter_function)
|
||||
self._explorer_path_button = builder.get_object("explorer_path_button")
|
||||
self._expander = builder.get_object("expander")
|
||||
self._text_view = builder.get_object("text_view")
|
||||
self._info_bar = builder.get_object("info_bar")
|
||||
self._filter_bar = builder.get_object("filter_bar")
|
||||
self._filter_button = builder.get_object("filter_button")
|
||||
self._picons_filter_entry = builder.get_object("picons_filter_entry")
|
||||
self._ip_entry = builder.get_object("ip_entry")
|
||||
self._picons_entry = builder.get_object("picons_entry")
|
||||
self._url_entry = builder.get_object("url_entry")
|
||||
@@ -77,10 +93,20 @@ class PiconsDialog:
|
||||
self._resize_220_132_radio_button = builder.get_object("resize_220_132_radio_button")
|
||||
self._resize_100_60_radio_button = builder.get_object("resize_100_60_radio_button")
|
||||
self._satellite_label = builder.get_object("satellite_label")
|
||||
self._explorer_action_box = builder.get_object("explorer_action_box")
|
||||
self._satellite_label.bind_property("visible", builder.get_object("loading_data_label"), "visible", 4)
|
||||
self._satellite_label.bind_property("visible", builder.get_object("loading_data_spinner"), "visible", 4)
|
||||
self._cancel_button.bind_property("visible", builder.get_object("header_download_box"), "visible", 4)
|
||||
# style
|
||||
self._cancel_button.bind_property("visible", builder.get_object("receive_button"), "visible", 4)
|
||||
self._cancel_button.bind_property("visible", self._load_providers_button, "visible", 4)
|
||||
self._convert_button.bind_property("visible", self._explorer_action_box, "visible", 4)
|
||||
downloader_action_box = builder.get_object("downloader_action_box")
|
||||
self._explorer_action_box.bind_property("visible", downloader_action_box, "visible", 4)
|
||||
self._convert_button.bind_property("visible", downloader_action_box, "visible", 4)
|
||||
self._filter_bar.bind_property("search-mode-enabled", self._filter_bar, "visible")
|
||||
self._explorer_path_button.bind_property("sensitive", builder.get_object("picons_view_sw"), "sensitive")
|
||||
# Init drag-and-drop
|
||||
self.init_drag_and_drop()
|
||||
# Style
|
||||
self._style_provider = Gtk.CssProvider()
|
||||
self._style_provider.load_from_path(UI_RESOURCES_PATH + "style.css")
|
||||
self._url_entry.get_style_context().add_provider_for_screen(Gdk.Screen.get_default(), self._style_provider,
|
||||
@@ -89,8 +115,11 @@ class PiconsDialog:
|
||||
self._s_type = settings.setting_type
|
||||
self._ip_entry.set_text(self._settings.host)
|
||||
self._picons_entry.set_text(self._settings.picons_path)
|
||||
self._picons_path = self._settings.picons_local_path
|
||||
self._picons_dir_entry.set_text(self._picons_path)
|
||||
self._picons_dir_entry.set_text(self._settings.picons_local_path)
|
||||
|
||||
window_size = self._settings.get("picons_downloader_window_size")
|
||||
if window_size:
|
||||
self._dialog.resize(*window_size)
|
||||
|
||||
if not len(self._picon_ids) and self._s_type is SettingsType.ENIGMA_2:
|
||||
message = get_message("To automatically set the identifiers for picons,\n"
|
||||
@@ -99,7 +128,110 @@ class PiconsDialog:
|
||||
self._satellite_label.show()
|
||||
|
||||
def show(self):
|
||||
self._dialog.run()
|
||||
self._dialog.show()
|
||||
|
||||
def on_picons_view_realize(self, view):
|
||||
self._explorer_path_button.set_current_folder(self._settings.picons_local_path)
|
||||
|
||||
def on_picons_folder_changed(self, button):
|
||||
path = button.get_filename()
|
||||
if not path or not os.path.exists(path):
|
||||
return
|
||||
|
||||
GLib.idle_add(self._explorer_path_button.set_sensitive, False)
|
||||
gen = self.update_picons(path)
|
||||
GLib.idle_add(lambda: next(gen, False), priority=GLib.PRIORITY_LOW)
|
||||
|
||||
def update_picons(self, path):
|
||||
p_model = self._picons_view.get_model()
|
||||
if not p_model:
|
||||
return
|
||||
|
||||
model = get_base_model(p_model)
|
||||
self._picons_view.set_model(None)
|
||||
factor = self._app.DEL_FACTOR
|
||||
|
||||
for index, itr in enumerate([row.iter for row in model]):
|
||||
model.remove(itr)
|
||||
if index % factor == 0:
|
||||
yield True
|
||||
|
||||
for file in os.listdir(path):
|
||||
if self._terminate:
|
||||
return
|
||||
|
||||
try:
|
||||
p = GdkPixbuf.Pixbuf.new_from_file_at_scale("{}/{}".format(path, file), 100, 60, True)
|
||||
except GLib.GError as e:
|
||||
pass
|
||||
else:
|
||||
yield model.append((p, file))
|
||||
|
||||
self._picons_view.set_model(p_model)
|
||||
self._explorer_path_button.set_sensitive(True)
|
||||
yield True
|
||||
|
||||
# ***************** Drag-and-drop ********************* #
|
||||
|
||||
def init_drag_and_drop(self):
|
||||
self._picons_view.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK, [], Gdk.DragAction.COPY)
|
||||
self._picons_view.drag_source_add_uri_targets()
|
||||
self._picons_view.enable_model_drag_dest([], Gdk.DragAction.DEFAULT | Gdk.DragAction.MOVE)
|
||||
self._picons_view.drag_dest_add_text_targets()
|
||||
|
||||
def on_picons_view_drag_drop(self, view, drag_context, x, y, time):
|
||||
view.stop_emission_by_name("drag_drop")
|
||||
targets = drag_context.list_targets()
|
||||
view.drag_get_data(drag_context, targets[-1] if targets else Gdk.atom_intern("text/plain", False), time)
|
||||
|
||||
def on_picons_view_drag_data_received(self, view, drag_context, x, y, data, info, time):
|
||||
view.stop_emission_by_name("drag_data_received")
|
||||
txt = data.get_text()
|
||||
if not txt:
|
||||
return
|
||||
|
||||
if txt.startswith("file://"):
|
||||
self.show_info_message("Not implemented yet!", Gtk.MessageType.WARNING)
|
||||
return
|
||||
|
||||
itr_str, sep, src = txt.partition("::::")
|
||||
if src == self._app.BQ_MODEL_NAME:
|
||||
return
|
||||
|
||||
path, pos = view.get_dest_item_at_pos(x, y) or (None, None)
|
||||
if not path:
|
||||
return
|
||||
|
||||
model = view.get_model()
|
||||
p_path = "{}/{}".format(self._explorer_path_button.get_filename(), model.get_value(model.get_iter(path), 1))
|
||||
if src == self._app.FAV_MODEL_NAME:
|
||||
target_view = self._app.fav_view
|
||||
c_id = Column.FAV_ID
|
||||
else:
|
||||
target_view = self._app.services_view
|
||||
c_id = Column.SRV_FAV_ID
|
||||
|
||||
t_mod = target_view.get_model()
|
||||
self._app.on_assign_picon(target_view, p_path)
|
||||
self.show_assign_info([t_mod.get_value(t_mod.get_iter_from_string(itr), c_id) for itr in itr_str.split(",")])
|
||||
|
||||
@run_idle
|
||||
def show_assign_info(self, fav_ids):
|
||||
self._expander.set_expanded(True)
|
||||
self._text_view.get_buffer().set_text("")
|
||||
for i in fav_ids:
|
||||
srv = self._app.current_services.get(i, None)
|
||||
if srv:
|
||||
info = self._app.get_hint_for_srv_list(srv)
|
||||
self.append_output("Picon assignment for the service:\n{}\n{}\n".format(info, " * " * 30))
|
||||
|
||||
def on_picons_view_drag_data_get(self, view, drag_context, data, info, time):
|
||||
model = view.get_model()
|
||||
path = view.get_selected_items()[0]
|
||||
p_path = "{}/{}".format(self._explorer_path_button.get_filename(), model.get_value(model.get_iter(path), 1))
|
||||
data.set_uris([p_path])
|
||||
|
||||
# ******************** ####### ************************* #
|
||||
|
||||
def on_satellites_view_realize(self, view):
|
||||
self.get_satellites(view)
|
||||
@@ -135,14 +267,20 @@ class PiconsDialog:
|
||||
self._cancel_button.show()
|
||||
url = self._url_entry.get_text()
|
||||
|
||||
self._current_process = subprocess.Popen(["wget", "-pkP", self._TMP_DIR, url],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
universal_newlines=True)
|
||||
GLib.io_add_watch(self._current_process.stderr, GLib.IO_IN, self.write_to_buffer)
|
||||
model = self._providers_tree_view.get_model()
|
||||
model.clear()
|
||||
self.append_providers(url, model)
|
||||
try:
|
||||
exe = "{}wget".format("./" if GTK_PATH else "")
|
||||
self._current_process = subprocess.Popen([exe, "-pkP", self._TMP_DIR, url],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
universal_newlines=True)
|
||||
except FileNotFoundError as e:
|
||||
self._cancel_button.hide()
|
||||
self.show_info_message(str(e), Gtk.MessageType.ERROR)
|
||||
else:
|
||||
GLib.io_add_watch(self._current_process.stderr, GLib.IO_IN, self.write_to_buffer)
|
||||
model = self._providers_view.get_model()
|
||||
model.clear()
|
||||
self.append_providers(url, model)
|
||||
|
||||
@run_task
|
||||
def append_providers(self, url, model):
|
||||
@@ -185,7 +323,7 @@ class PiconsDialog:
|
||||
if not self._POS_PATTERN.match(prv[2]):
|
||||
self.show_info_message(
|
||||
get_message("Specify the correct position value for the provider!"), Gtk.MessageType.ERROR)
|
||||
scroll_to(prv.path, self._providers_tree_view)
|
||||
scroll_to(prv.path, self._providers_view)
|
||||
return
|
||||
|
||||
try:
|
||||
@@ -195,7 +333,7 @@ class PiconsDialog:
|
||||
self.process_provider(Provider(*prv))
|
||||
|
||||
if self._resize_no_radio_button.get_active():
|
||||
self.resize(self._picons_path)
|
||||
self.resize(self._picons_dir_entry.get_text())
|
||||
|
||||
self.show_info_message(get_message("Done!"), Gtk.MessageType.INFO)
|
||||
finally:
|
||||
@@ -205,14 +343,16 @@ class PiconsDialog:
|
||||
def process_provider(self, prv):
|
||||
url = prv.url
|
||||
self.show_info_message(get_message("Please, wait..."), Gtk.MessageType.INFO)
|
||||
self._current_process = subprocess.Popen(["wget", "-pkP", self._TMP_DIR, url],
|
||||
exe = "{}wget".format("./" if GTK_PATH else "")
|
||||
self._current_process = subprocess.Popen([exe, "-pkP", self._TMP_DIR, url],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
universal_newlines=True)
|
||||
GLib.io_add_watch(self._current_process.stderr, GLib.IO_IN, self.write_to_buffer)
|
||||
self._current_process.wait()
|
||||
path = self._TMP_DIR + (url[url.find("//") + 2:] if prv.single else self._BASE_URL + url[url.rfind("/") + 1:])
|
||||
PiconsParser.parse(path, self._picons_path, self._TMP_DIR, prv, self._picon_ids, self.get_picons_format())
|
||||
PiconsParser.parse(path, self._picons_dir_entry.get_text(),
|
||||
self._TMP_DIR, prv, self._picon_ids, self.get_picons_format())
|
||||
|
||||
def write_to_buffer(self, fd, condition):
|
||||
if condition == GLib.IO_IN:
|
||||
@@ -227,8 +367,9 @@ class PiconsDialog:
|
||||
|
||||
def resize(self, path):
|
||||
self.show_info_message(get_message("Resizing..."), Gtk.MessageType.INFO)
|
||||
command = "mogrify -resize {}! *.png".format(
|
||||
"320x240" if self._resize_220_132_radio_button.get_active() else "100x60").split()
|
||||
exe = "{}mogrify".format("./" if GTK_PATH else "")
|
||||
is_220_132 = self._resize_220_132_radio_button.get_active()
|
||||
command = "{} -resize {}! *.png".format(exe, "220x132" if is_220_132 else "100x60").split()
|
||||
try:
|
||||
self._current_process = subprocess.Popen(command, universal_newlines=True, cwd=path)
|
||||
self._current_process.wait()
|
||||
@@ -253,9 +394,17 @@ class PiconsDialog:
|
||||
if self.on_cancel():
|
||||
return True
|
||||
|
||||
self._terminate = True
|
||||
self.save_window_size(window)
|
||||
self.clean_data()
|
||||
self._app.update_picons()
|
||||
GLib.idle_add(self._dialog.destroy)
|
||||
|
||||
def save_window_size(self, window):
|
||||
size = window.get_size()
|
||||
height = size.height - self._text_view.get_allocated_height() - self._info_bar.get_allocated_height()
|
||||
self._settings.add("picons_downloader_window_size", (size.width, height))
|
||||
|
||||
@run_task
|
||||
def clean_data(self):
|
||||
path = self._TMP_DIR + "www.lyngsat.com"
|
||||
@@ -266,23 +415,46 @@ class PiconsDialog:
|
||||
if show_dialog(DialogType.QUESTION, self._dialog) == Gtk.ResponseType.CANCEL:
|
||||
return
|
||||
|
||||
settings = Settings(self._settings.settings)
|
||||
settings.picons_local_path = self._explorer_path_button.get_filename() + "/"
|
||||
self.show_info_message(get_message("Please, wait..."), Gtk.MessageType.INFO)
|
||||
self.upload_picons()
|
||||
self.run_func(lambda: upload_data(settings=settings,
|
||||
download_type=DownloadType.PICONS,
|
||||
callback=self.append_output,
|
||||
done_callback=lambda: self.show_info_message(get_message("Done!"),
|
||||
Gtk.MessageType.INFO)))
|
||||
|
||||
@run_task
|
||||
def upload_picons(self):
|
||||
if self.is_task_running():
|
||||
self.show_dialog("The task is already running!", DialogType.ERROR)
|
||||
def on_download(self, item):
|
||||
if show_dialog(DialogType.QUESTION, self._dialog) == Gtk.ResponseType.CANCEL:
|
||||
return
|
||||
|
||||
settings = Settings(self._settings.settings)
|
||||
settings.picons_local_path = self._explorer_path_button.get_filename() + "/"
|
||||
self.run_func(lambda: download_data(settings=settings,
|
||||
download_type=DownloadType.PICONS,
|
||||
callback=self.append_output), True)
|
||||
|
||||
def on_remove(self, item):
|
||||
if show_dialog(DialogType.QUESTION, self._dialog) == Gtk.ResponseType.CANCEL:
|
||||
return
|
||||
|
||||
self.run_func(lambda: remove_picons(settings=self._settings,
|
||||
callback=self.append_output,
|
||||
done_callback=lambda: self.show_info_message(get_message("Done!"),
|
||||
Gtk.MessageType.INFO)))
|
||||
|
||||
@run_task
|
||||
def run_func(self, func, update=False):
|
||||
try:
|
||||
GLib.idle_add(self._expander.set_expanded, True)
|
||||
upload_data(settings=self._settings,
|
||||
download_type=DownloadType.PICONS,
|
||||
callback=self.append_output,
|
||||
done_callback=lambda: self.show_info_message(get_message("Done!"), Gtk.MessageType.INFO))
|
||||
GLib.idle_add(self._explorer_action_box.set_sensitive, False)
|
||||
func()
|
||||
except OSError as e:
|
||||
self.show_info_message(str(e), Gtk.MessageType.ERROR)
|
||||
finally:
|
||||
GLib.idle_add(self._explorer_action_box.set_sensitive, True)
|
||||
if update:
|
||||
self.on_picons_folder_changed(self._explorer_path_button)
|
||||
|
||||
def on_info_bar_close(self, bar=None, resp=None):
|
||||
self._info_bar.set_visible(False)
|
||||
@@ -291,14 +463,14 @@ class PiconsDialog:
|
||||
def show_info_message(self, text, message_type):
|
||||
self._info_bar.set_visible(True)
|
||||
self._info_bar.set_message_type(message_type)
|
||||
self._message_label.set_text(text)
|
||||
self._message_label.set_text(get_message(text))
|
||||
|
||||
def on_picons_dir_open(self, entry, icon, event_button):
|
||||
update_entry_data(entry, self._dialog, settings=self._settings)
|
||||
|
||||
@run_idle
|
||||
def on_selected_toggled(self, toggle, path):
|
||||
model = self._providers_tree_view.get_model()
|
||||
model = self._providers_view.get_model()
|
||||
model.set_value(model.get_iter(path), 7, not toggle.get_active())
|
||||
self.update_receive_button_state()
|
||||
|
||||
@@ -312,21 +484,45 @@ class PiconsDialog:
|
||||
view.get_model().foreach(lambda mod, path, itr: mod.set_value(itr, 7, select))
|
||||
self.update_receive_button_state()
|
||||
|
||||
def on_filter_toggled(self, button):
|
||||
active = button.get_active()
|
||||
self._filter_bar.set_search_mode(active)
|
||||
if not active:
|
||||
self._picons_filter_entry.set_text("")
|
||||
|
||||
def on_url_changed(self, entry):
|
||||
suit = self._PATTERN.search(entry.get_text())
|
||||
entry.set_name("GtkEntry" if suit else "digit-entry")
|
||||
self._load_providers_button.set_sensitive(suit if suit else False)
|
||||
|
||||
@run_with_delay(1)
|
||||
def on_picons_filter_changed(self, entry):
|
||||
GLib.idle_add(self._picons_filter_model.refilter, priority=GLib.PRIORITY_LOW)
|
||||
|
||||
def picons_filter_function(self, model, itr, data):
|
||||
if self._picons_filter_model is None or self._picons_filter_model == "None":
|
||||
return True
|
||||
|
||||
t = model.get_value(itr, 1)
|
||||
if not t:
|
||||
return True
|
||||
|
||||
txt = self._picons_filter_entry.get_text().upper()
|
||||
return txt in t.upper() or t in (
|
||||
map(lambda s: s.picon_id, filter(lambda s: txt in s.service.upper(), self._app.current_services.values())))
|
||||
|
||||
def on_position_edited(self, render, path, value):
|
||||
model = self._providers_tree_view.get_model()
|
||||
model = self._providers_view.get_model()
|
||||
model.set_value(model.get_iter(path), 2, value)
|
||||
|
||||
@run_idle
|
||||
def on_notebook_switch_page(self, nb, box, tab_num):
|
||||
self._load_providers_button.set_visible(not tab_num)
|
||||
self._receive_button.set_visible(not tab_num)
|
||||
self._convert_button.set_visible(tab_num)
|
||||
self._send_button.set_visible(not tab_num)
|
||||
def on_visible_page(self, stack: Gtk.Stack, param):
|
||||
name = stack.get_visible_child_name()
|
||||
self._convert_button.set_visible(name == "converter")
|
||||
is_explorer = name == "explorer"
|
||||
self._explorer_action_box.set_visible(is_explorer)
|
||||
if is_explorer:
|
||||
self.on_picons_folder_changed(self._explorer_path_button)
|
||||
|
||||
@run_idle
|
||||
def on_convert(self, item):
|
||||
@@ -355,7 +551,7 @@ class PiconsDialog:
|
||||
|
||||
def get_selected_providers(self):
|
||||
""" returns selected providers """
|
||||
return [r for r in self._providers_tree_view.get_model() if r[7]]
|
||||
return [r for r in self._providers_view.get_model() if r[7]]
|
||||
|
||||
@run_idle
|
||||
def show_dialog(self, message, dialog_type):
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,10 +9,10 @@ from app.commons import run_idle, run_task
|
||||
from app.eparser import get_satellites, write_satellites, Satellite, Transponder
|
||||
from app.eparser.ecommons import PLS_MODE, get_key_by_value
|
||||
from app.tools.satellites import SatellitesParser, SatelliteSource
|
||||
from .search import SearchProvider
|
||||
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, TEXT_DOMAIN, MOVE_KEYS, KeyboardKey, IS_GNOME_SESSION
|
||||
from .dialogs import show_dialog, DialogType, get_dialogs_string
|
||||
from .dialogs import show_dialog, DialogType, get_dialogs_string, get_chooser_dialog
|
||||
from .main_helper import move_items, scroll_to, append_text_to_tview, get_base_model, on_popup_menu
|
||||
from .search import SearchProvider
|
||||
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, TEXT_DOMAIN, MOVE_KEYS, KeyboardKey, IS_GNOME_SESSION, MOD_MASK
|
||||
|
||||
_UI_PATH = UI_RESOURCES_PATH + "satellites_dialog.glade"
|
||||
|
||||
@@ -48,7 +48,8 @@ class SatellitesDialog:
|
||||
builder.set_translation_domain(TEXT_DOMAIN)
|
||||
builder.add_objects_from_string(get_dialogs_string(_UI_PATH),
|
||||
("satellites_editor_window", "satellites_tree_store", "popup_menu",
|
||||
"left_header_menu", "popup_menu_add_image", "popup_menu_add_image_2"))
|
||||
"left_header_menu", "popup_menu_add_image", "popup_menu_add_image_2",
|
||||
"sat_editor_save_image", "sat_editor_update_image"))
|
||||
builder.connect_signals(handlers)
|
||||
|
||||
self._window = builder.get_object("satellites_editor_window")
|
||||
@@ -84,27 +85,17 @@ class SatellitesDialog:
|
||||
|
||||
@run_idle
|
||||
def on_open(self, model):
|
||||
response = self.get_file_dialog_response(Gtk.FileChooserAction.OPEN)
|
||||
if response == Gtk.ResponseType.CANCEL:
|
||||
response = get_chooser_dialog(self._window, self._settings, "satellites.xml", ("*.xml",))
|
||||
if response in (Gtk.ResponseType.CANCEL, Gtk.ResponseType.DELETE_EVENT):
|
||||
return
|
||||
|
||||
if not str(response).endswith("satellites.xml"):
|
||||
show_dialog(DialogType.ERROR, self._window, text="No satellites.xml file is selected!")
|
||||
return
|
||||
|
||||
self._data_path = response
|
||||
self.load_satellites_list(model)
|
||||
|
||||
def get_file_dialog_response(self, action: Gtk.FileChooserAction):
|
||||
file_filter = Gtk.FileFilter()
|
||||
file_filter.add_pattern("satellites.xml")
|
||||
file_filter.set_name("satellites.xml")
|
||||
response = show_dialog(dialog_type=DialogType.CHOOSER,
|
||||
transient=self._window,
|
||||
settings=self._settings,
|
||||
action_type=action,
|
||||
file_filter=file_filter)
|
||||
return response
|
||||
|
||||
@staticmethod
|
||||
def on_row_activated(view, path, column):
|
||||
if view.row_expanded(path):
|
||||
@@ -124,7 +115,7 @@ class SatellitesDialog:
|
||||
if not KeyboardKey.value_exist(key_code):
|
||||
return
|
||||
key = KeyboardKey(key_code)
|
||||
ctrl = event.state & Gdk.ModifierType.CONTROL_MASK
|
||||
ctrl = event.state & MOD_MASK
|
||||
|
||||
if key is KeyboardKey.DELETE:
|
||||
self.on_remove(view)
|
||||
@@ -466,7 +457,8 @@ class SatellitesUpdateDialog:
|
||||
("satellites_update_window", "update_source_store", "update_sat_list_store",
|
||||
"update_sat_list_model_filter", "update_sat_list_model_sort", "side_store",
|
||||
"pos_adjustment", "pos_adjustment2", "satellites_update_popup_menu",
|
||||
"remove_selection_image"))
|
||||
"remove_selection_image", "sat_update_cancel_image", "sat_receive_image",
|
||||
"sat_update_filter_image", "sat_update_search_image", "sat_update_image"))
|
||||
builder.connect_signals(handlers)
|
||||
|
||||
self._window = builder.get_object("satellites_update_window")
|
||||
|
||||
@@ -31,6 +31,8 @@ class SearchProvider:
|
||||
if self._max_indexes > 0:
|
||||
self.on_search_down()
|
||||
|
||||
self.update_navigation_buttons()
|
||||
|
||||
def scroll_to(self, index):
|
||||
view, path = self._paths[index]
|
||||
view.scroll_to_cell(path, None)
|
||||
|
||||
@@ -254,7 +254,6 @@
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Cancel</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="always_show_image">True</property>
|
||||
</object>
|
||||
</child>
|
||||
<child type="action">
|
||||
@@ -265,7 +264,6 @@
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Save current service</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="clicked" handler="on_save" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
@@ -276,7 +274,6 @@
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Create and save as new service</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<signal name="clicked" handler="on_create_new" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
@@ -1569,7 +1566,6 @@
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="always_show_image">True</property>
|
||||
</object>
|
||||
</child>
|
||||
<child type="action">
|
||||
@@ -1579,7 +1575,6 @@
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<property name="always_show_image">True</property>
|
||||
</object>
|
||||
</child>
|
||||
<child internal-child="vbox">
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,12 @@
|
||||
import os
|
||||
import re
|
||||
from enum import Enum
|
||||
from pathlib import Path
|
||||
|
||||
from app.commons import run_task, run_idle
|
||||
from app.commons import run_task, run_idle, log
|
||||
from app.connections import test_telnet, test_ftp, TestException, test_http, HttpApiException
|
||||
from app.settings import SettingsType, Settings
|
||||
from app.ui.dialogs import show_dialog, DialogType
|
||||
from .main_helper import update_entry_data, scroll_to
|
||||
from app.settings import SettingsType, Settings, PlayStreamsMode
|
||||
from app.ui.dialogs import show_dialog, DialogType, get_message, get_chooser_dialog
|
||||
from .main_helper import update_entry_data, scroll_to, get_picon_pixbuf
|
||||
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, FavClickMode, DEFAULT_ICON
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@ class Property(Enum):
|
||||
|
||||
|
||||
class SettingsDialog:
|
||||
_DIGIT_ENTRY_NAME = "digit-entry"
|
||||
_DIGIT_PATTERN = re.compile("(?:^[\\s]*$|\\D)")
|
||||
|
||||
def __init__(self, transient, settings: Settings):
|
||||
handlers = {"on_field_icon_press": self.on_field_icon_press,
|
||||
@@ -31,10 +33,12 @@ class SettingsDialog:
|
||||
"on_apply_profile_settings": self.on_apply_profile_settings,
|
||||
"on_connection_test": self.on_connection_test,
|
||||
"on_info_bar_close": self.on_info_bar_close,
|
||||
"on_set_color_switch_state": self.on_set_color_switch_state,
|
||||
"on_http_mode_switch_state": self.on_http_mode_switch_state,
|
||||
"on_yt_dl_switch_state": self.on_yt_dl_switch_state,
|
||||
"on_send_to_switch_state": self.on_send_to_switch_state,
|
||||
"on_set_color_switch": self.on_set_color_switch,
|
||||
"on_force_bq_name": self.on_force_bq_name,
|
||||
"on_http_mode_switch": self.on_http_mode_switch,
|
||||
"on_yt_dl_switch": self.on_yt_dl_switch,
|
||||
"on_default_path_mode_switch": self.on_default_path_mode_switch,
|
||||
"on_default_data_path_changed": self.on_default_data_path_changed,
|
||||
"on_profile_add": self.on_profile_add,
|
||||
"on_profile_edit": self.on_profile_edit,
|
||||
"on_profile_remove": self.on_profile_remove,
|
||||
@@ -48,7 +52,23 @@ class SettingsDialog:
|
||||
"on_network_settings_visible": self.on_network_settings_visible,
|
||||
"on_http_use_ssl_toggled": self.on_http_use_ssl_toggled,
|
||||
"on_click_mode_togged": self.on_click_mode_togged,
|
||||
"on_view_popup_menu": self.on_view_popup_menu}
|
||||
"on_play_mode_changed": self.on_play_mode_changed,
|
||||
"on_transcoding_preset_changed": self.on_transcoding_preset_changed,
|
||||
"on_apply_presets": self.on_apply_presets,
|
||||
"on_digit_entry_changed": self.on_digit_entry_changed,
|
||||
"on_view_popup_menu": self.on_view_popup_menu,
|
||||
"on_theme_changed": self.on_theme_changed,
|
||||
"on_theme_add": self.on_theme_add,
|
||||
"on_theme_remove": self.on_theme_remove,
|
||||
"on_icon_theme_changed": self.on_icon_theme_changed,
|
||||
"on_icon_theme_add": self.on_icon_theme_add,
|
||||
"on_icon_theme_remove": self.on_icon_theme_remove}
|
||||
|
||||
# Settings
|
||||
self._ext_settings = settings
|
||||
self._settings = Settings(settings.settings)
|
||||
self._profiles = self._settings.profiles
|
||||
self._s_type = self._settings.setting_type
|
||||
|
||||
builder = Gtk.Builder()
|
||||
builder.add_from_file(UI_RESOURCES_PATH + "settings_dialog.glade")
|
||||
@@ -80,6 +100,9 @@ class SettingsDialog:
|
||||
self._picons_field = builder.get_object("picons_field")
|
||||
self._picons_dir_field = builder.get_object("picons_dir_field")
|
||||
self._backup_dir_field = builder.get_object("backup_dir_field")
|
||||
self._default_data_dir_field = builder.get_object("default_data_dir_field")
|
||||
self._record_data_dir_field = builder.get_object("record_data_dir_field")
|
||||
self._default_data_paths_switch = builder.get_object("default_data_paths_switch")
|
||||
# Info bar
|
||||
self._info_bar = builder.get_object("info_bar")
|
||||
self._message_label = builder.get_object("info_bar_message_label")
|
||||
@@ -88,6 +111,25 @@ class SettingsDialog:
|
||||
self._enigma_radio_button = builder.get_object("enigma_radio_button")
|
||||
self._neutrino_radio_button = builder.get_object("neutrino_radio_button")
|
||||
self._support_ver5_switch = builder.get_object("support_ver5_switch")
|
||||
self._force_bq_name_switch = builder.get_object("force_bq_name_switch")
|
||||
# Streaming
|
||||
self._apply_presets_button = builder.get_object("apply_presets_button")
|
||||
self._transcoding_switch = builder.get_object("transcoding_switch")
|
||||
self._edit_preset_switch = builder.get_object("edit_preset_switch")
|
||||
self._presets_combo_box = builder.get_object("presets_combo_box")
|
||||
self._video_bitrate_field = builder.get_object("video_bitrate_field")
|
||||
self._video_width_field = builder.get_object("video_width_field")
|
||||
self._video_height_field = builder.get_object("video_height_field")
|
||||
self._audio_bitrate_field = builder.get_object("audio_bitrate_field")
|
||||
self._audio_channels_combo_box = builder.get_object("audio_channels_combo_box")
|
||||
self._audio_sample_rate_combo_box = builder.get_object("audio_sample_rate_combo_box")
|
||||
self._transcoding_switch.bind_property("active", builder.get_object("record_box"), "sensitive")
|
||||
self._edit_preset_switch.bind_property("active", self._apply_presets_button, "sensitive")
|
||||
self._edit_preset_switch.bind_property("active", builder.get_object("video_options_frame"), "sensitive")
|
||||
self._edit_preset_switch.bind_property("active", builder.get_object("audio_options_frame"), "sensitive")
|
||||
self._play_in_built_radio_button = builder.get_object("play_in_built_radio_button")
|
||||
self._play_in_vlc_radio_button = builder.get_object("play_in_vlc_radio_button")
|
||||
self._get_m3u_radio_button = builder.get_object("get_m3u_radio_button")
|
||||
# Program
|
||||
self._before_save_switch = builder.get_object("before_save_switch")
|
||||
self._before_downloading_switch = builder.get_object("before_downloading_switch")
|
||||
@@ -98,6 +140,9 @@ class SettingsDialog:
|
||||
self._new_color_button = builder.get_object("new_color_button")
|
||||
self._extra_color_button = builder.get_object("extra_color_button")
|
||||
self._load_on_startup_switch = builder.get_object("load_on_startup_switch")
|
||||
self._bouquet_hints_switch = builder.get_object("bouquet_hints_switch")
|
||||
self._services_hints_switch = builder.get_object("services_hints_switch")
|
||||
self._lang_combo_box = builder.get_object("lang_combo_box")
|
||||
# HTTP API
|
||||
self._support_http_api_switch = builder.get_object("support_http_api_switch")
|
||||
self._enable_y_dl_switch = builder.get_object("enable_y_dl_switch")
|
||||
@@ -112,49 +157,67 @@ class SettingsDialog:
|
||||
self._click_mode_zap_button.bind_property("sensitive", self._enable_send_to_switch, "sensitive")
|
||||
self._enable_send_to_switch.bind_property("sensitive", builder.get_object("enable_send_to_label"), "sensitive")
|
||||
self._extra_support_grid.bind_property("sensitive", builder.get_object("v5_support_grid"), "sensitive")
|
||||
self._extra_support_grid.bind_property("sensitive", builder.get_object("bq_naming_grid"), "sensitive")
|
||||
# Profiles
|
||||
self._profile_view = builder.get_object("profile_tree_view")
|
||||
self._profile_add_button = builder.get_object("profile_add_button")
|
||||
self._profile_remove_button = builder.get_object("profile_remove_button")
|
||||
self._apply_profile_button = builder.get_object("apply_profile_button")
|
||||
self._apply_profile_button.bind_property("visible", builder.get_object("header_separator"), "visible")
|
||||
# Language
|
||||
self._lang_combo_box = builder.get_object("lang_combo_box")
|
||||
# Settings
|
||||
self._ext_settings = settings
|
||||
self._settings = Settings(settings.settings)
|
||||
self._profiles = self._settings.profiles
|
||||
self._s_type = self._settings.setting_type
|
||||
self.set_settings()
|
||||
self._apply_profile_button.bind_property("visible", builder.get_object("reset_button"), "visible")
|
||||
# Style
|
||||
self._style_provider = Gtk.CssProvider()
|
||||
self._style_provider.load_from_path(UI_RESOURCES_PATH + "style.css")
|
||||
self._digit_elems = (self._port_field, self._http_port_field, self._telnet_port_field, self._video_width_field,
|
||||
self._video_bitrate_field, self._video_height_field, self._audio_bitrate_field)
|
||||
for el in self._digit_elems:
|
||||
el.get_style_context().add_provider_for_screen(Gdk.Screen.get_default(), self._style_provider,
|
||||
Gtk.STYLE_PROVIDER_PRIORITY_USER)
|
||||
self.init_ui_elements(self._s_type)
|
||||
self.init_profiles()
|
||||
|
||||
if self._settings.is_darwin:
|
||||
# Appearance
|
||||
self._appearance_box = builder.get_object("appearance_box")
|
||||
self._appearance_box.set_visible(True)
|
||||
self._theme_thumbnail_image = builder.get_object("theme_thumbnail_image")
|
||||
self._theme_combo_box = builder.get_object("theme_combo_box")
|
||||
self._icon_theme_combo_box = builder.get_object("icon_theme_combo_box")
|
||||
self._themes_support_switch = builder.get_object("themes_support_switch")
|
||||
self._themes_support_switch.bind_property("active", builder.get_object("gtk_theme_frame"), "sensitive")
|
||||
self._themes_support_switch.bind_property("active", builder.get_object("icon_theme_frame"), "sensitive")
|
||||
self.init_appearance()
|
||||
|
||||
@run_idle
|
||||
def init_ui_elements(self, s_type):
|
||||
is_enigma_profile = s_type is SettingsType.ENIGMA_2
|
||||
self._neutrino_radio_button.set_active(s_type is SettingsType.NEUTRINO_MP)
|
||||
self.update_header_bar()
|
||||
self.update_title()
|
||||
self._settings_stack.get_child_by_name(Property.HTTP.value).set_visible(is_enigma_profile)
|
||||
self._program_frame.set_sensitive(is_enigma_profile)
|
||||
self._extra_support_grid.set_sensitive(is_enigma_profile)
|
||||
http_active = 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._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(
|
||||
"The Neutrino has only experimental support. Not all features are supported!", Gtk.MessageType.WARNING)
|
||||
|
||||
def init_profiles(self):
|
||||
p_def = self._settings.default_profile
|
||||
for p in self._profiles:
|
||||
self._profile_view.get_model().append((p, DEFAULT_ICON if p == p_def else None))
|
||||
model = self._profile_view.get_model()
|
||||
for ind, p in enumerate(self._profiles):
|
||||
icon = DEFAULT_ICON if p == p_def else None
|
||||
model.append((p, icon))
|
||||
if icon:
|
||||
scroll_to(ind, self._profile_view)
|
||||
self.on_profile_selected(self._profile_view)
|
||||
self._profile_remove_button.set_sensitive(len(self._profile_view.get_model()) > 1)
|
||||
|
||||
def update_header_bar(self):
|
||||
label, sep, st = self._header_bar.get_subtitle().partition(":")
|
||||
def update_title(self):
|
||||
title = "{} [{}]"
|
||||
if self._s_type is SettingsType.ENIGMA_2:
|
||||
self._header_bar.set_subtitle("{}: {}".format(label, self._enigma_radio_button.get_label()))
|
||||
self._dialog.set_title(title.format(get_message("Options"), self._enigma_radio_button.get_label()))
|
||||
elif self._s_type is SettingsType.NEUTRINO_MP:
|
||||
self._header_bar.set_subtitle("{}: {}".format(label, self._neutrino_radio_button.get_label()))
|
||||
self._dialog.set_title(title.format(get_message("Options"), self._neutrino_radio_button.get_label()))
|
||||
|
||||
def show(self):
|
||||
self._dialog.run()
|
||||
@@ -170,17 +233,19 @@ class SettingsDialog:
|
||||
update_entry_data(entry, self._dialog, self._settings)
|
||||
|
||||
def on_settings_type_changed(self, item):
|
||||
profile = SettingsType.ENIGMA_2 if self._enigma_radio_button.get_active() else SettingsType.NEUTRINO_MP
|
||||
self._s_type = profile
|
||||
self._settings.setting_type = profile
|
||||
self.on_reset()
|
||||
self.init_ui_elements(profile)
|
||||
s_type = SettingsType.ENIGMA_2 if self._enigma_radio_button.get_active() else SettingsType.NEUTRINO_MP
|
||||
if s_type is not self._s_type:
|
||||
self._settings.setting_type = s_type
|
||||
self._s_type = s_type
|
||||
self.on_reset()
|
||||
self.init_ui_elements(s_type)
|
||||
|
||||
def on_reset(self, item=None):
|
||||
self._settings.reset()
|
||||
self.set_settings()
|
||||
|
||||
def set_settings(self):
|
||||
self._s_type = self._settings.setting_type
|
||||
self._host_field.set_text(self._settings.host)
|
||||
self._port_field.set_text(self._settings.port)
|
||||
self._login_field.set_text(self._settings.user)
|
||||
@@ -200,13 +265,23 @@ class SettingsDialog:
|
||||
self._data_dir_field.set_text(self._settings.data_local_path)
|
||||
self._picons_dir_field.set_text(self._settings.picons_local_path)
|
||||
self._backup_dir_field.set_text(self._settings.backup_local_path)
|
||||
self._default_data_dir_field.set_text(self._settings.default_data_path)
|
||||
self._record_data_dir_field.set_text(self._settings.records_path)
|
||||
self._before_save_switch.set_active(self._settings.backup_before_save)
|
||||
self._before_downloading_switch.set_active(self._settings.backup_before_downloading)
|
||||
self.set_fav_click_mode(self._settings.fav_click_mode)
|
||||
self.set_play_stream_mode(self._settings.play_streams_mode)
|
||||
self._load_on_startup_switch.set_active(self._settings.load_last_config)
|
||||
self._bouquet_hints_switch.set_active(self._settings.show_bq_hints)
|
||||
self._services_hints_switch.set_active(self._settings.show_srv_hints)
|
||||
self._default_data_paths_switch.set_active(self._settings.profile_folder_is_default)
|
||||
self._transcoding_switch.set_active(self._settings.activate_transcoding)
|
||||
self._presets_combo_box.set_active_id(self._settings.active_preset)
|
||||
self.on_transcoding_preset_changed(self._presets_combo_box)
|
||||
|
||||
if self._s_type is SettingsType.ENIGMA_2:
|
||||
self._support_ver5_switch.set_active(self._settings.v5_support)
|
||||
self._force_bq_name_switch.set_active(self._settings.force_bq_names)
|
||||
self._support_http_api_switch.set_active(self._settings.http_api_support)
|
||||
self._enable_y_dl_switch.set_active(self._settings.enable_yt_dl)
|
||||
self._enable_send_to_switch.set_active(self._settings.enable_send_to)
|
||||
@@ -218,7 +293,16 @@ class SettingsDialog:
|
||||
self._new_color_button.set_rgba(new_rgb)
|
||||
self._extra_color_button.set_rgba(extra_rgb)
|
||||
|
||||
if self._s_type is SettingsType.ENIGMA_2:
|
||||
self._enigma_radio_button.activate()
|
||||
else:
|
||||
self._neutrino_radio_button.activate()
|
||||
|
||||
def on_apply_profile_settings(self, item):
|
||||
if not self.is_data_correct(self._digit_elems):
|
||||
show_dialog(DialogType.ERROR, self._dialog, "Error. Verify the data!")
|
||||
return
|
||||
|
||||
self._s_type = SettingsType.ENIGMA_2 if self._enigma_radio_button.get_active() else SettingsType.NEUTRINO_MP
|
||||
self._settings.setting_type = self._s_type
|
||||
self._settings.host = self._host_field.get_text()
|
||||
@@ -249,14 +333,28 @@ class SettingsDialog:
|
||||
self._ext_settings.backup_before_save = self._before_save_switch.get_active()
|
||||
self._ext_settings.backup_before_downloading = self._before_downloading_switch.get_active()
|
||||
self._ext_settings.fav_click_mode = self.get_fav_click_mode()
|
||||
self._ext_settings.play_streams_mode = self.get_play_stream_mode()
|
||||
self._ext_settings.language = self._lang_combo_box.get_active_id()
|
||||
self._ext_settings.load_last_config = self._load_on_startup_switch.get_active()
|
||||
self._ext_settings.show_bq_hints = self._bouquet_hints_switch.get_active()
|
||||
self._ext_settings.show_srv_hints = self._services_hints_switch.get_active()
|
||||
self._ext_settings.profile_folder_is_default = self._default_data_paths_switch.get_active()
|
||||
self._ext_settings.default_data_path = self._default_data_dir_field.get_text()
|
||||
self._ext_settings.records_path = self._record_data_dir_field.get_text()
|
||||
self._ext_settings.activate_transcoding = self._transcoding_switch.get_active()
|
||||
self._ext_settings.active_preset = self._presets_combo_box.get_active_id()
|
||||
|
||||
if self._ext_settings.is_darwin:
|
||||
self._ext_settings.is_themes_support = self._themes_support_switch.get_active()
|
||||
self._ext_settings.theme = self._theme_combo_box.get_active_id()
|
||||
self._ext_settings.icon_theme = self._icon_theme_combo_box.get_active_id()
|
||||
|
||||
if self._s_type is SettingsType.ENIGMA_2:
|
||||
self._ext_settings.use_colors = self._set_color_switch.get_active()
|
||||
self._ext_settings.new_color = self._new_color_button.get_rgba().to_string()
|
||||
self._ext_settings.extra_color = self._extra_color_button.get_rgba().to_string()
|
||||
self._ext_settings.v5_support = self._support_ver5_switch.get_active()
|
||||
self._ext_settings.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_y_dl_switch.get_active()
|
||||
self._ext_settings.enable_send_to = self._enable_send_to_switch.get_active()
|
||||
@@ -316,7 +414,7 @@ class SettingsDialog:
|
||||
def show_info_message(self, text, message_type):
|
||||
self._info_bar.set_visible(True)
|
||||
self._info_bar.set_message_type(message_type)
|
||||
self._message_label.set_text(text)
|
||||
self._message_label.set_text(get_message(text))
|
||||
|
||||
@run_idle
|
||||
def show_spinner(self, show):
|
||||
@@ -326,21 +424,34 @@ class SettingsDialog:
|
||||
def on_info_bar_close(self, bar=None, resp=None):
|
||||
self._info_bar.set_visible(False)
|
||||
|
||||
def on_set_color_switch_state(self, switch, state):
|
||||
def on_set_color_switch(self, switch, state):
|
||||
self._colors_grid.set_sensitive(state)
|
||||
|
||||
def on_http_mode_switch_state(self, switch, state):
|
||||
def on_http_mode_switch(self, switch, state):
|
||||
self._click_mode_zap_button.set_sensitive(state)
|
||||
if any((self._click_mode_play_button.get_active(),
|
||||
self._click_mode_zap_button.get_active(),
|
||||
self._click_mode_zap_and_play_button.get_active())):
|
||||
self._click_mode_disabled_button.set_active(True)
|
||||
|
||||
def on_yt_dl_switch_state(self, switch, state):
|
||||
def on_force_bq_name(self, switch, state):
|
||||
if self._main_stack.get_visible_child_name() != "extra":
|
||||
return
|
||||
|
||||
if state:
|
||||
msg = "Some images may have problems displaying the favorites list!"
|
||||
self.show_info_message(msg, Gtk.MessageType.WARNING)
|
||||
else:
|
||||
self.on_info_bar_close()
|
||||
|
||||
def on_yt_dl_switch(self, switch, state):
|
||||
self.show_info_message("Not implemented yet!", Gtk.MessageType.WARNING)
|
||||
|
||||
def on_send_to_switch_state(self, switch, state):
|
||||
self.show_info_message("Not implemented yet!", Gtk.MessageType.WARNING)
|
||||
def on_default_path_mode_switch(self, switch, state):
|
||||
self._settings.profile_folder_is_default = state
|
||||
|
||||
def on_default_data_path_changed(self, entry):
|
||||
self._settings.default_data_path = entry.get_text()
|
||||
|
||||
def on_profile_add(self, item):
|
||||
model = self._profile_view.get_model()
|
||||
@@ -354,10 +465,6 @@ class SettingsDialog:
|
||||
model.append((name, None))
|
||||
scroll_to(len(model) - 1, self._profile_view)
|
||||
self.on_profile_selected(self._profile_view)
|
||||
p = name + "/"
|
||||
self._settings.data_local_path += p
|
||||
self._settings.picons_local_path += p
|
||||
self._settings.backup_local_path += p
|
||||
self.on_reset()
|
||||
|
||||
def on_profile_edit(self, item=None):
|
||||
@@ -379,25 +486,30 @@ class SettingsDialog:
|
||||
self._profile_remove_button.set_sensitive(len(model) > 1)
|
||||
|
||||
def on_profile_edited(self, render, path, new_value):
|
||||
p_name = render.get_property("text")
|
||||
p_name = self._profiles.pop(p_name, None)
|
||||
if p_name:
|
||||
row = self._profile_view.get_model()[path]
|
||||
row[0] = new_value
|
||||
self._profiles[new_value] = p_name
|
||||
row = self._profile_view.get_model()[path]
|
||||
old_name = row[0]
|
||||
if old_name == new_value:
|
||||
return
|
||||
|
||||
if p_name != new_value:
|
||||
self.update_local_paths(new_value)
|
||||
if new_value in self._profiles:
|
||||
show_dialog(DialogType.ERROR, self._dialog, "A profile with that name exists!")
|
||||
return
|
||||
|
||||
p_settings = self._profiles.pop(old_name, None)
|
||||
if p_settings:
|
||||
row[0] = new_value
|
||||
self._profiles[new_value] = p_settings
|
||||
self.update_local_paths(new_value, old_name)
|
||||
self.on_profile_selected(self._profile_view)
|
||||
|
||||
def update_local_paths(self, p_name, force_rename=False):
|
||||
def update_local_paths(self, p_name, old_name, force_rename=False):
|
||||
data_path = self._settings.data_local_path
|
||||
picons_path = self._settings.picons_local_path
|
||||
backup_path = self._settings.backup_local_path
|
||||
|
||||
self._settings.data_local_path = "{}/{}/".format(Path(data_path).parent, p_name)
|
||||
self._settings.picons_local_path = "{}/{}/".format(Path(picons_path).parent, p_name)
|
||||
self._settings.backup_local_path = "{}/{}/".format(Path(backup_path).parent, p_name)
|
||||
self._settings.data_local_path = p_name.join(data_path.rsplit(old_name, 1))
|
||||
self._settings.picons_local_path = p_name.join(picons_path.rsplit(old_name, 1))
|
||||
self._settings.backup_local_path = p_name.join(backup_path.rsplit(old_name, 1))
|
||||
|
||||
if force_rename:
|
||||
try:
|
||||
@@ -415,10 +527,6 @@ class SettingsDialog:
|
||||
if paths:
|
||||
profile = model.get_value(model.get_iter(paths), 0)
|
||||
self._settings.current_profile = profile
|
||||
if self._settings.setting_type is SettingsType.ENIGMA_2:
|
||||
self._enigma_radio_button.activate()
|
||||
else:
|
||||
self._neutrino_radio_button.activate()
|
||||
self.set_settings()
|
||||
|
||||
def on_profile_set_default(self, item):
|
||||
@@ -437,7 +545,9 @@ class SettingsDialog:
|
||||
self.show_info_message("Save and restart the program to apply the settings.", Gtk.MessageType.WARNING)
|
||||
|
||||
def on_main_settings_visible(self, stack, param):
|
||||
self._apply_profile_button.set_visible(stack.get_visible_child_name() == "profiles")
|
||||
name = stack.get_visible_child_name()
|
||||
self._apply_profile_button.set_visible(name == "profiles")
|
||||
self._apply_presets_button.set_visible(name == "streaming")
|
||||
|
||||
def on_network_settings_visible(self, stack, param):
|
||||
self._http_use_ssl_check_button.set_visible(Property(stack.get_visible_child_name()) is Property.HTTP)
|
||||
@@ -480,10 +590,187 @@ class SettingsDialog:
|
||||
|
||||
return FavClickMode.DISABLED
|
||||
|
||||
def on_play_mode_changed(self, button):
|
||||
if self._main_stack.get_visible_child_name() != "streaming":
|
||||
return
|
||||
|
||||
if button.get_active():
|
||||
self.show_info_message("Save and restart the program to apply the settings.", Gtk.MessageType.WARNING)
|
||||
|
||||
@run_idle
|
||||
def set_play_stream_mode(self, mode):
|
||||
self._play_in_built_radio_button.set_sensitive(not self._settings.is_darwin)
|
||||
self._play_in_built_radio_button.set_active(mode is PlayStreamsMode.BUILT_IN)
|
||||
self._play_in_vlc_radio_button.set_active(mode is PlayStreamsMode.VLC)
|
||||
self._get_m3u_radio_button.set_active(mode is PlayStreamsMode.M3U)
|
||||
|
||||
def get_play_stream_mode(self):
|
||||
if self._play_in_built_radio_button.get_active():
|
||||
return PlayStreamsMode.BUILT_IN
|
||||
if self._play_in_vlc_radio_button.get_active():
|
||||
return PlayStreamsMode.VLC
|
||||
if self._get_m3u_radio_button.get_active():
|
||||
return PlayStreamsMode.M3U
|
||||
|
||||
return self._settings.play_streams_mode
|
||||
|
||||
def on_transcoding_preset_changed(self, button):
|
||||
presets = self._settings.transcoding_presets
|
||||
prs = presets.get(button.get_active_id())
|
||||
self._video_bitrate_field.set_text(prs.get("vb", "0"))
|
||||
self._video_width_field.set_text(prs.get("width", "0"))
|
||||
self._video_height_field.set_text(prs.get("height", "0"))
|
||||
self._audio_bitrate_field.set_text(prs.get("ab", "0"))
|
||||
self._audio_channels_combo_box.set_active_id(prs.get("channels", "2"))
|
||||
self._audio_sample_rate_combo_box.set_active_id(prs.get("samplerate", "44100"))
|
||||
|
||||
def on_apply_presets(self, item):
|
||||
if not self.is_data_correct(self._digit_elems):
|
||||
show_dialog(DialogType.ERROR, self._dialog, "Error. Verify the data!")
|
||||
return
|
||||
|
||||
if show_dialog(DialogType.QUESTION, self._dialog) == Gtk.ResponseType.CANCEL:
|
||||
return
|
||||
|
||||
presets = self._settings.transcoding_presets
|
||||
prs = presets.get(self._presets_combo_box.get_active_id())
|
||||
prs["vb"] = self._video_bitrate_field.get_text()
|
||||
prs["width"] = self._video_width_field.get_text()
|
||||
prs["height"] = self._video_height_field.get_text()
|
||||
prs["ab"] = self._audio_bitrate_field.get_text()
|
||||
prs["channels"] = self._audio_channels_combo_box.get_active_id()
|
||||
prs["samplerate"] = self._audio_sample_rate_combo_box.get_active_id()
|
||||
self._ext_settings.transcoding_presets = presets
|
||||
self._edit_preset_switch.set_active(False)
|
||||
|
||||
def on_digit_entry_changed(self, entry):
|
||||
if self._DIGIT_PATTERN.search(entry.get_text()):
|
||||
entry.set_name(self._DIGIT_ENTRY_NAME)
|
||||
else:
|
||||
entry.set_name("GtkEntry")
|
||||
|
||||
def is_data_correct(self, elems):
|
||||
return not any(elem.get_name() == self._DIGIT_ENTRY_NAME for elem in elems)
|
||||
|
||||
def on_view_popup_menu(self, menu, event):
|
||||
if event.get_event_type() == Gdk.EventType.BUTTON_PRESS and event.button == Gdk.BUTTON_SECONDARY:
|
||||
menu.popup(None, None, None, None, event.button, event.time)
|
||||
|
||||
def on_theme_changed(self, button):
|
||||
if self._main_stack.get_visible_child_name() != "appearance":
|
||||
return
|
||||
|
||||
self.set_theme_thumbnail_image(button.get_active_id())
|
||||
self.show_info_message("Save and restart the program to apply the settings.", Gtk.MessageType.WARNING)
|
||||
|
||||
@run_idle
|
||||
def set_theme_thumbnail_image(self, theme_name):
|
||||
img_path = "{}{}/gtk-3.0/thumbnail.png".format(self._ext_settings.themes_path, theme_name)
|
||||
self._theme_thumbnail_image.set_from_pixbuf(get_picon_pixbuf(img_path, 96))
|
||||
|
||||
def on_theme_add(self, button):
|
||||
self.add_theme(self._ext_settings.themes_path, self._theme_combo_box)
|
||||
|
||||
def on_theme_remove(self, button):
|
||||
if show_dialog(DialogType.QUESTION, self._dialog) == Gtk.ResponseType.OK:
|
||||
Gtk.Settings().get_default().set_property("gtk-theme-name", "")
|
||||
self.remove_theme(self._theme_combo_box, self._ext_settings.themes_path)
|
||||
|
||||
def on_icon_theme_changed(self, button, state=False):
|
||||
if self._main_stack.get_visible_child_name() != "appearance":
|
||||
return
|
||||
self.show_info_message("Save and restart the program to apply the settings.", Gtk.MessageType.WARNING)
|
||||
|
||||
def on_icon_theme_add(self, button):
|
||||
self.add_theme(self._ext_settings.icon_themes_path, self._icon_theme_combo_box)
|
||||
|
||||
def on_icon_theme_remove(self, button):
|
||||
if show_dialog(DialogType.QUESTION, self._dialog) == Gtk.ResponseType.OK:
|
||||
Gtk.Settings().get_default().set_property("gtk-icon-theme-name", "")
|
||||
self.remove_theme(self._icon_theme_combo_box, self._ext_settings.icon_themes_path)
|
||||
|
||||
@run_idle
|
||||
def add_theme(self, path, button):
|
||||
response = get_chooser_dialog(self._dialog, self._settings, "Themes Archive [*.xz, *.zip]", ("*.xz", "*.zip"))
|
||||
if response in (Gtk.ResponseType.CANCEL, Gtk.ResponseType.DELETE_EVENT):
|
||||
return
|
||||
self._appearance_box.set_sensitive(False)
|
||||
self.unpack_theme(response, path, button)
|
||||
|
||||
@run_task
|
||||
def unpack_theme(self, src, dst, button):
|
||||
try:
|
||||
os.makedirs(os.path.dirname(dst), exist_ok=True)
|
||||
|
||||
import subprocess
|
||||
log("Unpacking '{}' started...".format(src))
|
||||
p = subprocess.Popen(["tar", "-xvf", src, "-C", dst],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT)
|
||||
p.communicate()
|
||||
log("Unpacking end.")
|
||||
finally:
|
||||
self.update_theme_button(button, dst)
|
||||
self._appearance_box.set_sensitive(True)
|
||||
|
||||
@run_idle
|
||||
def update_theme_button(self, button, dst):
|
||||
exist = set(os.listdir(dst))
|
||||
current = {r[0] for r in button.get_model()}
|
||||
added = exist - current
|
||||
if added:
|
||||
theme = added.pop()
|
||||
if theme not in current:
|
||||
button.append(theme, theme)
|
||||
button.set_active_id(theme)
|
||||
self.show_info_message("Done!", Gtk.MessageType.INFO)
|
||||
|
||||
@run_idle
|
||||
def remove_theme(self, button, path):
|
||||
theme = button.get_active_id()
|
||||
if not theme:
|
||||
self.show_info_message("No selected item!", Gtk.MessageType.ERROR)
|
||||
return
|
||||
|
||||
from shutil import rmtree
|
||||
|
||||
try:
|
||||
rmtree(path + theme, ignore_errors=True)
|
||||
except OSError as e:
|
||||
self.show_info_message(str(e), Gtk.MessageType.ERROR)
|
||||
else:
|
||||
self.theme_button_remove_active(button)
|
||||
|
||||
@run_idle
|
||||
def theme_button_remove_active(self, button):
|
||||
button.remove(button.get_active())
|
||||
button.set_active(0)
|
||||
|
||||
@run_idle
|
||||
def init_appearance(self):
|
||||
t_support = self._ext_settings.is_themes_support
|
||||
self._themes_support_switch.set_active(t_support)
|
||||
if t_support:
|
||||
# GTK
|
||||
try:
|
||||
for t in os.listdir(self._ext_settings.themes_path):
|
||||
self._theme_combo_box.append(t, t)
|
||||
self._theme_combo_box.set_active_id(self._ext_settings.theme)
|
||||
self.set_theme_thumbnail_image(self._ext_settings.theme)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
except PermissionError as e:
|
||||
log("{}".format(e))
|
||||
# Icons
|
||||
try:
|
||||
for t in os.listdir(self._ext_settings.icon_themes_path):
|
||||
self._icon_theme_combo_box.append(t, t)
|
||||
self._icon_theme_combo_box.set_active_id(self._ext_settings.icon_theme)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
except PermissionError as e:
|
||||
log("{}".format(e))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pass
|
||||
|
||||
@@ -1,8 +1,32 @@
|
||||
#digit-entry {
|
||||
border-color: Red;
|
||||
border-color: Red;
|
||||
border-width: 0.15em;
|
||||
}
|
||||
|
||||
#status-bar-button {
|
||||
padding: 1px;
|
||||
margin: 1px;
|
||||
margin: 0.1em;
|
||||
}
|
||||
|
||||
#textview-large {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.group {}
|
||||
|
||||
.group :first-child {
|
||||
padding-left: 0.5em;
|
||||
padding-right: 0.5em;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
|
||||
.group :last-child {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
||||
.group :not(:first-child):not(:last-child) {
|
||||
border-radius: 0;
|
||||
border-left-width: 0;
|
||||
border-right-width: 0;
|
||||
}
|
||||
250
app/ui/telnet.glade
Executable file
250
app/ui/telnet.glade
Executable file
@@ -0,0 +1,250 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.22.1
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018-2020 Dmitriy Yefremov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
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
|
||||
|
||||
-->
|
||||
<interface domain="demon-editor">
|
||||
<requires lib="gtk+" version="3.16"/>
|
||||
<!-- interface-license-type mit -->
|
||||
<!-- interface-name DemonEditor -->
|
||||
<!-- interface-copyright 2018-2020 Dmitriy Yefremov -->
|
||||
<!-- interface-authors Dmitriy Yefremov -->
|
||||
<object class="GtkTextTagTable" id="tag_table">
|
||||
<child type="tag">
|
||||
<object class="GtkTextTag" id="end_tag">
|
||||
<property name="font">Normal</property>
|
||||
<property name="editable">False</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkTextBuffer" id="text_buffer">
|
||||
<property name="tag_table">tag_table</property>
|
||||
</object>
|
||||
<object class="GtkWindow" id="dialog_window">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="title" translatable="yes">DemonEditor [Telnet client]</property>
|
||||
<property name="destroy_with_parent">True</property>
|
||||
<property name="icon_name">terminal</property>
|
||||
<property name="skip_taskbar_hint">True</property>
|
||||
<property name="skip_pager_hint">True</property>
|
||||
<signal name="delete-event" handler="on_close" swapped="no"/>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="main_box">
|
||||
<property name="width_request">560</property>
|
||||
<property name="height_request">320</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">2</property>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="telnet_scrolled_window">
|
||||
<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="name">textview-large</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="wrap_mode">char</property>
|
||||
<property name="left_margin">5</property>
|
||||
<property name="right_margin">5</property>
|
||||
<property name="buffer">text_buffer</property>
|
||||
<property name="overwrite">True</property>
|
||||
<property name="input_hints">GTK_INPUT_HINT_WORD_COMPLETION | GTK_INPUT_HINT_NONE</property>
|
||||
<property name="monospace">True</property>
|
||||
<signal name="key-press-event" handler="on_view_key_press" swapped="no"/>
|
||||
<signal name="realize" handler="on_text_view_realize" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="commands_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">5</property>
|
||||
<property name="margin_right">5</property>
|
||||
<property name="margin_bottom">2</property>
|
||||
<property name="spacing">2</property>
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="profile_combo_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="active">0</property>
|
||||
<property name="has_frame">False</property>
|
||||
<signal name="changed" handler="on_profile_changed" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="connect_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Connect</property>
|
||||
<signal name="clicked" handler="on_connect" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="connect_button_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-connect</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="disconnect_button">
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Disconnect</property>
|
||||
<signal name="clicked" handler="on_disconnect" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="disconnect_button_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-disconnect</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child type="center">
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="clear_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Clear</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<signal name="clicked" handler="on_clear" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="clear_button_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-clear</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkInfoBar" id="info_bar">
|
||||
<property name="app_paintable">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">2</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="layout_style">end</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child internal-child="content_area">
|
||||
<object class="GtkBox">
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="info_bar_message_label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label">Info</property>
|
||||
<property name="justify">center</property>
|
||||
<property name="wrap">True</property>
|
||||
<property name="wrap_mode">word-char</property>
|
||||
<property name="lines">2</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
256
app/ui/telnet.py
Executable file
256
app/ui/telnet.py
Executable file
@@ -0,0 +1,256 @@
|
||||
import re
|
||||
import selectors
|
||||
import socket
|
||||
from collections import deque
|
||||
from telnetlib import Telnet
|
||||
|
||||
from gi.repository import GLib
|
||||
|
||||
from app.commons import run_task, run_idle, log
|
||||
from app.settings import Settings
|
||||
from app.ui.uicommons import Gtk, Gdk, UI_RESOURCES_PATH, KeyboardKey, MOD_MASK
|
||||
|
||||
|
||||
class ExtTelnet(Telnet):
|
||||
|
||||
def __init__(self, output_callback, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self._output_callback = output_callback
|
||||
|
||||
def interact(self):
|
||||
"""Interaction function, emulates a very dumb telnet client."""
|
||||
with selectors.DefaultSelector() as selector:
|
||||
selector.register(self, selectors.EVENT_READ)
|
||||
|
||||
while True:
|
||||
for key, events in selector.select():
|
||||
if key.fileobj is self:
|
||||
try:
|
||||
text = self.read_very_eager()
|
||||
except EOFError as e:
|
||||
msg = "\n*** Connection closed by remote host ***\n"
|
||||
self._output_callback(msg)
|
||||
log(msg)
|
||||
raise e
|
||||
else:
|
||||
if text:
|
||||
self._output_callback(text)
|
||||
|
||||
|
||||
class TelnetDialog:
|
||||
""" Dialog of very simple telnet client. """
|
||||
_COLOR_PATTERN = re.compile("\x1b.*?m") # Color info
|
||||
_ERASING_PATTERN = re.compile("\x1b.*?K") # Erase to right
|
||||
_APP_MODE_PATTERN = re.compile("\x1b.*?(1h)|(1l)") # h - on, l - off
|
||||
_ALL_PATTERN = re.compile(r'(\x1b\[|\x9b)[0-?]*[@-~]')
|
||||
_NOT_SUPPORTED = {"mc", "mcedit", "vi", "nano"}
|
||||
|
||||
def __init__(self, transient, settings):
|
||||
self._handlers = {"on_profile_changed": self.on_profile_changed,
|
||||
"on_clear": self.on_clear,
|
||||
"on_text_view_realize": self.on_text_view_realize,
|
||||
"on_view_key_press": self.on_view_key_press,
|
||||
"on_info_bar_close": self.on_info_bar_close,
|
||||
"on_connect": self.on_connect,
|
||||
"on_disconnect": self.on_disconnect,
|
||||
"on_close": self.on_close}
|
||||
|
||||
builder = Gtk.Builder()
|
||||
builder.add_from_file(UI_RESOURCES_PATH + "telnet.glade")
|
||||
builder.connect_signals(self._handlers)
|
||||
self._dialog_window = builder.get_object("dialog_window")
|
||||
self._dialog_window.set_transient_for(transient)
|
||||
self._profile_combo_box = builder.get_object("profile_combo_box")
|
||||
self._info_bar = builder.get_object("info_bar")
|
||||
self._info_message_label = builder.get_object("info_bar_message_label")
|
||||
self._text_view = builder.get_object("text_view")
|
||||
self._buf = builder.get_object("text_buffer")
|
||||
self._end_tag = builder.get_object("end_tag")
|
||||
self._connect_button = builder.get_object("connect_button")
|
||||
self._connect_button.bind_property("visible", builder.get_object("disconnect_button"), "visible", 4)
|
||||
provider = Gtk.CssProvider()
|
||||
provider.load_from_path(UI_RESOURCES_PATH + "style.css")
|
||||
builder.get_object("main_box").get_style_context().add_provider(provider, Gtk.STYLE_PROVIDER_PRIORITY_USER)
|
||||
|
||||
window_size = settings.get("telnet_dialog_window_size")
|
||||
if window_size:
|
||||
self._dialog_window.resize(*window_size)
|
||||
|
||||
self._ext_settings = settings
|
||||
self._settings = Settings(settings.settings)
|
||||
self._tn = None
|
||||
self._app_mode = False
|
||||
self._commands = deque(maxlen=10)
|
||||
|
||||
def show(self):
|
||||
self._dialog_window.show()
|
||||
|
||||
def on_close(self, window, event):
|
||||
""" Performs shutdown tasks """
|
||||
self._ext_settings.add("telnet_dialog_window_size", window.get_size())
|
||||
self.on_disconnect()
|
||||
|
||||
def on_info_bar_close(self, bar=None, resp=None):
|
||||
self._info_bar.set_visible(False)
|
||||
|
||||
@run_idle
|
||||
def show_info_message(self, text, message_type):
|
||||
self._info_bar.set_visible(True)
|
||||
self._info_bar.set_message_type(message_type)
|
||||
self._info_message_label.set_text(text)
|
||||
|
||||
def on_text_view_realize(self, view):
|
||||
self.init_profiles()
|
||||
self.on_connect()
|
||||
|
||||
@run_idle
|
||||
def init_profiles(self):
|
||||
for p in self._settings.profiles:
|
||||
self._profile_combo_box.append(p, p)
|
||||
self._profile_combo_box.set_active_id(self._settings.current_profile)
|
||||
|
||||
@run_task
|
||||
def on_connect(self, item=None):
|
||||
try:
|
||||
GLib.idle_add(self._connect_button.set_visible, False)
|
||||
GLib.idle_add(self.on_info_bar_close)
|
||||
user, password = self._settings.telnet_user, self._settings.telnet_password
|
||||
timeout = self._settings.telnet_timeout
|
||||
|
||||
self._tn = ExtTelnet(self.append_output,
|
||||
host=self._settings.host,
|
||||
port=self._settings.telnet_port,
|
||||
timeout=timeout)
|
||||
|
||||
if user != "":
|
||||
self._tn.read_until(b"login: ")
|
||||
self._tn.write(user.encode("utf-8") + b"\n")
|
||||
if password != "":
|
||||
self._tn.read_until(b"Password: ")
|
||||
self._tn.write(password.encode("utf-8") + b"\n")
|
||||
|
||||
self._tn.interact()
|
||||
except (OSError, EOFError, socket.timeout, ConnectionRefusedError) as e:
|
||||
log("{}: {}".format(self.__class__.__name__, e))
|
||||
self.show_info_message(str(e), Gtk.MessageType.ERROR)
|
||||
finally:
|
||||
GLib.idle_add(self._connect_button.set_visible, True)
|
||||
|
||||
@run_task
|
||||
def on_disconnect(self, item=None):
|
||||
if self._tn:
|
||||
GLib.idle_add(self._connect_button.set_visible, True)
|
||||
self._tn.close()
|
||||
|
||||
def on_profile_changed(self, button):
|
||||
self._settings.current_profile = button.get_active_id()
|
||||
|
||||
def on_command_done(self, entry):
|
||||
command = entry.get_text()
|
||||
entry.set_text("")
|
||||
if command and self._tn:
|
||||
self._tn.write(command.encode("ascii") + b"\r")
|
||||
|
||||
def on_clear(self, item=None):
|
||||
self._buf.delete(self._buf.get_start_iter(), self._buf.get_end_iter())
|
||||
|
||||
def on_view_key_press(self, view, event):
|
||||
""" Handling keystrokes on press """
|
||||
if event.keyval == Gdk.KEY_Return:
|
||||
self.do_command()
|
||||
return True
|
||||
|
||||
key_code = event.hardware_keycode
|
||||
if not KeyboardKey.value_exist(key_code):
|
||||
return
|
||||
|
||||
key = KeyboardKey(key_code)
|
||||
ctrl = event.state & MOD_MASK
|
||||
if ctrl and key is KeyboardKey.C:
|
||||
if self._tn and self._tn.sock:
|
||||
self._tn.write(b"\x03") # interrupt
|
||||
|
||||
# last commands navigation
|
||||
if key is KeyboardKey.UP:
|
||||
self.delete_last_command()
|
||||
if self._commands:
|
||||
cmd = self._commands.pop()
|
||||
self._commands.appendleft(cmd)
|
||||
self._buf.insert_at_cursor(cmd, -1)
|
||||
return True
|
||||
elif key is KeyboardKey.DOWN:
|
||||
self.delete_last_command()
|
||||
if self._commands:
|
||||
cmd = self._commands.popleft()
|
||||
self._commands.append(cmd)
|
||||
self._buf.insert_at_cursor(cmd, -1)
|
||||
return True
|
||||
|
||||
def delete_last_command(self):
|
||||
end = self._buf.get_end_iter()
|
||||
if end.ends_tag(self._end_tag):
|
||||
return
|
||||
|
||||
if end.backward_to_tag_toggle(self._end_tag):
|
||||
self._buf.delete(self._buf.get_end_iter(), end)
|
||||
|
||||
def do_command(self):
|
||||
count = self._buf.get_line_count()
|
||||
begin = self._buf.get_iter_at_line(count)
|
||||
end = self._buf.get_end_iter()
|
||||
command = []
|
||||
|
||||
while end.backward_to_tag_toggle(self._end_tag):
|
||||
command.append(self._buf.get_text(end, begin, False))
|
||||
break
|
||||
else: # if buf is empty
|
||||
command.append(self._buf.get_text(begin, end, False))
|
||||
|
||||
# to preventing duplication of the command in the buf
|
||||
self._buf.delete(end, begin)
|
||||
|
||||
if command and self._tn.sock:
|
||||
cmd = command[0]
|
||||
if cmd in self._NOT_SUPPORTED:
|
||||
self.show_info_message("'{}' is not supported by this client.".format(cmd), Gtk.MessageType.ERROR)
|
||||
else:
|
||||
self._tn.write(cmd.encode("ascii") + b"\r")
|
||||
self._commands.append(cmd)
|
||||
|
||||
@run_idle
|
||||
def append_output(self, txt):
|
||||
t = txt.decode("ascii", errors="ignore")
|
||||
|
||||
ap = re.search(self._APP_MODE_PATTERN, t)
|
||||
if ap:
|
||||
on, of = ap.group(1), ap.group(2)
|
||||
if on:
|
||||
self._app_mode = True
|
||||
elif of:
|
||||
self._app_mode = False
|
||||
self.on_clear()
|
||||
|
||||
t = re.sub(self._ALL_PATTERN, "", t) # removing [replacing] ascii escape sequences
|
||||
|
||||
if self._app_mode:
|
||||
start, end = self._buf.get_start_iter(), self._buf.get_end_iter()
|
||||
count = self._buf.get_line_count()
|
||||
new_lines = t.split("\r\n")
|
||||
ext_lines = self._buf.get_text(start, end, True).split("\r\n")
|
||||
if count < len(new_lines):
|
||||
self._buf.set_text(re.sub(self._ERASING_PATTERN, "", t))
|
||||
else:
|
||||
for i, line in enumerate(new_lines):
|
||||
if line:
|
||||
ext_lines[i] = re.sub(self._ERASING_PATTERN, "", line)
|
||||
self._buf.set_text("\r\n".join(ext_lines))
|
||||
else:
|
||||
self._buf.insert_at_cursor(t, -1)
|
||||
|
||||
insert = self._buf.get_insert()
|
||||
self._text_view.scroll_to_mark(insert, 0.0, True, 0.0, 1.0)
|
||||
self._buf.apply_tag(self._end_tag, self._buf.get_start_iter(), self._buf.get_end_iter())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pass
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018-2019 Dmitriy Yefremov
|
||||
Copyright (c) 2018-2020 Dmitriy Yefremov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -26,20 +26,19 @@ THE SOFTWARE.
|
||||
Author: Dmitriy Yefremov
|
||||
|
||||
-->
|
||||
<interface>
|
||||
<interface domain="demon-editor">
|
||||
<requires lib="gtk+" version="3.16"/>
|
||||
<!-- interface-css-provider-path style.css -->
|
||||
<!-- interface-license-type mit -->
|
||||
<!-- interface-name DemonEditor -->
|
||||
<!-- interface-description Enigma2 channel and satellites list editor for GNU/Linux. -->
|
||||
<!-- interface-copyright 2018-2019 Dmitriy Yefremov -->
|
||||
<!-- interface-copyright 2018-2020 Dmitriy Yefremov -->
|
||||
<!-- interface-authors Dmitriy Yefremov -->
|
||||
<object class="GtkWindow" id="main_window">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="resizable">False</property>
|
||||
<property name="window_position">mouse</property>
|
||||
<property name="destroy_with_parent">True</property>
|
||||
<property name="type_hint">splashscreen</property>
|
||||
<property name="skip_taskbar_hint">True</property>
|
||||
<property name="skip_pager_hint">True</property>
|
||||
<property name="decorated">False</property>
|
||||
@@ -49,20 +48,29 @@ Author: Dmitriy Yefremov
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="main_box">
|
||||
<object class="GtkBox" id="tool_bar">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">1</property>
|
||||
<child>
|
||||
<object class="GtkEntry" id="url_entry">
|
||||
<object class="GtkButton" id="previous_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="margin_left">2</property>
|
||||
<property name="margin_right">2</property>
|
||||
<property name="margin_top">2</property>
|
||||
<property name="margin_bottom">2</property>
|
||||
<property name="primary_icon_stock">gtk-dnd-multiple</property>
|
||||
<signal name="drag-data-received" handler="on_drag_data_received" swapped="no"/>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Previous stream in the list</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="margin_left">1</property>
|
||||
<property name="margin_top">1</property>
|
||||
<property name="margin_bottom">1</property>
|
||||
<signal name="clicked" handler="on_previous" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="previous_button_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-media-previous</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
@@ -70,31 +78,156 @@ Author: Dmitriy Yefremov
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="next_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Next stream in the list</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="margin_top">1</property>
|
||||
<property name="margin_bottom">1</property>
|
||||
<signal name="clicked" handler="on_next" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="next_button_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-media-next</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="url_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Drag or paste the link here</property>
|
||||
<property name="margin_left">2</property>
|
||||
<property name="margin_right">2</property>
|
||||
<property name="margin_top">1</property>
|
||||
<property name="margin_bottom">1</property>
|
||||
<property name="primary_icon_stock">gtk-paste</property>
|
||||
<signal name="activate" handler="on_url_activate" swapped="no"/>
|
||||
<signal name="changed" handler="on_url_changed" swapped="no"/>
|
||||
<signal name="drag-data-received" handler="on_drag_data_received" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="play_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Play</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="margin_top">1</property>
|
||||
<property name="margin_bottom">1</property>
|
||||
<signal name="clicked" handler="on_play" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="play_button_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-media-play</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="stop_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Stop playback</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="margin_top">1</property>
|
||||
<property name="margin_bottom">1</property>
|
||||
<signal name="clicked" handler="on_stop" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="stop_button_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-media-stop</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="clear_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Remove added links in the playlist</property>
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="margin_right">1</property>
|
||||
<property name="margin_top">1</property>
|
||||
<property name="margin_bottom">1</property>
|
||||
<signal name="clicked" handler="on_clear" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkImage" id="clear_button_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-clear</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">6</property>
|
||||
</packing>
|
||||
</child>
|
||||
<style>
|
||||
<class name="primary-toolbar"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkStatusIcon" id="status_icon">
|
||||
<property name="icon_name">insert-link</property>
|
||||
<property name="has_tooltip">True</property>
|
||||
<signal name="activate" handler="on_status_icon_activate" object="main_window" swapped="no"/>
|
||||
<signal name="popup-menu" handler="on_popup_menu" object="staus_popup_menu" swapped="no"/>
|
||||
<signal name="query-tooltip" handler="on_query_tooltip" swapped="no"/>
|
||||
<object class="GtkImage" id="show_image">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">view-restore</property>
|
||||
</object>
|
||||
<object class="GtkMenu" id="staus_popup_menu">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkImageMenuItem" id="exit_menu_item">
|
||||
<property name="label">gtk-quit</property>
|
||||
<object class="GtkImageMenuItem" id="show_menu_item">
|
||||
<property name="label" translatable="yes">Show/Hide</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="activate" handler="on_exit" swapped="no"/>
|
||||
<property name="image">show_image</property>
|
||||
<property name="use_stock">False</property>
|
||||
<signal name="activate" handler="on_status_icon_activate" object="main_window" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkStatusIcon" id="status_icon">
|
||||
<property name="icon_name">demon-editor</property>
|
||||
<property name="has_tooltip">True</property>
|
||||
<signal name="activate" handler="on_status_icon_activate" object="main_window" swapped="no"/>
|
||||
<signal name="popup-menu" handler="on_popup_menu" object="staus_popup_menu" swapped="no"/>
|
||||
</object>
|
||||
</interface>
|
||||
|
||||
@@ -1,31 +1,73 @@
|
||||
from pathlib import Path
|
||||
from urllib.parse import urlparse
|
||||
|
||||
import gi
|
||||
from gi.repository import GLib
|
||||
|
||||
from app.commons import log
|
||||
from app.settings import IS_DARWIN
|
||||
from app.connections import HttpRequestType
|
||||
from app.tools.yt import YouTube
|
||||
from app.ui.iptv import get_yt_icon
|
||||
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, TEXT_DOMAIN
|
||||
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH
|
||||
|
||||
|
||||
class LinksTransmitter:
|
||||
""" The main media bar class for the "send to" function..
|
||||
|
||||
It used for direct playback of media links by the enigma2 media player.
|
||||
"""
|
||||
__STREAM_PREFIX = "4097:0:1:0:0:0:0:0:0:0:"
|
||||
|
||||
def __init__(self, http_api, app_window):
|
||||
handlers = {"on_popup_menu": self.on_popup_menu,
|
||||
"on_status_icon_activate": self.on_status_icon_activate,
|
||||
"on_query_tooltip": self.on_query_tooltip,
|
||||
"on_url_changed": self.on_url_changed,
|
||||
"on_url_activate": self.on_url_activate,
|
||||
"on_drag_data_received": self.on_drag_data_received,
|
||||
"on_exit": self.on_exit}
|
||||
"on_previous": self.on_previous,
|
||||
"on_next": self.on_next,
|
||||
"on_stop": self.on_stop,
|
||||
"on_clear": self.on_clear,
|
||||
"on_play": self.on_play}
|
||||
|
||||
self._http_api = http_api
|
||||
self._app_window = app_window
|
||||
self._is_status_icon = True
|
||||
|
||||
builder = Gtk.Builder()
|
||||
builder.set_translation_domain(TEXT_DOMAIN)
|
||||
builder.add_from_file(UI_RESOURCES_PATH + "transmitter.glade")
|
||||
builder.connect_signals(handlers)
|
||||
|
||||
self._tray = builder.get_object("status_icon")
|
||||
self._main_window = builder.get_object("main_window")
|
||||
self._url_entry = builder.get_object("url_entry")
|
||||
self._tool_bar = builder.get_object("tool_bar")
|
||||
self._popup_menu = builder.get_object("staus_popup_menu")
|
||||
self._restore_menu_item = builder.get_object("restore_menu_item")
|
||||
self._status_active = None
|
||||
self._status_passive = None
|
||||
|
||||
if IS_DARWIN:
|
||||
self._tray = builder.get_object("status_icon")
|
||||
else:
|
||||
try:
|
||||
gi.require_version("AppIndicator3", "0.1")
|
||||
from gi.repository import AppIndicator3
|
||||
except (ImportError, ValueError) as e:
|
||||
log("{}: Load library error: {}".format(__class__.__name__, e))
|
||||
self._tray = builder.get_object("status_icon")
|
||||
else:
|
||||
self._is_status_icon = False
|
||||
self._status_active = AppIndicator3.IndicatorStatus.ACTIVE
|
||||
self._status_passive = AppIndicator3.IndicatorStatus.PASSIVE
|
||||
|
||||
category = AppIndicator3.IndicatorCategory.APPLICATION_STATUS
|
||||
path = Path(UI_RESOURCES_PATH + "/icons/hicolor/scalable/apps/demon-editor.svg")
|
||||
path = str(path.resolve()) if path.is_file() else "demon-editor"
|
||||
self._tray = AppIndicator3.Indicator.new("DemonEditor", path, category)
|
||||
self._tray.set_status(self._status_active)
|
||||
self._tray.set_secondary_activate_target(builder.get_object("show_menu_item"))
|
||||
self._tray.set_menu(self._popup_menu)
|
||||
|
||||
style_provider = Gtk.CssProvider()
|
||||
style_provider.load_from_path(UI_RESOURCES_PATH + "style.css")
|
||||
@@ -33,7 +75,10 @@ class LinksTransmitter:
|
||||
Gtk.STYLE_PROVIDER_PRIORITY_USER)
|
||||
|
||||
def show(self, show):
|
||||
self._tray.set_visible(show)
|
||||
if self._is_status_icon:
|
||||
self._tray.set_visible(show)
|
||||
elif self._status_active:
|
||||
self._tray.set_status(self._status_active if show else self._status_passive)
|
||||
if not show:
|
||||
self.hide()
|
||||
|
||||
@@ -48,12 +93,12 @@ class LinksTransmitter:
|
||||
window.hide() if visible else window.show()
|
||||
self._app_window.present() if visible else self._app_window.iconify()
|
||||
|
||||
def on_query_tooltip(self, icon, g, x, y, tooltip: Gtk.Tooltip):
|
||||
if self._main_window.get_visible() or not self._url_entry.get_text():
|
||||
return False
|
||||
def on_url_changed(self, entry):
|
||||
entry.set_name("GtkEntry" if self.is_url(entry.get_text()) else "digit-entry")
|
||||
|
||||
tooltip.set_text(self._url_entry.get_text())
|
||||
return True
|
||||
def on_url_activate(self, entry):
|
||||
gen = self.activate_url(entry.get_text())
|
||||
GLib.idle_add(lambda: next(gen, False), priority=GLib.PRIORITY_LOW)
|
||||
|
||||
def on_drag_data_received(self, entry, drag_context, x, y, data, info, time):
|
||||
url = data.get_text()
|
||||
@@ -63,10 +108,10 @@ class LinksTransmitter:
|
||||
|
||||
def activate_url(self, url):
|
||||
self._url_entry.set_name("GtkEntry")
|
||||
result = urlparse(url)
|
||||
self._url_entry.set_icon_from_stock(Gtk.EntryIconPosition.SECONDARY, None)
|
||||
|
||||
if result.scheme and result.netloc:
|
||||
self._url_entry.set_sensitive(False)
|
||||
if self.is_url(url):
|
||||
self._tool_bar.set_sensitive(False)
|
||||
yt_id = YouTube.get_yt_id(url)
|
||||
yield True
|
||||
|
||||
@@ -77,22 +122,56 @@ class LinksTransmitter:
|
||||
if links:
|
||||
url = links[sorted(links, key=lambda x: int(x.rstrip("p")), reverse=True)[0]]
|
||||
else:
|
||||
self.on_play(links)
|
||||
self.on_done(links)
|
||||
return
|
||||
else:
|
||||
self._url_entry.set_icon_from_stock(Gtk.EntryIconPosition.SECONDARY, None)
|
||||
|
||||
self._http_api.send(HttpRequestType.PLAY, url, self.on_play)
|
||||
self._http_api.send(HttpRequestType.PLAY, url, self.on_done, self.__STREAM_PREFIX)
|
||||
yield True
|
||||
|
||||
def on_play(self, res):
|
||||
def on_done(self, res):
|
||||
""" Play callback """
|
||||
GLib.idle_add(self._url_entry.set_sensitive, True)
|
||||
res = res.get("e2state", None) if res else res
|
||||
self._url_entry.set_name("GtkEntry" if res else "digit-entry")
|
||||
GLib.idle_add(self._tool_bar.set_sensitive, True)
|
||||
|
||||
def on_exit(self, item=None):
|
||||
self.show(False)
|
||||
def on_previous(self, item):
|
||||
self._http_api.send(HttpRequestType.PLAYER_PREV, None, self.on_done)
|
||||
|
||||
def on_next(self, item):
|
||||
self._http_api.send(HttpRequestType.PLAYER_NEXT, None, self.on_done)
|
||||
|
||||
def on_play(self, item):
|
||||
self._http_api.send(HttpRequestType.PLAYER_PLAY, None, self.on_done)
|
||||
|
||||
def on_stop(self, item):
|
||||
self._http_api.send(HttpRequestType.PLAYER_STOP, None, self.on_done)
|
||||
|
||||
def on_clear(self, item):
|
||||
""" Remove added links in the playlist. """
|
||||
GLib.idle_add(self._tool_bar.set_sensitive, False)
|
||||
self._http_api.send(HttpRequestType.PLAYER_LIST, None, self.clear_playlist)
|
||||
|
||||
def clear_playlist(self, res):
|
||||
GLib.idle_add(self._tool_bar.set_sensitive, not res)
|
||||
if "error_code" in res:
|
||||
log("Error clearing playlist. There may be no http connection.")
|
||||
self.on_done(res)
|
||||
return
|
||||
|
||||
for ref in res:
|
||||
GLib.idle_add(self._tool_bar.set_sensitive, False)
|
||||
self._http_api.send(HttpRequestType.PLAYER_REMOVE,
|
||||
ref.get("e2servicereference", ""),
|
||||
self.on_done,
|
||||
self.__STREAM_PREFIX)
|
||||
|
||||
@staticmethod
|
||||
def is_url(text):
|
||||
""" Simple url checking. """
|
||||
result = urlparse(text)
|
||||
return result.scheme and result.netloc
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -1,78 +1,127 @@
|
||||
import locale
|
||||
import os
|
||||
from enum import Enum, IntEnum
|
||||
from functools import lru_cache
|
||||
from app.settings import Settings, SettingsException, IS_DARWIN
|
||||
|
||||
import gi
|
||||
|
||||
from app.settings import Settings, SettingsException
|
||||
gi.require_version("Gtk", "3.0")
|
||||
gi.require_version("Gdk", "3.0")
|
||||
from gi.repository import Gtk, Gdk, GLib
|
||||
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk, Gdk
|
||||
|
||||
# path to *.glade files
|
||||
UI_RESOURCES_PATH = "app/ui/" if os.path.exists("app/ui/") else "/usr/share/demoneditor/app/ui/"
|
||||
# Setting mod mask for keyboard depending on platform
|
||||
MOD_MASK = Gdk.ModifierType.MOD2_MASK if IS_DARWIN else Gdk.ModifierType.CONTROL_MASK
|
||||
# Path to *.glade files
|
||||
UI_RESOURCES_PATH = "app/ui/" if os.path.exists("app/ui/") else "ui/"
|
||||
LANG_PATH = UI_RESOURCES_PATH + "lang"
|
||||
GTK_PATH = os.environ.get("GTK_PATH", None)
|
||||
|
||||
IS_GNOME_SESSION = int(bool(os.environ.get("GNOME_DESKTOP_SESSION_ID")))
|
||||
# translation
|
||||
# Translation.
|
||||
TEXT_DOMAIN = "demon-editor"
|
||||
|
||||
try:
|
||||
settings = Settings.get_instance()
|
||||
except SettingsException:
|
||||
pass
|
||||
else:
|
||||
os.environ["LANGUAGE"] = settings.language
|
||||
if UI_RESOURCES_PATH == "app/ui/":
|
||||
locale.bindtextdomain(TEXT_DOMAIN, UI_RESOURCES_PATH + "lang")
|
||||
|
||||
if settings.is_themes_support:
|
||||
st = Gtk.Settings().get_default()
|
||||
st.set_property("gtk-theme-name", settings.theme)
|
||||
st.set_property("gtk-icon-theme-name", settings.icon_theme)
|
||||
else:
|
||||
style_provider = Gtk.CssProvider()
|
||||
s_path = "{}default_style.css".format(GTK_PATH + "/" + UI_RESOURCES_PATH if GTK_PATH else UI_RESOURCES_PATH)
|
||||
style_provider.load_from_path(s_path)
|
||||
Gtk.StyleContext.add_provider_for_screen(Gdk.Screen.get_default(), style_provider,
|
||||
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
|
||||
|
||||
if IS_DARWIN:
|
||||
import gettext
|
||||
|
||||
if GTK_PATH:
|
||||
LANG_PATH = GTK_PATH + "/share/locale"
|
||||
gettext.bindtextdomain(TEXT_DOMAIN, LANG_PATH)
|
||||
# For launching from the bundle.
|
||||
if os.getcwd() == "/" and GTK_PATH:
|
||||
os.chdir(GTK_PATH)
|
||||
else:
|
||||
import locale
|
||||
|
||||
locale.bindtextdomain(TEXT_DOMAIN, LANG_PATH)
|
||||
|
||||
theme = Gtk.IconTheme.get_default()
|
||||
theme.append_search_path(UI_RESOURCES_PATH + "icons")
|
||||
theme.append_search_path(GTK_PATH + "/share/icons" if GTK_PATH else UI_RESOURCES_PATH + "icons")
|
||||
|
||||
_IMAGE_MISSING = theme.load_icon("image-missing", 16, 0) if theme.lookup_icon("image-missing", 16, 0) else None
|
||||
CODED_ICON = theme.load_icon("emblem-readonly", 16, 0) if theme.lookup_icon(
|
||||
"emblem-readonly", 16, 0) else _IMAGE_MISSING
|
||||
LOCKED_ICON = theme.load_icon("changes-prevent-symbolic", 16, 0) if theme.lookup_icon(
|
||||
"system-lock-screen", 16, 0) else _IMAGE_MISSING
|
||||
HIDE_ICON = theme.load_icon("go-jump", 16, 0) if theme.lookup_icon("go-jump", 16, 0) else _IMAGE_MISSING
|
||||
TV_ICON = theme.load_icon("tv-symbolic", 16, 0) if theme.lookup_icon("tv-symbolic", 16, 0) else _IMAGE_MISSING
|
||||
IPTV_ICON = theme.load_icon("emblem-shared", 16, 0) if theme.lookup_icon("emblem-shared", 16, 0) else None
|
||||
EPG_ICON = theme.load_icon("gtk-index", 16, 0) if theme.lookup_icon("gtk-index", 16, 0) else None
|
||||
DEFAULT_ICON = theme.load_icon("emblem-default", 16, 0) if theme.lookup_icon("emblem-default", 16, 0) else None
|
||||
|
||||
def get_theme_icon(icon_theme, name, size):
|
||||
try:
|
||||
return icon_theme.load_icon(name, size, 0)
|
||||
except GLib.Error:
|
||||
pass
|
||||
|
||||
|
||||
_IMAGE_MISSING = get_theme_icon(theme, "image-missing", 16)
|
||||
CODED_ICON = get_theme_icon(theme, "emblem-readonly", 16) or _IMAGE_MISSING
|
||||
LOCKED_ICON = get_theme_icon(theme, "changes-prevent-symbolic", 16) or _IMAGE_MISSING
|
||||
HIDE_ICON = get_theme_icon(theme, "go-jump", 16) or _IMAGE_MISSING
|
||||
TV_ICON = get_theme_icon(theme, "tv-symbolic", 16) or _IMAGE_MISSING
|
||||
IPTV_ICON = get_theme_icon(theme, "emblem-shared", 16)
|
||||
EPG_ICON = get_theme_icon(theme, "gtk-index", 16)
|
||||
DEFAULT_ICON = get_theme_icon(theme, "emblem-default", 16)
|
||||
|
||||
|
||||
@lru_cache(maxsize=1)
|
||||
def get_yt_icon(icon_name, size=24):
|
||||
""" Getting YouTube icon. If the icon is not found in the icon themes, the "APPLY" icon is returned by default! """
|
||||
default_theme = Gtk.IconTheme.get_default()
|
||||
if default_theme.has_icon(icon_name):
|
||||
return default_theme.load_icon(icon_name, size, 0)
|
||||
|
||||
n_theme = Gtk.IconTheme.new()
|
||||
import glob
|
||||
|
||||
for theme_name in map(os.path.basename, filter(os.path.isdir, glob.glob("/usr/share/icons/*"))):
|
||||
theme.set_custom_theme(theme_name)
|
||||
if n_theme.has_icon(icon_name):
|
||||
return n_theme.load_icon(icon_name, size, 0)
|
||||
|
||||
if default_theme.lookup_icon(Gtk.STOCK_APPLY, size, 0):
|
||||
return default_theme.load_icon(Gtk.STOCK_APPLY, size, 0)
|
||||
|
||||
|
||||
class KeyboardKey(Enum):
|
||||
""" The raw(hardware) codes of the keyboard keys. """
|
||||
Q = 24
|
||||
E = 26
|
||||
R = 27
|
||||
T = 28
|
||||
U = 30
|
||||
O = 32
|
||||
P = 33
|
||||
S = 39
|
||||
D = 40
|
||||
H = 43
|
||||
L = 46
|
||||
X = 53
|
||||
C = 54
|
||||
V = 55
|
||||
B = 56
|
||||
W = 25
|
||||
Z = 52
|
||||
INSERT = 118
|
||||
HOME = 110
|
||||
END = 115
|
||||
UP = 111
|
||||
DOWN = 116
|
||||
PAGE_UP = 112
|
||||
PAGE_DOWN = 117
|
||||
LEFT = 113
|
||||
RIGHT = 114
|
||||
F2 = 68
|
||||
SPACE = 65
|
||||
DELETE = 119
|
||||
BACK_SPACE = 22
|
||||
CTRL_L = 37
|
||||
CTRL_R = 105
|
||||
F = 3 if IS_DARWIN else 41
|
||||
E = 14 if IS_DARWIN else 26
|
||||
R = 15 if IS_DARWIN else 27
|
||||
T = 17 if IS_DARWIN else 28
|
||||
P = 35 if IS_DARWIN else 33
|
||||
S = 1 if IS_DARWIN else 39
|
||||
H = 4 if IS_DARWIN else 43
|
||||
L = 37 if IS_DARWIN else 46
|
||||
X = 7 if IS_DARWIN else 53
|
||||
C = 8 if IS_DARWIN else 54
|
||||
V = 9 if IS_DARWIN else 55
|
||||
W = 13 if IS_DARWIN else 25
|
||||
Z = 6 if IS_DARWIN else 52
|
||||
INSERT = -1 if IS_DARWIN else 118
|
||||
HOME = -1 if IS_DARWIN else 110
|
||||
END = -1 if IS_DARWIN else 115
|
||||
UP = 126 if IS_DARWIN else 111
|
||||
DOWN = 125 if IS_DARWIN else 116
|
||||
PAGE_UP = -1 if IS_DARWIN else 112
|
||||
PAGE_DOWN = -1 if IS_DARWIN else 117
|
||||
LEFT = 123 if IS_DARWIN else 113
|
||||
RIGHT = 123 if IS_DARWIN else 114
|
||||
F2 = 120 if IS_DARWIN else 68
|
||||
SPACE = 49 if IS_DARWIN else 65
|
||||
DELETE = 51 if IS_DARWIN else 119
|
||||
BACK_SPACE = 76 if IS_DARWIN else 22
|
||||
CTRL_L = 55 if IS_DARWIN else 37
|
||||
CTRL_R = 55 if IS_DARWIN else 105
|
||||
# Laptop codes
|
||||
HOME_KP = 79
|
||||
END_KP = 87
|
||||
|
||||
18
build-deb.sh
18
build-deb.sh
@@ -1,18 +0,0 @@
|
||||
#!/bin/bash
|
||||
VER="0.4.7_Pre-alpha"
|
||||
B_PATH="dist/DemonEditor"
|
||||
DEB_PATH="$B_PATH/usr/share/demoneditor"
|
||||
|
||||
mkdir -p $B_PATH
|
||||
cp -TRv deb $B_PATH
|
||||
rsync --exclude=app/ui/lang --exclude=app/ui/icons -arv app $DEB_PATH
|
||||
|
||||
cd dist
|
||||
fakeroot dpkg-deb --build DemonEditor
|
||||
mv DemonEditor.deb DemonEditor_$VER.deb
|
||||
|
||||
rm -R DemonEditor
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
demon-editor for Debian
|
||||
----------------------
|
||||
DemonEditor
|
||||
Enigma2 channel and satellites list editor for GNU/Linux.
|
||||
|
||||
Experimental support of Neutrino-MP or others on the same basis (BPanther, etc).
|
||||
Focused on the convenience of working in lists from the keyboard. The mouse is also fully supported (Drag and Drop etc)
|
||||
|
||||
Keyboard shortcuts:
|
||||
Ctrl + Insert - copies the selected channels from the main list to the the bouquet beginning or inserts (creates) a new bouquet.
|
||||
Ctrl + BackSpace - copies the selected channels from the main list to the bouquet end.
|
||||
Ctrl + X - only in bouquet list. Ctrl + C - only in services list.
|
||||
Clipboard is "rubber". There is an accumulation before the insertion!
|
||||
Ctrl + E - edit.
|
||||
Ctrl + R, F2 - rename.
|
||||
Ctrl + S, T in Satellites edit tool for create satellite or transponder.
|
||||
Ctrl + L - parental lock.
|
||||
Ctrl + H - hide/skip.
|
||||
Ctrl + P - start play IPTV or other stream in the bouquet list.
|
||||
Ctrl + Z - switch (zap) the channel (works when the HTTP API is enabled, Enigma2 only).
|
||||
Ctrl + W - switch to the channel and watch in the program.
|
||||
Space - select/deselect.
|
||||
Left/Right - remove selection.
|
||||
Ctrl + Up, Down, PageUp, PageDown, Home, End - move selected items in the list.
|
||||
Ctrl + O - (re)load user data from current dir.
|
||||
Ctrl + D - load data from receiver.
|
||||
Ctrl + U/B upload data/bouquets to receiver.
|
||||
|
||||
Extra:
|
||||
Import feature.
|
||||
Multiple selections in lists only with Space key (as in file managers).
|
||||
Ability to download picons and update satellites (transponders) from web.
|
||||
Ability to import into bouquet (Neutrino WEB TV) from m3u.
|
||||
Ability to export bouquets with IPTV services to m3u.
|
||||
Assignment EPG from DVB or XML for IPTV services(Enigma2 only).
|
||||
Preview (playing) IPTV or other streams directly from the bouquet list (should be installed VLC).
|
||||
|
||||
Minimum requirements:
|
||||
Python >= 3.5.2 and GTK+ >= 3.16 with PyGObject bindings.
|
||||
|
||||
Note.
|
||||
Terrestrial(DVB-T/T2) and cable(DVB-C) channels are only supported for Enigma2!
|
||||
|
||||
Important:
|
||||
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!
|
||||
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
Package: demon-editor
|
||||
Version: 0.4.7-Pre-alpha
|
||||
Section: utils
|
||||
Priority: optional
|
||||
Architecture: all
|
||||
Essential: no
|
||||
Depends: python3 (>= 3.5)
|
||||
Maintainer: Dmitriy Yefremov <dmitry.v.yefremov@gmail.com>
|
||||
Description: Enigma2 channel and satellites list editor
|
||||
@@ -1,26 +0,0 @@
|
||||
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Contact: Dmitriy Yefremov <dmitry.v.yefremov@gmail.com>
|
||||
Source: https://github.com/DYefremov/DemonEditor
|
||||
|
||||
Files: *
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018-2020 Dmitriy Yefremov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
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.
|
||||
@@ -1 +0,0 @@
|
||||
README.source
|
||||
@@ -1,2 +0,0 @@
|
||||
#!/bin/bash
|
||||
python3 /usr/share/demoneditor/start.py $1
|
||||
@@ -1,11 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Version=1.0
|
||||
Name=DemonEditor
|
||||
Comment=Channels and satellites list editor for Enigma2
|
||||
Comment[ru]=Редактор списка каналов и спутников для Enigma2
|
||||
Icon=demon-editor
|
||||
Exec=/usr/bin/demon-editor
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=Utility;Application;
|
||||
StartupNotify=false
|
||||
@@ -1,4 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
from app.ui.main_app_window import start_app
|
||||
|
||||
start_app()
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.2 KiB |
@@ -1,634 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
id="svg1541"
|
||||
version="1.1"
|
||||
viewBox="0 0 16.743339 16.72816"
|
||||
height="63.224556"
|
||||
width="63.281971"
|
||||
sodipodi:docname="demon-editor.svg"
|
||||
inkscape:version="0.92.4 (unknown)">
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1366"
|
||||
inkscape:window-height="716"
|
||||
id="namedview127"
|
||||
showgrid="true"
|
||||
fit-margin-left="0"
|
||||
inkscape:zoom="6.1714295"
|
||||
inkscape:cx="40.088627"
|
||||
inkscape:cy="31.742631"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1541"
|
||||
fit-margin-top="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid128"
|
||||
originx="-10.604603"
|
||||
originy="-1.1727724" />
|
||||
</sodipodi:namedview>
|
||||
<title
|
||||
id="title1088">DeamonEditor Icons</title>
|
||||
<defs
|
||||
id="defs1535">
|
||||
<linearGradient
|
||||
id="linearGradient2198">
|
||||
<stop
|
||||
id="stop2194"
|
||||
style="stop-color:#ffb320;stop-opacity:1"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop2196"
|
||||
style="stop-color:#e7ff00;stop-opacity:1"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient2192">
|
||||
<stop
|
||||
offset="0"
|
||||
style="stop-color:#ffb320;stop-opacity:1"
|
||||
id="stop2188" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#b3c54c;stop-opacity:1"
|
||||
id="stop2190" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3700-8">
|
||||
<stop
|
||||
offset="0"
|
||||
style="stop-color:#2e4f84;stop-opacity:1"
|
||||
id="stop2183" />
|
||||
<stop
|
||||
offset="1"
|
||||
style="stop-color:#4c77c5;stop-opacity:1"
|
||||
id="stop2185" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="1"
|
||||
y2="0"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(13.526835,20.525875,20.525875,-13.526835,19.18986,1021.0543)"
|
||||
spreadMethod="pad"
|
||||
id="linearGradient1844">
|
||||
<stop
|
||||
style="stop-opacity:1;stop-color:#29282b"
|
||||
offset="0"
|
||||
id="stop1826" />
|
||||
<stop
|
||||
id="stop1828"
|
||||
offset="0.13293758"
|
||||
style="stop-color:#b5bdcf;stop-opacity:1" />
|
||||
<stop
|
||||
style="stop-opacity:1;stop-color:#92979f"
|
||||
offset="0.21261224"
|
||||
id="stop1832" />
|
||||
<stop
|
||||
style="stop-opacity:1;stop-color:#737881"
|
||||
offset="0.29780689"
|
||||
id="stop1834" />
|
||||
<stop
|
||||
style="stop-opacity:1;stop-color:#70757e"
|
||||
offset="0.29780689"
|
||||
id="stop1836" />
|
||||
<stop
|
||||
style="stop-opacity:1;stop-color:#e4e6e8"
|
||||
offset="0.45395693"
|
||||
id="stop1838" />
|
||||
<stop
|
||||
style="stop-opacity:1;stop-color:#696c76"
|
||||
offset="0.71871042"
|
||||
id="stop1840" />
|
||||
<stop
|
||||
style="stop-opacity:1;stop-color:#29282b"
|
||||
offset="1"
|
||||
id="stop1842" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient1754"
|
||||
spreadMethod="pad"
|
||||
gradientTransform="matrix(13.526835,20.525875,20.525875,-13.526835,19.18986,1021.0543)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
y2="0"
|
||||
x2="1"
|
||||
y1="0"
|
||||
x1="0">
|
||||
<stop
|
||||
id="stop1736"
|
||||
offset="0"
|
||||
style="stop-opacity:1;stop-color:#29282b" />
|
||||
<stop
|
||||
style="stop-color:#b5bdcf;stop-opacity:1"
|
||||
offset="0.02582242"
|
||||
id="stop1738" />
|
||||
<stop
|
||||
id="stop1740"
|
||||
offset="0.14669065"
|
||||
style="stop-opacity:1;stop-color:#868c95" />
|
||||
<stop
|
||||
id="stop1742"
|
||||
offset="0.21261224"
|
||||
style="stop-opacity:1;stop-color:#92979f" />
|
||||
<stop
|
||||
id="stop1744"
|
||||
offset="0.29780689"
|
||||
style="stop-opacity:1;stop-color:#737881" />
|
||||
<stop
|
||||
id="stop1746"
|
||||
offset="0.29780689"
|
||||
style="stop-opacity:1;stop-color:#70757e" />
|
||||
<stop
|
||||
id="stop1748"
|
||||
offset="0.45395693"
|
||||
style="stop-opacity:1;stop-color:#e4e6e8" />
|
||||
<stop
|
||||
id="stop1750"
|
||||
offset="0.71871042"
|
||||
style="stop-opacity:1;stop-color:#ffffff" />
|
||||
<stop
|
||||
id="stop1752"
|
||||
offset="1"
|
||||
style="stop-opacity:1;stop-color:#1d191a" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="1"
|
||||
y2="0"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(13.526835,20.525875,20.525875,-13.526835,19.18986,1021.0543)"
|
||||
spreadMethod="pad"
|
||||
id="linearGradient1606">
|
||||
<stop
|
||||
style="stop-opacity:1;stop-color:#29282b"
|
||||
offset="0"
|
||||
id="stop1590" />
|
||||
<stop
|
||||
id="stop1608"
|
||||
offset="0.03065561"
|
||||
style="stop-color:#b5bdcf;stop-opacity:1" />
|
||||
<stop
|
||||
style="stop-opacity:1;stop-color:#868c95"
|
||||
offset="0.1125849"
|
||||
id="stop1592" />
|
||||
<stop
|
||||
style="stop-opacity:1;stop-color:#92979f"
|
||||
offset="0.13955873"
|
||||
id="stop1594" />
|
||||
<stop
|
||||
style="stop-opacity:1;stop-color:#737881"
|
||||
offset="0.1915853"
|
||||
id="stop1596" />
|
||||
<stop
|
||||
style="stop-opacity:1;stop-color:#70757e"
|
||||
offset="0.25400829"
|
||||
id="stop1598" />
|
||||
<stop
|
||||
style="stop-opacity:1;stop-color:#e4e6e8"
|
||||
offset="0.45395693"
|
||||
id="stop1600" />
|
||||
<stop
|
||||
style="stop-opacity:1;stop-color:#ffffff"
|
||||
offset="0.71871042"
|
||||
id="stop1602" />
|
||||
<stop
|
||||
style="stop-opacity:1;stop-color:#1d191a"
|
||||
offset="1"
|
||||
id="stop1604" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient886-0">
|
||||
<stop
|
||||
style="stop-color:#535353;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop888" />
|
||||
<stop
|
||||
style="stop-color:#f0f0f0;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop890" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient1473">
|
||||
<stop
|
||||
id="stop1469"
|
||||
offset="0"
|
||||
style="stop-color:#ffffff;stop-opacity:0" />
|
||||
<stop
|
||||
id="stop1471"
|
||||
offset="1"
|
||||
style="stop-color:#ffffff;stop-opacity:0.96088022" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient2447-35">
|
||||
<stop
|
||||
id="stop2449"
|
||||
offset="0"
|
||||
style="stop-color:#00c62e;stop-opacity:1" />
|
||||
<stop
|
||||
id="stop2451"
|
||||
offset="1"
|
||||
style="stop-color:#136100;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3795-1">
|
||||
<stop
|
||||
id="stop3797-1"
|
||||
offset="0"
|
||||
style="stop-color:#803400;stop-opacity:1" />
|
||||
<stop
|
||||
id="stop3799-3"
|
||||
offset="1"
|
||||
style="stop-color:#c87137;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient2447-3">
|
||||
<stop
|
||||
style="stop-color:#c60300;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop2443" />
|
||||
<stop
|
||||
style="stop-color:#c40e00;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop2445" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient2458">
|
||||
<stop
|
||||
id="stop2454"
|
||||
offset="0"
|
||||
style="stop-color:#c60300;stop-opacity:1" />
|
||||
<stop
|
||||
id="stop2456"
|
||||
offset="1"
|
||||
style="stop-color:#ee6000;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3519">
|
||||
<stop
|
||||
id="stop3521"
|
||||
offset="0"
|
||||
style="stop-color:#1d2120;stop-opacity:1" />
|
||||
<stop
|
||||
id="stop3523"
|
||||
offset="1"
|
||||
style="stop-color:#545d5d;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient1446">
|
||||
<stop
|
||||
id="stop1442"
|
||||
offset="0"
|
||||
style="stop-color:#ffffff;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop1444"
|
||||
offset="1"
|
||||
style="stop-color:#ffffff;stop-opacity:0;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient1547"
|
||||
spreadMethod="pad"
|
||||
gradientTransform="matrix(13.526835,20.525875,20.525875,-13.526835,19.18986,1021.0543)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
y2="0"
|
||||
x2="1"
|
||||
y1="0"
|
||||
x1="0">
|
||||
<stop
|
||||
id="stop1529"
|
||||
offset="0"
|
||||
style="stop-opacity:1;stop-color:#ffffff" />
|
||||
<stop
|
||||
id="stop1531"
|
||||
offset="0.0263736"
|
||||
style="stop-opacity:1;stop-color:#29282b" />
|
||||
<stop
|
||||
id="stop1533"
|
||||
offset="0.263736"
|
||||
style="stop-opacity:1;stop-color:#868c95" />
|
||||
<stop
|
||||
id="stop1535"
|
||||
offset="0.395604"
|
||||
style="stop-opacity:1;stop-color:#92979f" />
|
||||
<stop
|
||||
id="stop1537"
|
||||
offset="0.39560401"
|
||||
style="stop-opacity:1;stop-color:#737881" />
|
||||
<stop
|
||||
id="stop1539"
|
||||
offset="0.42333773"
|
||||
style="stop-opacity:1;stop-color:#70757e" />
|
||||
<stop
|
||||
id="stop1541"
|
||||
offset="0.56268591"
|
||||
style="stop-opacity:1;stop-color:#e4e6e8" />
|
||||
<stop
|
||||
id="stop1543"
|
||||
offset="0.62400264"
|
||||
style="stop-opacity:1;stop-color:#ffffff" />
|
||||
<stop
|
||||
id="stop1545"
|
||||
offset="1"
|
||||
style="stop-opacity:1;stop-color:#1d191a" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient1527"
|
||||
spreadMethod="pad"
|
||||
gradientTransform="matrix(13.526835,20.525875,20.525875,-13.526835,19.18986,1021.0543)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
y2="0"
|
||||
x2="1"
|
||||
y1="0"
|
||||
x1="0">
|
||||
<stop
|
||||
id="stop1509"
|
||||
offset="0"
|
||||
style="stop-opacity:1;stop-color:#ffffff" />
|
||||
<stop
|
||||
id="stop1511"
|
||||
offset="0.0527472"
|
||||
style="stop-opacity:1;stop-color:#29282b" />
|
||||
<stop
|
||||
id="stop1513"
|
||||
offset="0.142147"
|
||||
style="stop-opacity:1;stop-color:#868c95" />
|
||||
<stop
|
||||
id="stop1515"
|
||||
offset="0.19700864"
|
||||
style="stop-opacity:1;stop-color:#92979f" />
|
||||
<stop
|
||||
id="stop1517"
|
||||
offset="0.25031137"
|
||||
style="stop-opacity:1;stop-color:#737881" />
|
||||
<stop
|
||||
id="stop1519"
|
||||
offset="0.3710371"
|
||||
style="stop-opacity:1;stop-color:#70757e" />
|
||||
<stop
|
||||
id="stop1521"
|
||||
offset="0.53961843"
|
||||
style="stop-opacity:1;stop-color:#e4e6e8" />
|
||||
<stop
|
||||
id="stop1523"
|
||||
offset="0.76283824"
|
||||
style="stop-opacity:1;stop-color:#ffffff" />
|
||||
<stop
|
||||
id="stop1525"
|
||||
offset="1"
|
||||
style="stop-opacity:1;stop-color:#1d191a" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
gradientTransform="matrix(0.26458333,0,0,0.26458333,-5.8254634,-78.732754)"
|
||||
y2="1179.7145"
|
||||
x2="66.791626"
|
||||
y1="1188.7661"
|
||||
x1="99.044022"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient1485"
|
||||
xlink:href="#linearGradient1473" />
|
||||
<linearGradient
|
||||
gradientTransform="matrix(0.26458333,0,0,0.26458333,-2.2733744,-70.526334)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
y2="1155.8046"
|
||||
x2="67.311417"
|
||||
y1="1161.6112"
|
||||
x1="77.19442"
|
||||
id="linearGradient1448"
|
||||
xlink:href="#linearGradient1446" />
|
||||
<linearGradient
|
||||
gradientTransform="matrix(0.26458333,0,0,0.26458333,-18.198747,-79.859424)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
y2="1186.8096"
|
||||
x2="146.16808"
|
||||
y1="1186.8096"
|
||||
x1="131.86871"
|
||||
id="linearGradient2180"
|
||||
xlink:href="#linearGradient886-0" />
|
||||
<linearGradient
|
||||
gradientTransform="matrix(0.20863982,0,0,0.20863982,-0.63935937,-13.031239)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
y2="1184.73"
|
||||
x2="101.19952"
|
||||
y1="1184.73"
|
||||
x1="83.066002"
|
||||
id="linearGradient2160"
|
||||
xlink:href="#linearGradient886-0" />
|
||||
<linearGradient
|
||||
gradientTransform="matrix(0.26458333,0,0,0.26458333,-6.2370714,-102.12414)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
y2="1267.1335"
|
||||
x2="117.99127"
|
||||
y1="1267.1335"
|
||||
x1="75.853806"
|
||||
id="linearGradient2131"
|
||||
xlink:href="#linearGradient886-0" />
|
||||
<linearGradient
|
||||
id="linearGradient3700-8-3">
|
||||
<stop
|
||||
id="stop3702-1"
|
||||
style="stop-color:#2e4f84;stop-opacity:1"
|
||||
offset="0" />
|
||||
<stop
|
||||
id="stop3704-8"
|
||||
style="stop-color:#4c77c5;stop-opacity:1"
|
||||
offset="1" />
|
||||
</linearGradient>
|
||||
<defs
|
||||
id="defs4922">
|
||||
<filter
|
||||
style="color-interpolation-filters:sRGB"
|
||||
id="Adobe_OpacityMaskFilter"
|
||||
filterUnits="userSpaceOnUse"
|
||||
x="3.7850001"
|
||||
y="4.6750002"
|
||||
width="5.8829999"
|
||||
height="73.013">
|
||||
<feColorMatrix
|
||||
type="matrix"
|
||||
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0"
|
||||
id="feColorMatrix4925" />
|
||||
</filter>
|
||||
</defs>
|
||||
<mask
|
||||
maskUnits="userSpaceOnUse"
|
||||
x="3.785"
|
||||
y="4.675"
|
||||
width="5.883"
|
||||
height="73.013"
|
||||
id="SVGID_2_">
|
||||
<g
|
||||
style="filter:url(#Adobe_OpacityMaskFilter)"
|
||||
id="g4928">
|
||||
<linearGradient
|
||||
id="SVGID_3_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="3.7852001"
|
||||
y1="41.181198"
|
||||
x2="9.6680002"
|
||||
y2="41.181198">
|
||||
<stop
|
||||
offset="0"
|
||||
style="stop-color:#FFFFFF"
|
||||
id="stop4931" />
|
||||
<stop
|
||||
offset="0.0029"
|
||||
style="stop-color:#FAFBFB"
|
||||
id="stop4933" />
|
||||
<stop
|
||||
offset="0.0756"
|
||||
style="stop-color:#BBBDBF"
|
||||
id="stop4935" />
|
||||
<stop
|
||||
offset="0.1438"
|
||||
style="stop-color:#898B8E"
|
||||
id="stop4937" />
|
||||
<stop
|
||||
offset="0.2053"
|
||||
style="stop-color:#646567"
|
||||
id="stop4939" />
|
||||
<stop
|
||||
offset="0.259"
|
||||
style="stop-color:#444446"
|
||||
id="stop4941" />
|
||||
<stop
|
||||
offset="0.3028"
|
||||
style="stop-color:#1D1C1D"
|
||||
id="stop4943" />
|
||||
<stop
|
||||
offset="0.3313"
|
||||
style="stop-color:#000000"
|
||||
id="stop4945" />
|
||||
</linearGradient>
|
||||
<rect
|
||||
style="fill:url(#SVGID_3_)"
|
||||
x="3.7850001"
|
||||
y="4.6750002"
|
||||
width="5.8829999"
|
||||
height="73.013"
|
||||
id="rect4947" />
|
||||
</g>
|
||||
</mask>
|
||||
<filter
|
||||
style="color-interpolation-filters:sRGB"
|
||||
id="filter1268"
|
||||
filterUnits="userSpaceOnUse"
|
||||
x="3.7850001"
|
||||
y="4.6750002"
|
||||
width="5.8829999"
|
||||
height="73.013">
|
||||
<feColorMatrix
|
||||
type="matrix"
|
||||
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0"
|
||||
id="feColorMatrix1266" />
|
||||
</filter>
|
||||
<linearGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
y2="203.22046"
|
||||
x2="23.551136"
|
||||
y1="203.22046"
|
||||
x1="13.487289"
|
||||
id="linearGradient1160"
|
||||
xlink:href="#linearGradient3519" />
|
||||
<clipPath
|
||||
id="clipPath1890"
|
||||
clipPathUnits="userSpaceOnUse">
|
||||
<circle
|
||||
style="opacity:1;fill:#2d2d2d;fill-opacity:1;stroke:#434242;stroke-width:0.0575568;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="circle1892"
|
||||
cx="78.548424"
|
||||
cy="-31.019459"
|
||||
r="6.4721422"
|
||||
transform="scale(1,-1)" />
|
||||
</clipPath>
|
||||
<linearGradient
|
||||
gradientTransform="translate(-0.24389927,14.877856)"
|
||||
y2="27.314217"
|
||||
x2="84.864914"
|
||||
y1="27.314217"
|
||||
x1="72.164909"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient2134"
|
||||
xlink:href="#linearGradient3700-8-3" />
|
||||
</defs>
|
||||
<metadata
|
||||
id="metadata1538">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title>DeamonEditor Icons</dc:title>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>mfgeg</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:date>7.1.2020</dc:date>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
transform="matrix(1.1690805,0,0,1.1690805,-14.929261,-167.45253)"
|
||||
id="layer1">
|
||||
<g
|
||||
transform="translate(0.86526724,-82.691658)"
|
||||
id="g1351">
|
||||
<path
|
||||
d="m 13.715358,227.65981 h 2.97616 v 12.57332 h -2.97616 z m 5.79826,-1.73376 -0.327076,0.42227 c -0.179879,0.23226 -0.586303,0.67932 -0.903223,0.99412 -0.480677,0.47726 -0.640897,0.57235 -0.967777,0.57235 -0.223557,0 -0.380895,-0.0584 -0.624024,-0.25067 v 3.18307 c 0.172884,-0.0214 0.359647,-0.0333 0.575071,-0.0352 0.68403,-0.006 0.91815,0.0416 1.436333,0.29581 1.14586,0.56274 1.762492,1.5589 1.768251,2.8566 0.0094,2.10836 -1.870896,3.55161 -3.779655,3.16529 v 3.10345 c 4.345352,0.0758 4.093104,-2.37537 6.573781,-2.25837 1.486139,0.0748 1.333421,0.16555 1.796225,-1.064 l 0.259834,-0.6913 -0.803704,-0.66493 c -0.960855,-0.79478 -1.303983,-1.29079 -1.205013,-1.74132 0.06631,-0.30189 1.20818,-1.50093 1.779011,-1.86778 0.240181,-0.1543 0.244255,-0.17878 0.09575,-0.59661 -0.08522,-0.23979 -0.259522,-0.65746 -0.386789,-0.92744 l -0.23132,-0.49115 h -1.412666 c -1.868582,0 -1.802386,0.068 -1.805368,-1.82472 l -0.0021,-1.43582 -0.917745,-0.37171 z"
|
||||
style="opacity:1;fill:#000000;fill-opacity:0.5372549;stroke:none;stroke-width:0.18460207;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.5012225"
|
||||
id="path2133"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path2106"
|
||||
style="opacity:1;fill:url(#linearGradient2131);fill-opacity:1;stroke:none;stroke-width:0.17733108;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.5012225"
|
||||
d="m 13.832581,227.93117 h 2.858936 v 12.07807 h -2.858936 z m 5.569881,-1.6655 -0.314194,0.40566 c -0.172793,0.22309 -0.563209,0.65257 -0.867647,0.95496 -0.46174,0.45847 -0.615654,0.5498 -0.929658,0.5498 -0.214752,0 -0.365893,-0.056 -0.599446,-0.24079 v 3.05768 c 0.166077,-0.0206 0.345483,-0.0319 0.55242,-0.0338 0.657089,-0.006 0.881987,0.0399 1.379764,0.28416 1.100724,0.54057 1.693073,1.49747 1.698606,2.74408 0.009,2.02535 -1.797211,3.41174 -3.63079,3.04061 v 2.98122 c 4.174205,0.0728 3.931888,-2.28179 6.314859,-2.1694 1.427604,0.0718 1.2809,0.15902 1.725477,-1.02213 l 0.249597,-0.66408 -0.772046,-0.63871 c -0.923009,-0.76345 -1.252622,-1.23996 -1.157552,-1.67277 0.0637,-0.29001 1.160592,-1.44177 1.708939,-1.79419 0.230721,-0.14825 0.234635,-0.17174 0.09198,-0.57312 -0.08187,-0.23032 -0.249296,-0.63156 -0.371555,-0.89088 l -0.222207,-0.4718 h -1.357022 c -1.794983,0 -1.731396,0.0653 -1.734262,-1.75284 l -0.0021,-1.3793 -0.881603,-0.35705 z"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path2151"
|
||||
d="m 17.266983,230.95755 c -0.215637,0.003 -0.402408,0.014 -0.575465,0.0354 v 6.28854 c 1.910653,0.38671 3.792716,-1.05815 3.783336,-3.16865 -0.0058,-1.29897 -0.623064,-2.29597 -1.770059,-2.85927 -0.518699,-0.25451 -0.753103,-0.30234 -1.437812,-0.29607 z m 0.482341,1.17002 c 0.433747,-0.004 0.582202,0.0265 0.910784,0.18761 0.726595,0.35682 1.117604,0.98848 1.121256,1.81134 0.0059,1.33694 -1.186343,2.25211 -2.396695,2.00715 v -3.98359 c 0.109628,-0.0135 0.228054,-0.0214 0.364655,-0.0225 z"
|
||||
style="opacity:1;fill:url(#linearGradient2160);fill-opacity:1;stroke:none;stroke-width:0.18478528;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.5012225"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="opacity:1;fill:none;fill-opacity:1;stroke:url(#linearGradient2180);stroke-width:0.18478528;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.5012225"
|
||||
d="m 17.266981,230.95753 c -0.215636,0.003 -0.402408,0.014 -0.575464,0.0354 v 6.28853 c 1.910652,0.38672 3.792715,-1.05815 3.783336,-3.16865 -0.0057,-1.29897 -0.623065,-2.29597 -1.77006,-2.85927 -0.518697,-0.2545 -0.753103,-0.30234 -1.437812,-0.29607 z m 0.482343,1.17001 c 0.433747,-0.004 0.5822,0.0265 0.910783,0.18762 0.726594,0.35681 1.117605,0.98848 1.121257,1.81133 0.006,1.33694 -1.186344,2.25211 -2.396697,2.00716 v -3.98359 c 0.109628,-0.0135 0.228055,-0.0214 0.364657,-0.0225 z"
|
||||
id="path2170"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path1422"
|
||||
d="m 17.266983,230.95755 c -0.215637,0.003 -0.402408,0.014 -0.575464,0.0354 v 6.28854 c 1.910652,0.38671 3.792715,-1.05815 3.783335,-3.16865 -0.0057,-1.29897 -0.623064,-2.29597 -1.770059,-2.85927 -0.518699,-0.25451 -0.753103,-0.30234 -1.437812,-0.29607 z m 0.482342,1.17002 c 0.433748,-0.004 0.582201,0.0265 0.910784,0.18761 0.726594,0.35682 1.117605,0.98848 1.121257,1.81134 0.006,1.33694 -1.186344,2.25211 -2.396697,2.00715 v -3.98359 c 0.109628,-0.0135 0.228054,-0.0214 0.364656,-0.0225 z"
|
||||
style="opacity:1;fill:none;fill-opacity:1;stroke:url(#linearGradient1448);stroke-width:0.1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
id="path1454"
|
||||
d="m 19.402462,226.26149 -0.314194,0.40566 c -0.172793,0.22309 -0.563209,0.65259 -0.867644,0.95499 -0.461741,0.45847 -0.615657,0.54983 -0.929661,0.54983 -0.214752,0 -0.365893,-0.056 -0.599446,-0.2408 v -0.004 h -2.858741 v 12.0783 h 2.858741 c 4.174205,0.0728 3.931888,-2.28177 6.314861,-2.16937 1.427604,0.0718 1.280898,0.15899 1.725475,-1.02217 l 0.249597,-0.66402 -0.772046,-0.63873 c -0.923009,-0.76346 -1.252622,-1.23997 -1.157552,-1.67278 0.0637,-0.29001 1.160595,-1.44176 1.708939,-1.79419 0.230721,-0.14825 0.234635,-0.17171 0.09198,-0.57309 -0.08187,-0.23032 -0.249296,-0.63158 -0.371555,-0.8909 l -0.222207,-0.47181 h -1.357025 c -1.794983,0 -1.731393,0.0653 -1.734259,-1.75286 l -0.0021,-1.37925 -0.8816,-0.35708 z"
|
||||
style="opacity:1;fill:none;fill-opacity:1;stroke:url(#linearGradient1485);stroke-width:0.1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
<g
|
||||
transform="translate(63.49728,-55.136805)"
|
||||
id="g1174" />
|
||||
<g
|
||||
transform="translate(50.48327,11.624037)"
|
||||
id="g1812" />
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 22 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
dist/DemonEditor.app.zip
vendored
Normal file
BIN
dist/DemonEditor.app.zip
vendored
Normal file
Binary file not shown.
@@ -1,18 +1,18 @@
|
||||
# Copyright (C) 2018-2019 Dmitriy Yefremov
|
||||
# Copyright (C) 2018-2020 Dmitriy Yefremov
|
||||
# This file is distributed under the MIT license.
|
||||
#
|
||||
#Charly, 2019.
|
||||
#
|
||||
# Charly, 2019.
|
||||
# Dmitriy Yefremov, 2020.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Last-Translator: Charly\n"
|
||||
"Last-Translator: Dmitriy Yefremov\n"
|
||||
"Language: de\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
msgid "translator-credits"
|
||||
msgstr "Charly"
|
||||
msgstr "Charly, Dmitriy Yefremov"
|
||||
|
||||
# Main
|
||||
msgid "Service"
|
||||
@@ -672,7 +672,7 @@ msgid "Disabled"
|
||||
msgstr "Ausgeschaltet"
|
||||
|
||||
msgid "Enable ver. 5 support (experimental)"
|
||||
msgstr "Ver.5 Unterstützung aktivieren (experimentell)"
|
||||
msgstr "Lamedb ver. 5 Unterstützung aktivieren (experimentell)"
|
||||
|
||||
msgid "Enable HTTP API (experimental)"
|
||||
msgstr "HTTP-API aktivieren (experimentell)"
|
||||
@@ -684,4 +684,306 @@ msgid "Switch the channel and watch in the program(Ctrl + W)"
|
||||
msgstr "Kanal wechseln und im Programm ansehen(Strg + W)"
|
||||
|
||||
msgid "Play IPTV or other stream in the program(Ctrl + P)"
|
||||
msgstr "Wiedergabe von IPTV oder anderen Streams im Programm(Strg + P)"
|
||||
msgstr "Wiedergabe von IPTV oder anderen Streams im Programm(Strg + P)"
|
||||
|
||||
msgid "Export to m3u"
|
||||
msgstr "Export nach m3u"
|
||||
|
||||
msgid "EPG configuration"
|
||||
msgstr "EPG Konfiguration"
|
||||
|
||||
msgid "Apply"
|
||||
msgstr "Anwenden"
|
||||
|
||||
msgid "EPG source"
|
||||
msgstr "EPG Quelle"
|
||||
|
||||
msgid "Service names source:"
|
||||
msgstr "Quelle der Dienstnamen:"
|
||||
|
||||
msgid "Main service list"
|
||||
msgstr "Hauptdienstliste"
|
||||
|
||||
msgid "XML file"
|
||||
msgstr "XML-Datei"
|
||||
|
||||
msgid "Use web source"
|
||||
msgstr "Web-Quelle verwenden"
|
||||
|
||||
msgid "Url to *.xml.gz file:"
|
||||
msgstr "Url zur *.xml.gz Datei:"
|
||||
|
||||
msgid "Enable filtering"
|
||||
msgstr "Filterung einschalten"
|
||||
|
||||
msgid "Filter by presence in the epg.dat file."
|
||||
msgstr "Filtern nach dem Vorhandensein in der epg.dat Datei."
|
||||
|
||||
msgid "Paths to the epg.dat file:"
|
||||
msgstr "Pfade zur epg.dat Datei:"
|
||||
|
||||
msgid "Local path:"
|
||||
msgstr "Local path:"
|
||||
|
||||
msgid "STB path:"
|
||||
msgstr "STB-Pfad:"
|
||||
|
||||
msgid "Update on start"
|
||||
msgstr "Update beim Start"
|
||||
|
||||
msgid "Auto configuration by service names."
|
||||
msgstr "Automatische Konfiguration nach Dienstnamen."
|
||||
|
||||
msgid "Save list to xml."
|
||||
msgstr "Liste in XML speichern."
|
||||
|
||||
msgid "Download XML file error."
|
||||
msgstr "Fehler beim Herunterladen der XML-Datei."
|
||||
|
||||
msgid "Unsupported file type:"
|
||||
msgstr "Nicht unterstützter Dateityp:"
|
||||
|
||||
msgid "Unpacking data error."
|
||||
msgstr "Fehler beim Entpacken von Daten."
|
||||
|
||||
msgid "XML parsing error:"
|
||||
msgstr "XML Parsing-Fehler:"
|
||||
|
||||
msgid "Count of successfully configured services:"
|
||||
msgstr "Anzahl der erfolgreich konfigurierten Dienste:"
|
||||
|
||||
msgid "Current epg.dat file does not contains references for the services of this bouquet!"
|
||||
msgstr "Die aktuelle epg.dat Datei enthält keine Referenzen für die Dienste dieses Bouquets!"
|
||||
|
||||
msgid "Use HTTP"
|
||||
msgstr "HTTP verwenden"
|
||||
|
||||
msgid "Close playback"
|
||||
msgstr "Wiedergabe schliessen"
|
||||
|
||||
msgid "Import YouTube playlist"
|
||||
msgstr "YouTube-Wiedergabeliste importieren"
|
||||
|
||||
msgid ""
|
||||
"Found a link to the YouTube resource!\n"
|
||||
"Try to get a direct link to the video?"
|
||||
msgstr ""
|
||||
"Ich habe einen Link zur YouTube-Ressource gefunden!\n"
|
||||
"Versuchen einen direkten Link zum Video zu bekommen?"
|
||||
|
||||
msgid "Playlist import"
|
||||
msgstr "Playlist-Import"
|
||||
|
||||
msgid "Getting link error:"
|
||||
msgstr "Link-Fehler erhalten:"
|
||||
|
||||
msgid "Extra"
|
||||
msgstr "Extra"
|
||||
|
||||
msgid "Apply profile settings"
|
||||
msgstr "Profileinstellungen anwenden"
|
||||
|
||||
msgid "Settings type:"
|
||||
msgstr "Art der Einstellungen:"
|
||||
|
||||
msgid "Set default"
|
||||
msgstr "Standard setzen"
|
||||
|
||||
msgid "Language:"
|
||||
msgstr "Sprache:"
|
||||
|
||||
msgid "Load the last open configuration at program startup"
|
||||
msgstr "Laden der zuletzt geöffneten Konfiguration beim Programmstart"
|
||||
|
||||
msgid "Enable direct playback bar (experimental)"
|
||||
msgstr "Aktivieren der direkten Wiedergabeleiste (experimentell)"
|
||||
|
||||
msgid "Enables direct sending and playback of media links on the receiver"
|
||||
msgstr "Ermöglicht das direkte Senden und Abspielen von Medienlinks auf dem Box"
|
||||
|
||||
msgid "Watch the channel in the program"
|
||||
msgstr "Gucken den Kanal im Programm an"
|
||||
|
||||
msgid "Zap and Play"
|
||||
msgstr "Zap und Abspielen"
|
||||
|
||||
msgid "Drag or paste the link here"
|
||||
msgstr "Ziehe den Link hierher oder füge ihn ein"
|
||||
|
||||
msgid "Remove added links in the playlist"
|
||||
msgstr "Hinzugefügte Links in der Wiedergabeliste entfernen"
|
||||
|
||||
msgid "A bouquet with that name exists!"
|
||||
msgstr "Bouquet mit diesem Namen existiert!"
|
||||
|
||||
msgid "Details"
|
||||
msgstr "Details"
|
||||
|
||||
msgid "Profile"
|
||||
msgstr "Profil"
|
||||
|
||||
msgid "Reset"
|
||||
msgstr "Reset"
|
||||
|
||||
msgid "File"
|
||||
msgstr "Ablage"
|
||||
|
||||
msgid "Picons manager"
|
||||
msgstr "Picons-Manager"
|
||||
|
||||
msgid "Explorer"
|
||||
msgstr ""
|
||||
|
||||
msgid "Satellite url:"
|
||||
msgstr "Satellit URL:"
|
||||
|
||||
msgid "Cut"
|
||||
msgstr "Ausschneiden"
|
||||
|
||||
msgid "Paste"
|
||||
msgstr "Einfügen"
|
||||
|
||||
msgid "To the top"
|
||||
msgstr "Zum Anfang"
|
||||
|
||||
msgid "To the end"
|
||||
msgstr "Zum Ende"
|
||||
|
||||
msgid "View"
|
||||
msgstr "Darstellung"
|
||||
|
||||
msgid "Lock"
|
||||
msgstr "Sperre"
|
||||
|
||||
msgid "Parent lock"
|
||||
msgstr "Elternsperre"
|
||||
|
||||
msgid "Hide/Skip"
|
||||
msgstr "Ausblenden/Überspringen"
|
||||
|
||||
msgid "IPTV tools"
|
||||
msgstr "IPTV-Tools"
|
||||
|
||||
msgid "Make profile folder as default for the additional data"
|
||||
msgstr "Profilordner als Standard für die zusätzlichen Daten festlegen"
|
||||
|
||||
msgid "Default data path:"
|
||||
msgstr "Standard-Datenpfad:"
|
||||
|
||||
msgid "Streams record path:"
|
||||
msgstr "Streams Aufnahmepfad:"
|
||||
|
||||
msgid "Record"
|
||||
msgstr "Aufnahme"
|
||||
|
||||
msgid "Record:"
|
||||
msgstr "Aufnahme:"
|
||||
|
||||
msgid "Record to disk:"
|
||||
msgstr "Aufnahme auf Festplatte:"
|
||||
|
||||
msgid "Streaming"
|
||||
msgstr "Streaming"
|
||||
|
||||
msgid "Activate transcoding"
|
||||
msgstr "Aktivieren der Transkodierung"
|
||||
|
||||
msgid "Presets:"
|
||||
msgstr "Voreinstellungen:"
|
||||
|
||||
msgid "Video options:"
|
||||
msgstr "Video-Optionen:"
|
||||
|
||||
msgid "Audio options:"
|
||||
msgstr "Audio-Optionen:"
|
||||
|
||||
msgid "Bitrate (kb/s):"
|
||||
msgstr "Bitrate (kb/s):"
|
||||
|
||||
msgid "Codec:"
|
||||
msgstr "Codec:"
|
||||
|
||||
msgid "Width (px):"
|
||||
msgstr "Breite (px):"
|
||||
|
||||
msgid "Height (px):"
|
||||
msgstr "Höhe (px):"
|
||||
|
||||
msgid "Channels:"
|
||||
msgstr "Kanälen:"
|
||||
|
||||
msgid "Sample rate (Hz):"
|
||||
msgstr "Samplerate (Hz):"
|
||||
|
||||
msgid "Play streams mode:"
|
||||
msgstr "Streams Abspielen-Modus:"
|
||||
|
||||
msgid "Built-in player"
|
||||
msgstr "Integrierter Player"
|
||||
|
||||
msgid "VLC media player"
|
||||
msgstr "VLC Media Player"
|
||||
|
||||
msgid "Only get m3u file"
|
||||
msgstr "Nur m3u-Datei erhalten"
|
||||
|
||||
msgid "Save and restart the program to apply the settings."
|
||||
msgstr "Speicher und starte das Programm neu, um die Einstellungen zu übernehmen."
|
||||
|
||||
msgid "Some images may have problems displaying the favorites list!"
|
||||
msgstr "Einige Images können Probleme mit der Anzeige der Favoritenliste haben!"
|
||||
|
||||
msgid "Operates in standby mode or current active transponder!"
|
||||
msgstr "Arbeitet im Standby-Modus oder auf dem aktuell aktiven Transponder!"
|
||||
|
||||
msgid "No connection to the receiver!"
|
||||
msgstr "Keine Verbindung zum Box!"
|
||||
|
||||
msgid "Signal level"
|
||||
msgstr "Signalpegel"
|
||||
|
||||
msgid "Receiver info"
|
||||
msgstr "Box-Info"
|
||||
|
||||
msgid "A profile with that name exists!"
|
||||
msgstr "Ein Profil mit diesem Namen existiert!"
|
||||
|
||||
msgid "Show short info as hints in the main services list"
|
||||
msgstr "Kurzinfos als Tooltips in der Hauptliste anzeigen"
|
||||
|
||||
msgid "Show detailed info as hints in the bouquet list"
|
||||
msgstr "Detaillierteinfos als Tooltips in der Bouquetliste anzeigen"
|
||||
|
||||
msgid "Enable alternate bouquet file naming"
|
||||
msgstr "Aktivieren der Alternativerbenennung für Bouquet-Dateien"
|
||||
|
||||
msgid "Allows you to name bouquet files using their names."
|
||||
msgstr "Ermöglicht Bouquet-Dateien mit ihren Namen zu benennen."
|
||||
|
||||
msgid "Appearance"
|
||||
msgstr "Aussehen"
|
||||
|
||||
msgid "Enable Themes support"
|
||||
msgstr "Unterstützung von Themen aktivieren"
|
||||
|
||||
msgid "Gtk3 Theme:"
|
||||
msgstr "Gtk3-Theme:"
|
||||
|
||||
msgid "Icon Theme:"
|
||||
msgstr "Icon-Theme:"
|
||||
|
||||
msgid "Gtk3 Themes and Icons:"
|
||||
msgstr "Gtk3 Themes and Icons:"
|
||||
|
||||
msgid "Deleting data..."
|
||||
msgstr "Daten löschen..."
|
||||
|
||||
msgid "Download from the receiver"
|
||||
msgstr "Downloaden vom Receiver"
|
||||
|
||||
msgid "Remove all picons from the receiver"
|
||||
msgstr "Alle Picons aus dem Receiver entfernen"
|
||||
|
||||
msgid "Service reference"
|
||||
msgstr "Kanalreferenz"
|
||||
|
||||
|
||||
@@ -486,7 +486,7 @@ msgid "STB file paths:"
|
||||
msgstr "Rutas de ficheros del receptor:"
|
||||
|
||||
msgid "Local file paths:"
|
||||
msgstr "Rutas de ficheros local:"
|
||||
msgstr "Rutas de ficheros locales:"
|
||||
|
||||
# Dialogs messages
|
||||
msgid "Error. No bouquet is selected!"
|
||||
@@ -620,7 +620,7 @@ msgid "Before downloading from the receiver"
|
||||
msgstr "Antes de recibir del receptor"
|
||||
|
||||
msgid "Set background color for the services"
|
||||
msgstr "Determinar color de fondo de los servicios"
|
||||
msgstr "Fijar color de fondo de los servicios"
|
||||
|
||||
msgid "Marked as new:"
|
||||
msgstr "Marcado como nuevo:"
|
||||
@@ -666,7 +666,7 @@ msgid "Test connection"
|
||||
msgstr "Probar conexión"
|
||||
|
||||
msgid "Double click on the service in the bouquet list:"
|
||||
msgstr "Haga doble clic en el servicio en la lista de bouquet:"
|
||||
msgstr "Al hacer doble clic en el servicio en la lista de bouquet:"
|
||||
|
||||
msgid "Zap"
|
||||
msgstr "Zapear"
|
||||
@@ -771,10 +771,49 @@ msgid "Import YouTube playlist"
|
||||
msgstr "Importar lista de reproducción de YouTube"
|
||||
|
||||
msgid "Found a link to the YouTube resource!\nTry to get a direct link to the video?"
|
||||
msgstr "¡Encontrado enlace al recurso de YouTube!\n¿Intentar obtener un enlace directo al vídeo?"
|
||||
msgstr "¡Se ha encontrado enlace al recurso de YouTube!\n¿Intentar obtener un enlace directo al vídeo?"
|
||||
|
||||
msgid "Playlist import"
|
||||
msgstr "Importar lista de reproducción"
|
||||
|
||||
msgid "Getting link error:"
|
||||
msgstr "Error en el enlace:"
|
||||
|
||||
msgid "Extra"
|
||||
msgstr "Extra"
|
||||
|
||||
msgid "Apply profile settings"
|
||||
msgstr "Aplicar ajustes de perfil"
|
||||
|
||||
msgid "Settings type:"
|
||||
msgstr "Tipo de ajustes:"
|
||||
|
||||
msgid "Set default"
|
||||
msgstr "Por defecto"
|
||||
|
||||
msgid "Language:"
|
||||
msgstr "Idioma:"
|
||||
|
||||
msgid "Load the last open configuration at program startup"
|
||||
msgstr "Cargar la última configuración abierta al iniciar el programa"
|
||||
|
||||
msgid "Enable direct playback bar (experimental)"
|
||||
msgstr "Habilitar la barra de reproducción directa (experimental)"
|
||||
|
||||
msgid "Enables direct sending and playback of media links on the receiver"
|
||||
msgstr "Habilita el envío directo y la reproducción de enlaces de medios en el receptor"
|
||||
|
||||
msgid "Watch the channel in the program"
|
||||
msgstr "Ver el canal en el programa"
|
||||
|
||||
msgid "Zap and Play"
|
||||
msgstr "Zapear y reproducir"
|
||||
|
||||
msgid "Drag or paste the link here"
|
||||
msgstr "Soltar o pegar en enlace aquí"
|
||||
|
||||
msgid "Remove added links in the playlist"
|
||||
msgstr "Quitar los enlaces añadidos en la lista de reproducción"
|
||||
|
||||
msgid "A bouquet with that name exists!"
|
||||
msgstr "¡Ya existe un bouquet con ese nombre!"
|
||||
@@ -1,7 +1,7 @@
|
||||
# Copyright (C) 2018-2019 Frank Neirynck
|
||||
# Copyright (C) 2018-2020 Frank Neirynck
|
||||
# This file is distributed under the MIT license.
|
||||
#
|
||||
# Frank Neirynck <frank@insink.be>, 2018-2019.
|
||||
# Frank Neirynck <frank@insink.be>, 2018-2020.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -10,11 +10,6 @@ msgstr ""
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Project-Id-Version: \n"
|
||||
"POT-Creation-Date: \n"
|
||||
"PO-Revision-Date: \n"
|
||||
"Language-Team: \n"
|
||||
"X-Generator: Poedit 2.2.1\n"
|
||||
|
||||
msgid "translator-credits"
|
||||
msgstr "Frank Neirynck <frank@insink.be>"
|
||||
@@ -776,4 +771,202 @@ msgid "Playlist import"
|
||||
msgstr "Importeer playlist"
|
||||
|
||||
msgid "Getting link error:"
|
||||
msgstr "Volgende Link error gekregen:"
|
||||
msgstr "Volgende Link error gekregen:"
|
||||
|
||||
msgid "Extra"
|
||||
msgstr "Extra"
|
||||
|
||||
msgid "Apply profile settings"
|
||||
msgstr "Pas profiel settings toe"
|
||||
|
||||
msgid "Settings type:"
|
||||
msgstr "Settings type:"
|
||||
|
||||
msgid "Set default"
|
||||
msgstr "Stel standaard in"
|
||||
|
||||
msgid "Language:"
|
||||
msgstr "Taal:"
|
||||
|
||||
msgid "Load the last open configuration at program startup"
|
||||
msgstr "Laad de laatst geopende configuratie op bij opstart programma"
|
||||
|
||||
msgid "Enable direct playback bar (experimental)"
|
||||
msgstr "Laat onmiddelijk playback bar toe (experimenteel)"
|
||||
|
||||
msgid "Enables direct sending and playback of media links on the receiver"
|
||||
msgstr "Laat rechtstreeks versturen van and playback en media links op de ontvanger toe"
|
||||
|
||||
msgid "Watch the channel in the program"
|
||||
msgstr "Bekijk het kanaal in het programma"
|
||||
|
||||
msgid "Zap and Play"
|
||||
msgstr "Zap en speel af"
|
||||
|
||||
msgid "Drag or paste the link here"
|
||||
msgstr "Sleep of plak link naar hier"
|
||||
|
||||
msgid "Remove added links in the playlist"
|
||||
msgstr "Verwijder toegevoegde links uit playlist"
|
||||
|
||||
msgid "A bouquet with that name exists!"
|
||||
msgstr "Er bestaat al een boeket met deze naam!"
|
||||
|
||||
msgid "Details"
|
||||
msgstr "Details"
|
||||
|
||||
msgid "Profile"
|
||||
msgstr "Profiel"
|
||||
|
||||
msgid "Reset"
|
||||
msgstr "Reset"
|
||||
|
||||
msgid "File"
|
||||
msgstr "File"
|
||||
|
||||
msgid "Picons manager"
|
||||
msgstr "Picons manager"
|
||||
|
||||
msgid "Explorer"
|
||||
msgstr "Explorer"
|
||||
|
||||
msgid "Satellite url:"
|
||||
msgstr "Satelliet url:"
|
||||
|
||||
msgid "Cut"
|
||||
msgstr "Knip"
|
||||
|
||||
msgid "Paste"
|
||||
msgstr "Plak"
|
||||
|
||||
msgid "To the top"
|
||||
msgstr "Naar de top"
|
||||
|
||||
msgid "To the end"
|
||||
msgstr "Naar het einde"
|
||||
|
||||
msgid "View"
|
||||
msgstr "View"
|
||||
|
||||
msgid "Lock"
|
||||
msgstr "Slot"
|
||||
|
||||
msgid "Parent lock"
|
||||
msgstr "Ouderlijk Slot"
|
||||
|
||||
msgid "Hide/Skip"
|
||||
msgstr "Verberg/Spring"
|
||||
|
||||
msgid "IPTV tools"
|
||||
msgstr "IPTV instrumenten"
|
||||
|
||||
msgid "Make profile folder as default for the additional data"
|
||||
msgstr "Maak profiel map standaard voor addionele data"
|
||||
|
||||
msgid "Default data path:"
|
||||
msgstr "Standaard data pad:"
|
||||
|
||||
msgid "Streams record path:"
|
||||
msgstr "Opnamepad streams:"
|
||||
|
||||
msgid "Record"
|
||||
msgstr "Opnemen"
|
||||
|
||||
msgid "Record:"
|
||||
msgstr "Opnemen:"
|
||||
|
||||
msgid "Record to disk:"
|
||||
msgstr "Opnemen op schijf:"
|
||||
|
||||
msgid "Streaming"
|
||||
msgstr "Streaming"
|
||||
|
||||
msgid "Activate transcoding"
|
||||
msgstr "Activeer transcodering"
|
||||
|
||||
msgid "Presets:"
|
||||
msgstr "Onstellingen:"
|
||||
|
||||
msgid "Video options:"
|
||||
msgstr "Video opties:"
|
||||
|
||||
msgid "Audio options:"
|
||||
msgstr "Audio opties:"
|
||||
|
||||
msgid "Bitrate (kb/s):"
|
||||
msgstr "Bitrate (kb/s):"
|
||||
|
||||
msgid "Codec:"
|
||||
msgstr "Codec:"
|
||||
|
||||
msgid "Width (px):"
|
||||
msgstr "Breedte (px):"
|
||||
|
||||
msgid "Height (px):"
|
||||
msgstr "Hoogte (px):"
|
||||
|
||||
msgid "Channels:"
|
||||
msgstr "Kanalen:"
|
||||
|
||||
msgid "Sample rate (Hz):"
|
||||
msgstr "Sample rate (Hz):"
|
||||
|
||||
msgid "Play streams mode:"
|
||||
msgstr "Speel in streams mode:"
|
||||
|
||||
msgid "Built-in player"
|
||||
msgstr "Ingebouwde speler"
|
||||
|
||||
msgid "VLC media player"
|
||||
msgstr "VLC Media speler"
|
||||
|
||||
msgid "Only get m3u file"
|
||||
msgstr "Enkel de m3u file ophalen"
|
||||
|
||||
msgid "Save and restart the program to apply the settings."
|
||||
msgstr "Het programma opslaan en herstarten om settings toe te passen."
|
||||
|
||||
msgid "Some images may have problems displaying the favorites list!"
|
||||
msgstr "Sommige afbeeldingen kunnen problemen opleveren bij vertonen in de favorietenlijst!"
|
||||
|
||||
msgid "Operates in standby mode or current active transponder!"
|
||||
msgstr "Werkt in standby mode of op dehuiduge actieve transponder!"
|
||||
|
||||
msgid "No connection to the receiver!"
|
||||
msgstr "Geen verbinding met de ontvanger!"
|
||||
|
||||
msgid "Signal level"
|
||||
msgstr "Signaal niveau"
|
||||
|
||||
msgid "Receiver info"
|
||||
msgstr "Informatie over de ontvanger"
|
||||
|
||||
msgid "A profile with that name exists!"
|
||||
msgstr "Er bestaat al een profiel met die naam!"
|
||||
|
||||
msgid "Show short info as hints in the main services list"
|
||||
msgstr "Toon korte info als hints in de hoofd servicelijst"
|
||||
|
||||
msgid "Show detailed info as hints in the bouquet list"
|
||||
msgstr "Toon gedetalleerde info als hints in de boeket lijst"
|
||||
|
||||
msgid "Enable alternate bouquet file naming"
|
||||
msgstr "Laat alternatieve boeket benamingen toe"
|
||||
|
||||
msgid "Allows you to name bouquet files using their names."
|
||||
msgstr "Laat toe om boeket te noemen naar bestandsbenaming."
|
||||
|
||||
msgid "Appearance"
|
||||
msgstr "Uitzicht"
|
||||
|
||||
msgid "Enable Themes support"
|
||||
msgstr "Laat themaondersteuning toe"
|
||||
|
||||
msgid "Gtk3 Theme:"
|
||||
msgstr "Gtk3 Thema:"
|
||||
|
||||
msgid "Icon Theme:"
|
||||
msgstr "Icoon Thema:"
|
||||
|
||||
msgid "Gtk3 Themes and Icons:"
|
||||
msgstr "Gtk3 en Icoon Themas:"
|
||||
|
||||
840
po/pl/demon-editor.po
Executable file
840
po/pl/demon-editor.po
Executable file
@@ -0,0 +1,840 @@
|
||||
# Copyright (C) 2018-2019 Dmitriy Yefremov
|
||||
# This file is distributed under the MIT license.
|
||||
#
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Last-Translator: wwns\n"
|
||||
"Language: pl\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
msgid "translator-credits"
|
||||
msgstr "wwns"
|
||||
|
||||
# Main
|
||||
msgid "File"
|
||||
msgstr "Plik"
|
||||
|
||||
msgid "View"
|
||||
msgstr "Widok"
|
||||
|
||||
msgid "Lock"
|
||||
msgstr "Zablokuj"
|
||||
|
||||
msgid "Service"
|
||||
msgstr "Serwis"
|
||||
|
||||
msgid "Package"
|
||||
msgstr "Pakiet"
|
||||
|
||||
msgid "Type"
|
||||
msgstr "Typ"
|
||||
|
||||
msgid "Picon"
|
||||
msgstr "Pikon"
|
||||
|
||||
msgid "Freq"
|
||||
msgstr "Freq"
|
||||
|
||||
msgid "Rate"
|
||||
msgstr "Rate"
|
||||
|
||||
msgid "Pol"
|
||||
msgstr "Pol"
|
||||
|
||||
msgid "System"
|
||||
msgstr "System"
|
||||
|
||||
msgid "Pos"
|
||||
msgstr "Pos"
|
||||
|
||||
msgid "Num"
|
||||
msgstr "Num"
|
||||
|
||||
msgid "Current IP:"
|
||||
msgstr "Adres IP:"
|
||||
|
||||
msgid "Assign"
|
||||
msgstr "Przypisz"
|
||||
|
||||
msgid "Bouquet details"
|
||||
msgstr "Bukiet szczegóły"
|
||||
|
||||
msgid "Bouquets"
|
||||
msgstr "Bukiety"
|
||||
|
||||
msgid "Copy"
|
||||
msgstr "Kopiuj"
|
||||
|
||||
msgid "Copy reference"
|
||||
msgstr "Kopiuj odniesienie"
|
||||
|
||||
msgid "Download"
|
||||
msgstr "Pobierz"
|
||||
|
||||
msgid "Edit"
|
||||
msgstr "Edytuj"
|
||||
|
||||
msgid "Edit mаrker text"
|
||||
msgstr "Edytuj tekst znacznika"
|
||||
|
||||
msgid "FTP-transfer"
|
||||
msgstr "Transfer FTP"
|
||||
|
||||
msgid "Global search"
|
||||
msgstr "Globalne wyszukiwanie"
|
||||
|
||||
msgid "Hide"
|
||||
msgstr "Ukryj"
|
||||
|
||||
msgid "Hide/Skip On/Off Ctrl + H"
|
||||
msgstr "Ukryj/Pomiń wł./wył Ctrl + H"
|
||||
|
||||
msgid "Add IPTV or stream service"
|
||||
msgstr "Dodaj strumień IPTV"
|
||||
|
||||
msgid "Import m3u"
|
||||
msgstr "Importuj m3u"
|
||||
|
||||
msgid "Import m3u file"
|
||||
msgstr "Importuj plik m3u"
|
||||
|
||||
msgid "List configuration"
|
||||
msgstr "Konfiguracja listy"
|
||||
|
||||
msgid "Rename for this bouquet"
|
||||
msgstr "Zmień nazwę tego serwisu"
|
||||
|
||||
msgid "Set default name"
|
||||
msgstr "Ustaw domyślną nazwę"
|
||||
|
||||
msgid "Insert marker"
|
||||
msgstr "Wstaw znacznik"
|
||||
|
||||
msgid "Locate in services"
|
||||
msgstr "Znajdź w usługach"
|
||||
|
||||
msgid "Locked"
|
||||
msgstr "Zablokowany"
|
||||
|
||||
msgid "Move"
|
||||
msgstr "Przenieś"
|
||||
|
||||
msgid "New"
|
||||
msgstr "Nowy"
|
||||
|
||||
msgid "New bouquet"
|
||||
msgstr "Nowy bukiet"
|
||||
|
||||
msgid "Create bouquet"
|
||||
msgstr "Utwórz bukiet"
|
||||
|
||||
msgid "For current satellite"
|
||||
msgstr "Dla bieżącego satelity"
|
||||
|
||||
msgid "For current package"
|
||||
msgstr "Dla bieżącego pakietu"
|
||||
|
||||
msgid "For current type"
|
||||
msgstr "Dla bieżącego typu"
|
||||
|
||||
msgid "For each satellite"
|
||||
msgstr "Dla każdego satelity"
|
||||
|
||||
msgid "For each package"
|
||||
msgstr "Dla każdego pakietu"
|
||||
|
||||
msgid "For each type"
|
||||
msgstr "Dla każdego typu"
|
||||
|
||||
msgid "Open"
|
||||
msgstr "Otwórz"
|
||||
|
||||
msgid "Parent lock On/Off Ctrl + L"
|
||||
msgstr "Blokada rodzicielska wł./wył Ctrl + L"
|
||||
|
||||
msgid "Picons"
|
||||
msgstr "Pikony"
|
||||
|
||||
msgid "Picons downloader"
|
||||
msgstr "Pobieranie pikonów"
|
||||
|
||||
msgid "Satellites downloader"
|
||||
msgstr "Pobierania satelitów"
|
||||
|
||||
msgid "Remove"
|
||||
msgstr "Usuń"
|
||||
|
||||
msgid "Remove all unavailable"
|
||||
msgstr "Usuń wszystkie niedostępne"
|
||||
|
||||
msgid "Satellites editor"
|
||||
msgstr "Edytor satelitów"
|
||||
|
||||
msgid "Save"
|
||||
msgstr "Zapisz"
|
||||
|
||||
msgid "Search"
|
||||
msgstr "Szukaj"
|
||||
|
||||
msgid "Services"
|
||||
msgstr "Kanały"
|
||||
|
||||
msgid "Services filter"
|
||||
msgstr "Filtr kanałów"
|
||||
|
||||
msgid "Settings"
|
||||
msgstr "Ustawienia"
|
||||
|
||||
msgid "Up"
|
||||
msgstr "Góra"
|
||||
|
||||
msgid "Down"
|
||||
msgstr "Dół"
|
||||
|
||||
msgid "Active profile:"
|
||||
msgstr "Aktywny Profil:"
|
||||
|
||||
msgid "All"
|
||||
msgstr "Wszystko"
|
||||
|
||||
msgid "Are you sure?"
|
||||
msgstr "Czy na pewno?"
|
||||
|
||||
msgid "Current data path:"
|
||||
msgstr "Aktualna ścieżka danych:"
|
||||
|
||||
msgid "Data:"
|
||||
msgstr "Dane:"
|
||||
|
||||
msgid "Enigma2 channel and satellites list editor for GNU/Linux"
|
||||
msgstr "Edytor kanałów Enigma2 i listy satelitów dla GNU/Linux"
|
||||
|
||||
msgid "Host:"
|
||||
msgstr "Host:"
|
||||
|
||||
msgid "Loading data..."
|
||||
msgstr "Ładowanie danych…"
|
||||
|
||||
msgid "Receive"
|
||||
msgstr "Pobierz"
|
||||
|
||||
msgid "Receive files from receiver"
|
||||
msgstr "Pobieranie plików z odbiornika"
|
||||
|
||||
msgid "Receiver IP:"
|
||||
msgstr "Odbiornik IP:"
|
||||
|
||||
msgid "Remove unused bouquets"
|
||||
msgstr "Usuń nieużywany bouquet"
|
||||
|
||||
msgid "Reset profile"
|
||||
msgstr "Reset profilu"
|
||||
|
||||
msgid "Satellites"
|
||||
msgstr "Satelity"
|
||||
|
||||
msgid "Satellites.xml file:"
|
||||
msgstr "Plik Satellites.xml:"
|
||||
|
||||
msgid "Selected"
|
||||
msgstr "Wybrany"
|
||||
|
||||
msgid "Send"
|
||||
msgstr "Wyślij"
|
||||
|
||||
msgid "Send files to receiver"
|
||||
msgstr "Wysyłanie plików do odbiornika"
|
||||
|
||||
msgid "Services and Bouquets files:"
|
||||
msgstr "Usługi i bukiety plików:"
|
||||
|
||||
msgid "User bouquet files:"
|
||||
msgstr "Pliki bukietu użytkownika:"
|
||||
|
||||
msgid "Extra:"
|
||||
msgstr "Dodatkowe"
|
||||
|
||||
# Filter bar
|
||||
msgid "Only free"
|
||||
msgstr "Tylko FTA"
|
||||
|
||||
msgid "All positions"
|
||||
msgstr "Wszystkie pozycje"
|
||||
|
||||
msgid "All types"
|
||||
msgstr "Wszystkie typy"
|
||||
|
||||
# Streams player
|
||||
msgid "Play"
|
||||
msgstr "Odtwarzaj"
|
||||
|
||||
msgid "Stop playback"
|
||||
msgstr "Zatrzymaj odtwarzanie"
|
||||
|
||||
msgid "Previous stream in the list"
|
||||
msgstr "Poprzedni strumień na liście"
|
||||
|
||||
msgid "Next stream in the list"
|
||||
msgstr "Następny strumień na liście"
|
||||
|
||||
msgid "Toggle in fullscreen"
|
||||
msgstr "Przełącz na pełny ekran"
|
||||
|
||||
msgid "Close"
|
||||
msgstr "Zamknij"
|
||||
|
||||
# Picons dialog
|
||||
msgid "Load providers"
|
||||
msgstr "Załaduj dostawców"
|
||||
|
||||
msgid "Providers"
|
||||
msgstr "Dostawca"
|
||||
|
||||
msgid "Receive picons"
|
||||
msgstr "Pobierz pikony"
|
||||
|
||||
msgid "Picons name format:"
|
||||
msgstr "Format nazw pikon:"
|
||||
|
||||
msgid "Resize:"
|
||||
msgstr "Zmień rozmiar:"
|
||||
|
||||
msgid "Current picons path:"
|
||||
msgstr "Aktualna ścieżka pikon:"
|
||||
|
||||
msgid "Receiver picons path:"
|
||||
msgstr "Ścieżka pikon odbiornika:"
|
||||
|
||||
msgid "Picons download tool"
|
||||
msgstr "Narzędzie pobierania pikon"
|
||||
|
||||
msgid "Transfer to receiver"
|
||||
msgstr "Wyślij do odbiornika"
|
||||
|
||||
msgid "Downloader"
|
||||
msgstr "Pobieranie"
|
||||
|
||||
msgid "Converter"
|
||||
msgstr "Konwerter"
|
||||
|
||||
msgid "Convert"
|
||||
msgstr "Konwertuj"
|
||||
|
||||
msgid "Path to save:"
|
||||
msgstr "Zapisz do:"
|
||||
|
||||
msgid "Path to Enigma2 picons:"
|
||||
msgstr "Ścieżka do pikon Enigma2:"
|
||||
|
||||
msgid "Specify the correct position value for the provider!"
|
||||
msgstr "Podaj poprawną wartość pozycji dla dostawcy!"
|
||||
|
||||
msgid "Converter between name formats"
|
||||
msgstr "Konwerter między formatami nazw"
|
||||
|
||||
msgid "Receive picons for providers"
|
||||
msgstr "Pobierz pikony od nadawcy"
|
||||
|
||||
msgid "Load satellite providers."
|
||||
msgstr "Załaduj dostawców satelitarnych."
|
||||
|
||||
msgid ""
|
||||
"To automatically set the identifiers for picons,\n"
|
||||
"first load the required services list into the main application window."
|
||||
msgstr ""
|
||||
"Aby automatycznie ustawić identyfikatory pikon,\n"
|
||||
"najpierw załaduj listę wymaganych usług do głównego okna aplikacji."
|
||||
|
||||
# Satellites editor
|
||||
msgid "Satellites edit tool"
|
||||
msgstr "Narzędzie do edycji satelitów"
|
||||
|
||||
msgid "Add"
|
||||
msgstr "Dodaj"
|
||||
|
||||
msgid "Satellite"
|
||||
msgstr "Satelita"
|
||||
|
||||
msgid "Transponder"
|
||||
msgstr "Transponder"
|
||||
|
||||
msgid "Satellite properties:"
|
||||
msgstr "Właściwości satelity:"
|
||||
|
||||
msgid "Transponder properties:"
|
||||
msgstr "Właściwości transpondera:"
|
||||
|
||||
msgid "Name"
|
||||
msgstr "Nazwa"
|
||||
|
||||
msgid "Position"
|
||||
msgstr "Pozycja"
|
||||
|
||||
# Satellites update dialog
|
||||
msgid "Satellites update"
|
||||
msgstr "Aktualizacja satelitów"
|
||||
|
||||
msgid "Remove selection"
|
||||
msgstr "Usuń wybrane"
|
||||
|
||||
# Service details dialog
|
||||
msgid "Service data:"
|
||||
msgstr "Dane usług:"
|
||||
|
||||
msgid "Transponder data:"
|
||||
msgstr "Dane transpondera:"
|
||||
|
||||
msgid "Service data"
|
||||
msgstr "Dane usług"
|
||||
|
||||
msgid "Transponder details"
|
||||
msgstr "Szczegóły transpondera"
|
||||
|
||||
msgid ""
|
||||
"Changes will be applied to all services of this transponder!\n"
|
||||
"Continue?"
|
||||
msgstr ""
|
||||
"Zmiany zostaną zastosowane do wszystkich usług transpondera!\n"
|
||||
"kontynuować?"
|
||||
|
||||
msgid "Reference"
|
||||
msgstr "Odniesienie"
|
||||
|
||||
msgid "Namespace"
|
||||
msgstr "Namespace"
|
||||
|
||||
msgid "Flags:"
|
||||
msgstr "Flagi:"
|
||||
|
||||
msgid "Delays (ms):"
|
||||
msgstr "Zwłoka (ms):"
|
||||
|
||||
msgid "Bitstream"
|
||||
msgstr "Bitstream"
|
||||
|
||||
msgid "Description"
|
||||
msgstr "Opis"
|
||||
|
||||
msgid "Source:"
|
||||
msgstr "Źródło:"
|
||||
|
||||
msgid "Cancel"
|
||||
msgstr "Anuluj"
|
||||
|
||||
msgid "Update"
|
||||
msgstr "Uaktualnienie"
|
||||
|
||||
msgid "Filter"
|
||||
msgstr "Filtr"
|
||||
|
||||
msgid "Find"
|
||||
msgstr "Znajdź"
|
||||
|
||||
# IPTV dialog
|
||||
msgid "Stream data"
|
||||
msgstr "Przesyłanie danych"
|
||||
|
||||
# IPTV list configuration dialog
|
||||
msgid "Starting values"
|
||||
msgstr "Wartości początkowe"
|
||||
|
||||
msgid "Reset to default"
|
||||
msgstr "Ustawienia domyślne"
|
||||
|
||||
msgid "IPTV streams list configuration"
|
||||
msgstr "Konfiguracja listy strumieni IPTV"
|
||||
|
||||
# Settings dialog
|
||||
msgid "Preferences"
|
||||
msgstr "Preferencje"
|
||||
|
||||
msgid "Profile:"
|
||||
msgstr "Profil:"
|
||||
|
||||
msgid "Timeout between commands in seconds"
|
||||
msgstr "Limit czasu między poleceniami w sekundach"
|
||||
|
||||
msgid "Timeout:"
|
||||
msgstr "Koniec czasu:"
|
||||
|
||||
msgid "Login:"
|
||||
msgstr "Login:"
|
||||
|
||||
msgid "Options"
|
||||
msgstr "Opcje"
|
||||
|
||||
msgid "Password:"
|
||||
msgstr "Hasło:"
|
||||
|
||||
msgid "Picons:"
|
||||
msgstr "Pikony:"
|
||||
|
||||
msgid "Port:"
|
||||
msgstr "Port:"
|
||||
|
||||
msgid "Data path:"
|
||||
msgstr "Ścieżka danych:"
|
||||
|
||||
msgid "Picons path:"
|
||||
msgstr "Ścieżka pikon:"
|
||||
|
||||
msgid "Network settings:"
|
||||
msgstr "Ustawienia sieci:"
|
||||
|
||||
msgid "STB file paths:"
|
||||
msgstr "Ścieżki do plików w STB:"
|
||||
|
||||
msgid "Local file paths:"
|
||||
msgstr "Lokalne ścieżki plików:"
|
||||
|
||||
# Dialogs messages
|
||||
msgid "Error. No bouquet is selected!"
|
||||
msgstr "Błąd. Nie wybrano żadnego bukietu!"
|
||||
|
||||
msgid "This item is not allowed to be removed!"
|
||||
msgstr "Tego elementu nie można usunąć!"
|
||||
|
||||
msgid "This item is not allowed to edit!"
|
||||
msgstr "Tego elementu nie można edytować!"
|
||||
|
||||
msgid "Not allowed in this context!"
|
||||
msgstr "Niedozwolone w tym kontekście!"
|
||||
|
||||
msgid "Please, download files from receiver or setup your path for read data!"
|
||||
msgstr "Pobierz pliki z odbiornika lub ustaw ścieżkę do odczytu danych!"
|
||||
|
||||
msgid "Reading data error!"
|
||||
msgstr "Błąd odczytu danych!"
|
||||
|
||||
msgid "No m3u file is selected!"
|
||||
msgstr "Nie wybrano pliku m3u!"
|
||||
|
||||
msgid "Not implemented yet!"
|
||||
msgstr "Jeszcze niezaimplementowane!"
|
||||
|
||||
msgid "The text of marker is empty, please try again!"
|
||||
msgstr "Tekst znacznika jest pusty, spróbuj ponownie!"
|
||||
|
||||
msgid "Please, select only one item!"
|
||||
msgstr "Wybierz tylko jeden element!"
|
||||
|
||||
msgid "No png file is selected!"
|
||||
msgstr "Nie wybrano pliku png!"
|
||||
|
||||
msgid "No reference is present!"
|
||||
msgstr "Brak referencji!"
|
||||
|
||||
msgid "No selected item!"
|
||||
msgstr "Brak wybranego elementu!"
|
||||
|
||||
msgid "The task is already running!"
|
||||
msgstr "Zadanie już działa!"
|
||||
|
||||
msgid "Done!"
|
||||
msgstr "Zrobione!"
|
||||
|
||||
msgid "Please, wait..."
|
||||
msgstr "Proszę czekać…"
|
||||
|
||||
msgid "Resizing..."
|
||||
msgstr "Zmiana rozmiaru…"
|
||||
|
||||
msgid "Select paths!"
|
||||
msgstr "Wybierz ścieżki!"
|
||||
|
||||
msgid "No satellite is selected!"
|
||||
msgstr "Nie wybrano satelity!"
|
||||
|
||||
msgid "Please, select only one satellite!"
|
||||
msgstr "Wybierz tylko jednego satelitę!"
|
||||
|
||||
msgid "Please check your parameters and try again."
|
||||
msgstr "Sprawdź parametry i spróbuj ponownie."
|
||||
|
||||
msgid "No satellites.xml file is selected!"
|
||||
msgstr "Nie wybrano pliku satellites.xml!"
|
||||
|
||||
msgid "Error. Verify the data!"
|
||||
msgstr "Błąd. Zweryfikuj dane!"
|
||||
|
||||
msgid "Operation not allowed in this context!"
|
||||
msgstr "Operacja niedozwolona w tym kontekście!"
|
||||
|
||||
msgid "No VLC is found. Check that it is installed!"
|
||||
msgstr "Nie znaleziono VLC. Sprawdź, czy jest zainstalowany!"
|
||||
|
||||
# Search unavailable streams dialog
|
||||
msgid "Please wait, streams testing in progress..."
|
||||
msgstr "Proszę czekać, trwa testowanie strumieni…"
|
||||
|
||||
msgid "Found"
|
||||
msgstr "Znaleziono"
|
||||
|
||||
msgid "unavailable streams."
|
||||
msgstr "niedostępne strumienie."
|
||||
|
||||
msgid "No changes required!"
|
||||
msgstr "Nie wymaga zmian!"
|
||||
|
||||
msgid "This list does not contains IPTV streams!"
|
||||
msgstr "Ta lista nie zawiera strumieni IPTV!"
|
||||
|
||||
msgid "New empty configuration"
|
||||
msgstr "Nowa pusta konfiguracja"
|
||||
|
||||
msgid "No data to save!"
|
||||
msgstr "Brak danych do zapisania!"
|
||||
|
||||
msgid "Network"
|
||||
msgstr "Sieć"
|
||||
|
||||
msgid "Paths"
|
||||
msgstr "Ścieżki"
|
||||
|
||||
msgid "Program"
|
||||
msgstr "Program"
|
||||
|
||||
msgid "Backup:"
|
||||
msgstr "Kopia:"
|
||||
|
||||
msgid "Backup"
|
||||
msgstr "Kopia"
|
||||
|
||||
msgid "Backups"
|
||||
msgstr "Kopie zapasowe"
|
||||
|
||||
msgid "Backup path:"
|
||||
msgstr "Ścieżka kopii:"
|
||||
|
||||
msgid "Restore bouquets"
|
||||
msgstr "Przywróć bukiety"
|
||||
|
||||
msgid "Restore all"
|
||||
msgstr "Przywrócić wszystko"
|
||||
|
||||
msgid "Before saving"
|
||||
msgstr "Przed zapisaniem"
|
||||
|
||||
msgid "Before downloading from the receiver"
|
||||
msgstr "Przed pobraniem z odbiornika"
|
||||
|
||||
msgid "Set background color for the services"
|
||||
msgstr "Ustaw kolor tła dla usług"
|
||||
|
||||
msgid "Marked as new:"
|
||||
msgstr "Oznacz jako nowy:"
|
||||
|
||||
msgid "With an extra name in the bouquet:"
|
||||
msgstr "Z dodatkową nazwą w bukiecie:"
|
||||
|
||||
msgid "Select"
|
||||
msgstr "Wybierz"
|
||||
|
||||
msgid "About"
|
||||
msgstr "Wersja"
|
||||
|
||||
msgid "Exit"
|
||||
msgstr "Wyjście"
|
||||
|
||||
msgid "Tools"
|
||||
msgstr "Narzędzia"
|
||||
|
||||
# Import
|
||||
msgid "Import"
|
||||
msgstr "Importuj"
|
||||
|
||||
msgid "Bouquet"
|
||||
msgstr "Bukiet"
|
||||
|
||||
msgid "Bouquets and services"
|
||||
msgstr "Bukiety i kanały"
|
||||
|
||||
msgid "The main list does not contain services for this bouquet!"
|
||||
msgstr "Główna lista nie zawiera kanałów dla tego bukietu!"
|
||||
|
||||
msgid "No bouquet file is selected!"
|
||||
msgstr "Nie wybrano pliku bukietu!"
|
||||
|
||||
msgid "Remove all unused"
|
||||
msgstr "Usuń wszystkie nieużywane"
|
||||
|
||||
msgid "Test"
|
||||
msgstr "Test"
|
||||
|
||||
msgid "Test connection"
|
||||
msgstr "Testuj połączenie"
|
||||
|
||||
msgid "Double click on the service in the bouquet list:"
|
||||
msgstr "Kliknij dwukrotnie usługę na liście bukietów:"
|
||||
|
||||
msgid "Zap"
|
||||
msgstr "Przełącz"
|
||||
|
||||
msgid "Play stream"
|
||||
msgstr "Odtwórz strumień"
|
||||
|
||||
msgid "Disabled"
|
||||
msgstr "Wyłączone"
|
||||
|
||||
msgid "Enable ver. 5 support (experimental)"
|
||||
msgstr "Włącz wer. 5 wsparcie (eksperymentalne)"
|
||||
|
||||
msgid "Enable HTTP API (experimental)"
|
||||
msgstr "Włącz API HTTP (eksperymentalne)"
|
||||
|
||||
msgid "Switch(zap) the channel(Ctrl + Z)"
|
||||
msgstr "Przełącz(zap) kanał(Ctrl + Z)"
|
||||
|
||||
msgid "Switch the channel and watch in the program(Ctrl + W)"
|
||||
msgstr "Przełącz kanał i oglądaj w programie(Ctrl + W)"
|
||||
|
||||
msgid "Play IPTV or other stream in the program(Ctrl + P)"
|
||||
msgstr "Odtwórz IPTV lub inny strumień w programie(Ctrl + P)"
|
||||
|
||||
msgid "Export to m3u"
|
||||
msgstr "Eksportuj do m3u"
|
||||
|
||||
msgid "EPG configuration"
|
||||
msgstr "Koniguruj EPG"
|
||||
|
||||
msgid "Apply"
|
||||
msgstr "Zatwierdź"
|
||||
|
||||
msgid "EPG source"
|
||||
msgstr "Źródło EPG"
|
||||
|
||||
msgid "Service names source:"
|
||||
msgstr "Źródło nazw usług:"
|
||||
|
||||
msgid "Main service list"
|
||||
msgstr "Główna lista usług"
|
||||
|
||||
msgid "XML file"
|
||||
msgstr "Plik XML"
|
||||
|
||||
msgid "Use web source"
|
||||
msgstr "Użyj źródła internetowego"
|
||||
|
||||
msgid "Url to *.xml.gz file:"
|
||||
msgstr "URL do pliku *.xml.gz:"
|
||||
|
||||
msgid "Enable filtering"
|
||||
msgstr "Włącz filtrowanie"
|
||||
|
||||
msgid "Filter by presence in the epg.dat file."
|
||||
msgstr "Filtruj według ustawień w pliku epg.dat."
|
||||
|
||||
msgid "Paths to the epg.dat file:"
|
||||
msgstr "Ścieżka do pliku epg.dat:"
|
||||
|
||||
msgid "Local path:"
|
||||
msgstr "Ścieżka lokalna:"
|
||||
|
||||
msgid "STB path:"
|
||||
msgstr "Ścieżka STB:"
|
||||
|
||||
msgid "Update on start"
|
||||
msgstr "Aktualizuj przy starcie"
|
||||
|
||||
msgid "Auto configuration by service names."
|
||||
msgstr "Automatyczna konfiguracja serwisu według nazw."
|
||||
|
||||
msgid "Save list to xml."
|
||||
msgstr "Zapisz listę do XML."
|
||||
|
||||
msgid "Download XML file error."
|
||||
msgstr "Błąd pobierania pliku XML."
|
||||
|
||||
msgid "Unsupported file type:"
|
||||
msgstr "Nieobsługiwany typ pliku:"
|
||||
|
||||
msgid "Unpacking data error."
|
||||
msgstr "Błąd rozpakowywania danych."
|
||||
|
||||
msgid "XML parsing error:"
|
||||
msgstr "Błąd analizy XML:"
|
||||
|
||||
msgid "Count of successfully configured services:"
|
||||
msgstr "Liczba pomyślnie skonfigurowanych usług:"
|
||||
|
||||
msgid "Current epg.dat file does not contains references for the services of this bouquet!"
|
||||
msgstr "Bieżący plik epg.dat nie zawiera odniesień do usług tego bukietu!"
|
||||
|
||||
msgid "Use HTTP"
|
||||
msgstr "Użyj HTTP"
|
||||
|
||||
msgid "Close playback"
|
||||
msgstr "Zamknij odtwarzanie"
|
||||
|
||||
msgid "Import YouTube playlist"
|
||||
msgstr "Importuj listę odtwarzania YouTube"
|
||||
|
||||
msgid ""
|
||||
"Found a link to the YouTube resource!\n"
|
||||
"Try to get a direct link to the video?"
|
||||
msgstr ""
|
||||
"Znaleziono link do zasobu YouTube!\n"
|
||||
"Chcesz uzyskać bezpośredni link do filmu?"
|
||||
|
||||
msgid "Playlist import"
|
||||
msgstr "Import listy odtwarzania"
|
||||
|
||||
msgid "Getting link error:"
|
||||
msgstr "Błąd pobierania łącza:"
|
||||
|
||||
msgid "Extra"
|
||||
msgstr "Ekstra"
|
||||
|
||||
msgid "Apply profile settings"
|
||||
msgstr "Zastosuj ustawienia profilu"
|
||||
|
||||
msgid "Settings type:"
|
||||
msgstr "Ustawienia dla:"
|
||||
|
||||
msgid "Set default"
|
||||
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 (experimental)"
|
||||
msgstr "Włącz pasek bezpośredniego odtwarzania (eksperymentalnie)"
|
||||
|
||||
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"
|
||||
|
||||
msgid "Watch the channel in the program"
|
||||
msgstr "Obejrzyj kanał w programie"
|
||||
|
||||
msgid "Receiver info"
|
||||
msgstr "Informacje o odbiorniku"
|
||||
|
||||
msgid "Operates in standby mode or current active transponder!"
|
||||
msgstr "Działa w trybie gotowości lub aktualnie jest aktywny transponder!"
|
||||
|
||||
msgid "Download picons from the receiver"
|
||||
msgstr "Pobierz pikony z odbiornika"
|
||||
|
||||
msgid "Remove picons from the receiver"
|
||||
msgstr "Usuń pikony z odbiornika"
|
||||
|
||||
msgid "Use http to reload data in the receiver."
|
||||
msgstr "Użyj http aby ponownie załadować dane do odbiornika."
|
||||
|
||||
msgid "Zap and Play"
|
||||
msgstr "Przełącz i Odtwórz"
|
||||
|
||||
msgid "Drag or paste the link here"
|
||||
msgstr "Przeciągnij lub wklej tutaj link"
|
||||
|
||||
msgid "Remove added links in the playlist"
|
||||
msgstr "Usuń dodane linki z listy odtwarzania"
|
||||
|
||||
msgid "A bouquet with that name exists!"
|
||||
msgstr "Istnieje bukiet o tej nazwie!"
|
||||
@@ -663,7 +663,7 @@ msgid "Disabled"
|
||||
msgstr "Выкл."
|
||||
|
||||
msgid "Enable ver. 5 support (experimental)"
|
||||
msgstr "Включить поддержку вер. 5 (экспериментально)"
|
||||
msgstr "Включить поддержку lamedb вер. 5 (экспериментально)"
|
||||
|
||||
msgid "Enable HTTP API (experimental)"
|
||||
msgstr "Включить HTTP API (экспериментально)"
|
||||
@@ -763,3 +763,214 @@ msgstr "Импорт плейлиста"
|
||||
|
||||
msgid "Getting link error:"
|
||||
msgstr "Ошибка получения ссылки:"
|
||||
|
||||
msgid "Extra"
|
||||
msgstr "Дополнительно"
|
||||
|
||||
msgid "Apply profile settings"
|
||||
msgstr "Применить настройки профиля"
|
||||
|
||||
msgid "Settings type:"
|
||||
msgstr "Тип настроек:"
|
||||
|
||||
msgid "Set default"
|
||||
msgstr "Установить по умолчанию"
|
||||
|
||||
msgid "Language:"
|
||||
msgstr "Язык:"
|
||||
|
||||
msgid "Load the last open configuration at program startup"
|
||||
msgstr "Загружать последнюю открытую конфигурацию при запуске программы"
|
||||
|
||||
msgid "Enable direct playback bar (experimental)"
|
||||
msgstr "Включить панель прямого воспроизведения (экспериментально)"
|
||||
|
||||
msgid "Enables direct sending and playback of media links on the receiver"
|
||||
msgstr "Включает прямую отправку и воспроизведение медиа-ссылок на ресивере"
|
||||
|
||||
msgid "Watch the channel in the program"
|
||||
msgstr "Просмотр канала в программе"
|
||||
|
||||
msgid "Zap and Play"
|
||||
msgstr "Перекл. и просмотр"
|
||||
|
||||
msgid "Drag or paste the link here"
|
||||
msgstr "Перетащите или вставьте ссылку здесь"
|
||||
|
||||
msgid "Remove added links in the playlist"
|
||||
msgstr "Удалить добавленные ссылки из плейлиста"
|
||||
|
||||
msgid "A bouquet with that name exists!"
|
||||
msgstr "Букет с таким именем существует!"
|
||||
|
||||
msgid "Details"
|
||||
msgstr "Подробно"
|
||||
|
||||
msgid "Profile"
|
||||
msgstr "Профиль"
|
||||
|
||||
msgid "Reset"
|
||||
msgstr "Сброс"
|
||||
|
||||
msgid "File"
|
||||
msgstr "Файл"
|
||||
|
||||
msgid "Picons manager"
|
||||
msgstr "Менеджер пиконов"
|
||||
|
||||
msgid "Explorer"
|
||||
msgstr "Проводник"
|
||||
|
||||
msgid "Satellite url:"
|
||||
msgstr "URL cпутника:"
|
||||
|
||||
msgid "Cut"
|
||||
msgstr "Вырезать"
|
||||
|
||||
msgid "Paste"
|
||||
msgstr "Вставить"
|
||||
|
||||
msgid "To the top"
|
||||
msgstr "В начало"
|
||||
|
||||
msgid "To the end"
|
||||
msgstr "В конец"
|
||||
|
||||
msgid "View"
|
||||
msgstr "Вид"
|
||||
|
||||
msgid "Lock"
|
||||
msgstr "Замок"
|
||||
|
||||
msgid "Parent lock"
|
||||
msgstr "Родительский замок"
|
||||
|
||||
msgid "Hide/Skip"
|
||||
msgstr "Скрыть/Пропустить"
|
||||
|
||||
msgid "IPTV tools"
|
||||
msgstr "Инструменты IPTV"
|
||||
|
||||
msgid "Make profile folder as default for the additional data"
|
||||
msgstr "Установить папку профиля по умолчанию для доп. данных"
|
||||
|
||||
msgid "Default data path:"
|
||||
msgstr "Путь к данным по умолчанию:"
|
||||
|
||||
msgid "Streams record path:"
|
||||
msgstr "Путь к записям потоков:"
|
||||
|
||||
msgid "Record"
|
||||
msgstr "Запись"
|
||||
|
||||
msgid "Record:"
|
||||
msgstr "Запись:"
|
||||
|
||||
msgid "Record to disk:"
|
||||
msgstr "Запись на диск:"
|
||||
|
||||
msgid "Streaming"
|
||||
msgstr "Потоки"
|
||||
|
||||
msgid "Activate transcoding"
|
||||
msgstr "Активировать перекодировку"
|
||||
|
||||
msgid "Presets:"
|
||||
msgstr "Предустановки:"
|
||||
|
||||
msgid "Video options:"
|
||||
msgstr "Опции видео:"
|
||||
|
||||
msgid "Audio options:"
|
||||
msgstr "Опции аудио:"
|
||||
|
||||
msgid "Bitrate (kb/s):"
|
||||
msgstr "Битрейт (kb/s):"
|
||||
|
||||
msgid "Codec:"
|
||||
msgstr "Кодек:"
|
||||
|
||||
msgid "Width (px):"
|
||||
msgstr "Ширина (px):"
|
||||
|
||||
msgid "Height (px):"
|
||||
msgstr "Высота (px):"
|
||||
|
||||
msgid "Channels:"
|
||||
msgstr "Каналы:"
|
||||
|
||||
msgid "Sample rate (Hz):"
|
||||
msgstr "Частота дискр. (Гц):"
|
||||
|
||||
msgid "Play streams mode:"
|
||||
msgstr "Режим воспроизведения потоков:"
|
||||
|
||||
msgid "Built-in player"
|
||||
msgstr "Встроенный плеер"
|
||||
|
||||
msgid "VLC media player"
|
||||
msgstr "VLC медиаплеер"
|
||||
|
||||
msgid "Only get m3u file"
|
||||
msgstr "Получить файл *.m3u"
|
||||
|
||||
msgid "Save and restart the program to apply the settings."
|
||||
msgstr "Сохраните и перезапустите программу, чтобы применить настройки."
|
||||
|
||||
msgid "Some images may have problems displaying the favorites list!"
|
||||
msgstr "Некоторые образы могут иметь проблемы с отображением списка избранного!"
|
||||
|
||||
msgid "Operates in standby mode or current active transponder!"
|
||||
msgstr "Работает в режиме ожидания или текущем активном транспондере!"
|
||||
|
||||
msgid "No connection to the receiver!"
|
||||
msgstr "Нет соединение с ресивером!"
|
||||
|
||||
msgid "Signal level"
|
||||
msgstr "Уровень сигнала"
|
||||
|
||||
msgid "Receiver info"
|
||||
msgstr "Информация о ресивере"
|
||||
|
||||
msgid "A profile with that name exists!"
|
||||
msgstr "Профиль с таким именем существует!"
|
||||
|
||||
msgid "Show short info as hints in the main services list"
|
||||
msgstr "Показывать краткую информацию в виде подсказок в основном списке услуг"
|
||||
|
||||
msgid "Show detailed info as hints in the bouquet list"
|
||||
msgstr "Показывать подробную информацию в виде подсказок в списке букетов"
|
||||
|
||||
msgid "Enable alternate bouquet file naming"
|
||||
msgstr "Включить альтернативное именование файлов букета"
|
||||
|
||||
msgid "Allows you to name bouquet files using their names."
|
||||
msgstr "Позволяет называть файлы букетов, используя их имена."
|
||||
|
||||
msgid "Appearance"
|
||||
msgstr "Внешний вид"
|
||||
|
||||
msgid "Enable Themes support"
|
||||
msgstr "Включить поддержку тем"
|
||||
|
||||
msgid "Gtk3 Theme:"
|
||||
msgstr "Тема Gtk3:"
|
||||
|
||||
msgid "Icon Theme:"
|
||||
msgstr "Тема значков:"
|
||||
|
||||
msgid "Gtk3 Themes and Icons:"
|
||||
msgstr "Gtk3 темы и иконки:"
|
||||
|
||||
msgid "Deleting data..."
|
||||
msgstr "Удаление данных ..."
|
||||
|
||||
msgid "Download from the receiver"
|
||||
msgstr "Загрузить с ресивера"
|
||||
|
||||
msgid "Remove all picons from the receiver"
|
||||
msgstr "Удалить все пиконы с ресивера"
|
||||
|
||||
msgid "Service reference"
|
||||
msgstr "Сервисная ссылка"
|
||||
|
||||
|
||||
978
po/tr/demon-editor.po
Normal file
978
po/tr/demon-editor.po
Normal file
@@ -0,0 +1,978 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: DemonEditor\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2020-04-16 15:59+0300\n"
|
||||
"PO-Revision-Date: 2020-05-11 20:02+0300\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Last-Translator: audi06_19 <info@dreamosat-forum.com>\n"
|
||||
"Language-Team: \n"
|
||||
"X-Generator: Poedit 2.2.1\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"Language: tr\n"
|
||||
|
||||
msgid "translator-credits"
|
||||
msgstr "audi06_19 <info@dreamosat-forum.com>"
|
||||
|
||||
# Main
|
||||
msgid "Service"
|
||||
msgstr "Hizmet"
|
||||
|
||||
msgid "Package"
|
||||
msgstr "Paket"
|
||||
|
||||
msgid "Type"
|
||||
msgstr "Tür"
|
||||
|
||||
msgid "Picon"
|
||||
msgstr "Picon"
|
||||
|
||||
msgid "Freq"
|
||||
msgstr "Frekans"
|
||||
|
||||
msgid "Rate"
|
||||
msgstr "Oran"
|
||||
|
||||
msgid "Pol"
|
||||
msgstr "Pol"
|
||||
|
||||
msgid "System"
|
||||
msgstr "Sistem"
|
||||
|
||||
msgid "Pos"
|
||||
msgstr "Pos"
|
||||
|
||||
msgid "Num"
|
||||
msgstr "Num"
|
||||
|
||||
msgid "Current IP:"
|
||||
msgstr "Geçerli IP:"
|
||||
|
||||
msgid "Assign"
|
||||
msgstr "Ata"
|
||||
|
||||
msgid "Bouquet details"
|
||||
msgstr "Buket detayları"
|
||||
|
||||
msgid "Bouquets"
|
||||
msgstr "Buketler"
|
||||
|
||||
msgid "Copy"
|
||||
msgstr "Kopya"
|
||||
|
||||
msgid "Copy reference"
|
||||
msgstr "Referansı kopyala"
|
||||
|
||||
msgid "Download"
|
||||
msgstr "İndir"
|
||||
|
||||
msgid "Edit"
|
||||
msgstr "Düzelt"
|
||||
|
||||
msgid "Edit mаrker text"
|
||||
msgstr "Marker metnini Düzenle"
|
||||
|
||||
msgid "FTP-transfer"
|
||||
msgstr "FTP aktarımı"
|
||||
|
||||
msgid "Global search"
|
||||
msgstr "Global arama"
|
||||
|
||||
msgid "Hide"
|
||||
msgstr "Gizle"
|
||||
|
||||
msgid "Hide/Skip On/Off Ctrl + H"
|
||||
msgstr "Gizle/Atla Açık/Kapalı Ctrl + H"
|
||||
|
||||
msgid "Add IPTV or stream service"
|
||||
msgstr "IPTV veya akış hizmeti ekle"
|
||||
|
||||
msgid "Import m3u"
|
||||
msgstr "M3u aktar"
|
||||
|
||||
msgid "Import m3u file"
|
||||
msgstr "İçe aktar M3U"
|
||||
|
||||
msgid "List configuration"
|
||||
msgstr "Liste yapılandırması"
|
||||
|
||||
msgid "Rename for this bouquet"
|
||||
msgstr "Bu buketi yeniden adlandır"
|
||||
|
||||
msgid "Set default name"
|
||||
msgstr "Varsayılan adı ayarla"
|
||||
|
||||
msgid "Insert marker"
|
||||
msgstr "İşaretçi ekle"
|
||||
|
||||
msgid "Locate in services"
|
||||
msgstr "Hizmetlerde bulun"
|
||||
|
||||
msgid "Locked"
|
||||
msgstr "Kilitli"
|
||||
|
||||
msgid "Move"
|
||||
msgstr "Taçı"
|
||||
|
||||
msgid "New"
|
||||
msgstr "Yeni"
|
||||
|
||||
msgid "New bouquet"
|
||||
msgstr "Yeni buket"
|
||||
|
||||
msgid "Create bouquet"
|
||||
msgstr "Buket oluştur"
|
||||
|
||||
msgid "For current satellite"
|
||||
msgstr "Mevcut uydu için"
|
||||
|
||||
msgid "For current package"
|
||||
msgstr "Mevcut paket için"
|
||||
|
||||
msgid "For current type"
|
||||
msgstr "Mevcut tip için"
|
||||
|
||||
msgid "For each satellite"
|
||||
msgstr "Her uydu için"
|
||||
|
||||
msgid "For each package"
|
||||
msgstr "Her paket için"
|
||||
|
||||
msgid "For each type"
|
||||
msgstr "Her tip için"
|
||||
|
||||
msgid "Open"
|
||||
msgstr "Aç"
|
||||
|
||||
msgid "Parent lock On/Off Ctrl + L"
|
||||
msgstr "Ebeveyn kilidi Açık/Kapalı Ctrl + L"
|
||||
|
||||
msgid "Picons"
|
||||
msgstr "Piconlar"
|
||||
|
||||
msgid "Picons downloader"
|
||||
msgstr "Piconları Güncelle/indir"
|
||||
|
||||
msgid "Satellites downloader"
|
||||
msgstr "Satellites Güncelle/indir"
|
||||
|
||||
msgid "Remove"
|
||||
msgstr "Kaldır"
|
||||
|
||||
msgid "Remove all unavailable"
|
||||
msgstr "Tüm mevcut olmayanları kaldır"
|
||||
|
||||
msgid "Satellites editor"
|
||||
msgstr "Uydular editörü"
|
||||
|
||||
msgid "Save"
|
||||
msgstr "Kaydet"
|
||||
|
||||
msgid "Search"
|
||||
msgstr "Arama"
|
||||
|
||||
msgid "Services"
|
||||
msgstr "Hizmetler"
|
||||
|
||||
msgid "Services filter"
|
||||
msgstr "Hizmet filtresi"
|
||||
|
||||
msgid "Settings"
|
||||
msgstr "Ayarlar"
|
||||
|
||||
msgid "Up"
|
||||
msgstr "Yukarı"
|
||||
|
||||
msgid "Down"
|
||||
msgstr "Aşağı"
|
||||
|
||||
msgid "Active profile:"
|
||||
msgstr "Etkin profil:"
|
||||
|
||||
msgid "All"
|
||||
msgstr "Tümü"
|
||||
|
||||
msgid "Are you sure?"
|
||||
msgstr "Emin misin?"
|
||||
|
||||
msgid "Current data path:"
|
||||
msgstr "Mevcut veri yolu:"
|
||||
|
||||
msgid "Data:"
|
||||
msgstr "Veri:"
|
||||
|
||||
msgid "Enigma2 channel and satellites list editor for GNU/Linux"
|
||||
msgstr "GNU/Linux için Enigma2 kanalı ve uydu listesi editörü"
|
||||
|
||||
msgid "Host:"
|
||||
msgstr "Ana bilgisayar:"
|
||||
|
||||
msgid "Loading data..."
|
||||
msgstr "Veriler yükleniyor ..."
|
||||
|
||||
msgid "Receive"
|
||||
msgstr "Al"
|
||||
|
||||
msgid "Receive files from receiver"
|
||||
msgstr "Alıcıdan dosya al"
|
||||
|
||||
msgid "Receiver IP:"
|
||||
msgstr "Alıcı IP'si:"
|
||||
|
||||
msgid "Remove unused bouquets"
|
||||
msgstr "Kullanılmayan buketleri kaldır"
|
||||
|
||||
msgid "Reset profile"
|
||||
msgstr "Profili sıfırla"
|
||||
|
||||
msgid "Satellites"
|
||||
msgstr "Uydular"
|
||||
|
||||
msgid "Satellites.xml file:"
|
||||
msgstr "Satellites.xml dosyası:"
|
||||
|
||||
msgid "Selected"
|
||||
msgstr "Seçildi"
|
||||
|
||||
msgid "Send"
|
||||
msgstr "Gönder"
|
||||
|
||||
msgid "Send files to receiver"
|
||||
msgstr "Alıcıya dosya gönder"
|
||||
|
||||
msgid "Services and Bouquets files:"
|
||||
msgstr "Hizmetler ve Buketler dosyaları:"
|
||||
|
||||
msgid "User bouquet files:"
|
||||
msgstr "Kullanıcı buketi dosyaları:"
|
||||
|
||||
msgid "Extra:"
|
||||
msgstr "Ekstra:"
|
||||
|
||||
# Filter bar
|
||||
msgid "Only free"
|
||||
msgstr "Sadece ücretsiz"
|
||||
|
||||
msgid "All positions"
|
||||
msgstr "Tüm pozisyonlar"
|
||||
|
||||
msgid "All types"
|
||||
msgstr "Tüm türler"
|
||||
|
||||
# Streams player
|
||||
msgid "Play"
|
||||
msgstr "Oynat"
|
||||
|
||||
msgid "Stop playback"
|
||||
msgstr "Oynatmayı durdur"
|
||||
|
||||
msgid "Previous stream in the list"
|
||||
msgstr "Listedeki önceki akış"
|
||||
|
||||
msgid "Next stream in the list"
|
||||
msgstr "Listedeki sonraki akış"
|
||||
|
||||
msgid "Toggle in fullscreen"
|
||||
msgstr "Tam ekranda geçiş yap"
|
||||
|
||||
msgid "Close"
|
||||
msgstr "Kapat"
|
||||
|
||||
# Picons dialog
|
||||
msgid "Load providers"
|
||||
msgstr "Yük sağlayıcılar"
|
||||
|
||||
msgid "Providers"
|
||||
msgstr "Yayıncılar"
|
||||
|
||||
msgid "Receive picons"
|
||||
msgstr "Piconları al"
|
||||
|
||||
msgid "Picons name format:"
|
||||
msgstr "Piconların adı biçimi:"
|
||||
|
||||
msgid "Resize:"
|
||||
msgstr "Yeniden boyutlandır:"
|
||||
|
||||
msgid "Current picons path:"
|
||||
msgstr "Geçerli picon yolları:"
|
||||
|
||||
msgid "Receiver picons path:"
|
||||
msgstr "Alıcı picon yolu:"
|
||||
|
||||
msgid "Picons download tool"
|
||||
msgstr "Picon indirme aracı"
|
||||
|
||||
msgid "Transfer to receiver"
|
||||
msgstr "Alıcıya aktar"
|
||||
|
||||
msgid "Downloader"
|
||||
msgstr "İndirici"
|
||||
|
||||
msgid "Converter"
|
||||
msgstr "Dönüştürücü"
|
||||
|
||||
msgid "Convert"
|
||||
msgstr "Dönüştür"
|
||||
|
||||
msgid "Path to save:"
|
||||
msgstr "Kaydetme yolu:"
|
||||
|
||||
msgid "Path to Enigma2 picons:"
|
||||
msgstr "Enigma2 piconların yolu:"
|
||||
|
||||
msgid "Specify the correct position value for the provider!"
|
||||
msgstr "Sağlayıcı için doğru pozisyon değerini belirtin!"
|
||||
|
||||
msgid "Converter between name formats"
|
||||
msgstr "İsim formatları arasında dönüştürücü"
|
||||
|
||||
msgid "Receive picons for providers"
|
||||
msgstr "Sağlayıcılar için picon alma"
|
||||
|
||||
msgid "Load satellite providers."
|
||||
msgstr "Uydu sağlayıcılarını yükle."
|
||||
|
||||
msgid ""
|
||||
"To automatically set the identifiers for picons,\n"
|
||||
"first load the required services list into the main application window."
|
||||
msgstr ""
|
||||
"Picon tanımlayıcılarını otomatik olarak ayarlamak için \n"
|
||||
"önce gerekli uygulama listesini ana uygulama penceresine yükleyin."
|
||||
|
||||
# Satellites editor
|
||||
msgid "Satellites edit tool"
|
||||
msgstr "Uydular düzenleme aracı"
|
||||
|
||||
msgid "Add"
|
||||
msgstr "Ekle"
|
||||
|
||||
msgid "Satellite"
|
||||
msgstr "Uydu"
|
||||
|
||||
msgid "Transponder"
|
||||
msgstr "Transponder"
|
||||
|
||||
msgid "Satellite properties:"
|
||||
msgstr "Uydu özellikleri:"
|
||||
|
||||
msgid "Transponder properties:"
|
||||
msgstr "Transponder özellikleri:"
|
||||
|
||||
msgid "Name"
|
||||
msgstr "Ad"
|
||||
|
||||
msgid "Position"
|
||||
msgstr "Konum"
|
||||
|
||||
# Satellites update dialog
|
||||
msgid "Satellites update"
|
||||
msgstr "Uydular güncelleme"
|
||||
|
||||
msgid "Remove selection"
|
||||
msgstr "Seçimi kaldır"
|
||||
|
||||
# Service details dialog
|
||||
msgid "Service data:"
|
||||
msgstr "Servis verileri:"
|
||||
|
||||
msgid "Transponder data:"
|
||||
msgstr "Transponder verileri:"
|
||||
|
||||
msgid "Service data"
|
||||
msgstr "Servis verileri"
|
||||
|
||||
msgid "Transponder details"
|
||||
msgstr "Transponder detayları"
|
||||
|
||||
msgid ""
|
||||
"Changes will be applied to all services of this transponder!\n"
|
||||
"Continue?"
|
||||
msgstr ""
|
||||
"Değişiklikler bu transponderin tüm servislerine uygulanacak!\n"
|
||||
"Devam edilsinmi?"
|
||||
|
||||
msgid "Reference"
|
||||
msgstr "Referans"
|
||||
|
||||
msgid "Namespace"
|
||||
msgstr "Ad alanı"
|
||||
|
||||
msgid "Flags:"
|
||||
msgstr "Bayraklar:"
|
||||
|
||||
msgid "Delays (ms):"
|
||||
msgstr "Gecikmeler (ms):"
|
||||
|
||||
msgid "Bitstream"
|
||||
msgstr "Bit akımı"
|
||||
|
||||
msgid "Description"
|
||||
msgstr "Açıklama"
|
||||
|
||||
msgid "Source:"
|
||||
msgstr "Kaynak:"
|
||||
|
||||
msgid "Cancel"
|
||||
msgstr "İptal"
|
||||
|
||||
msgid "Update"
|
||||
msgstr "Güncelle"
|
||||
|
||||
msgid "Filter"
|
||||
msgstr "Filtre"
|
||||
|
||||
msgid "Find"
|
||||
msgstr "Bul"
|
||||
|
||||
# IPTV dialog
|
||||
msgid "Stream data"
|
||||
msgstr "Veri akışı"
|
||||
|
||||
# IPTV list configuration dialog
|
||||
msgid "Starting values"
|
||||
msgstr "Başlangıç değerleri"
|
||||
|
||||
msgid "Reset to default"
|
||||
msgstr "Varsayılana sıfırla"
|
||||
|
||||
msgid "IPTV streams list configuration"
|
||||
msgstr "IPTV akış listesi yapılandırması"
|
||||
|
||||
# Settings dialog
|
||||
msgid "Preferences"
|
||||
msgstr "Tercihler"
|
||||
|
||||
msgid "Profile:"
|
||||
msgstr "Profil:"
|
||||
|
||||
msgid "Timeout between commands in seconds"
|
||||
msgstr "Komutlar arasında saniye cinsinden zaman aşımı"
|
||||
|
||||
msgid "Timeout:"
|
||||
msgstr "Zaman aşımı:"
|
||||
|
||||
msgid "Login:"
|
||||
msgstr "Giriş:"
|
||||
|
||||
msgid "Options"
|
||||
msgstr "Seçenekler"
|
||||
|
||||
msgid "Password:"
|
||||
msgstr "Parola:"
|
||||
|
||||
msgid "Picons:"
|
||||
msgstr "Piconlar:"
|
||||
|
||||
msgid "Port:"
|
||||
msgstr "Port:"
|
||||
|
||||
msgid "Data path:"
|
||||
msgstr "Veri yolu:"
|
||||
|
||||
msgid "Picons path:"
|
||||
msgstr "Picon yolu:"
|
||||
|
||||
msgid "Network settings:"
|
||||
msgstr "Ağ ayarları:"
|
||||
|
||||
msgid "STB file paths:"
|
||||
msgstr "STB dosya yolları:"
|
||||
|
||||
msgid "Local file paths:"
|
||||
msgstr "Yerel dosya yolları:"
|
||||
|
||||
# Dialogs messages
|
||||
msgid "Error. No bouquet is selected!"
|
||||
msgstr "Hata. Buket seçilmedi!"
|
||||
|
||||
msgid "This item is not allowed to be removed!"
|
||||
msgstr "Bu öğenin kaldırılmasına izin verilmiyor!"
|
||||
|
||||
msgid "This item is not allowed to edit!"
|
||||
msgstr "Bu öğenin düzenlenmesine izin verilmiyor!"
|
||||
|
||||
msgid "Not allowed in this context!"
|
||||
msgstr "Bu bağlamda izin verilmiyor!"
|
||||
|
||||
msgid "Please, download files from receiver or setup your path for read data!"
|
||||
msgstr "Lütfen, alıcıdan dosya indirin veya veri okumak için yolunuzu ayarlayın!"
|
||||
|
||||
msgid "Reading data error!"
|
||||
msgstr "Veri hatası okunuyor!"
|
||||
|
||||
msgid "No m3u file is selected!"
|
||||
msgstr "Hiçbir m3u dosyası seçilmedi!"
|
||||
|
||||
msgid "Not implemented yet!"
|
||||
msgstr "Henüz uygulanmadı!"
|
||||
|
||||
msgid "The text of marker is empty, please try again!"
|
||||
msgstr "İşaretçi metni boş, lütfen tekrar deneyin!"
|
||||
|
||||
msgid "Please, select only one item!"
|
||||
msgstr "Lütfen sadece bir ürün seçiniz!"
|
||||
|
||||
msgid "No png file is selected!"
|
||||
msgstr "Hiçbir png dosyası seçilmedi!"
|
||||
|
||||
msgid "No reference is present!"
|
||||
msgstr "Referans yok!"
|
||||
|
||||
msgid "No selected item!"
|
||||
msgstr "Seçili öğe yok!"
|
||||
|
||||
msgid "The task is already running!"
|
||||
msgstr "Görev zaten çalışıyor!"
|
||||
|
||||
msgid "Done!"
|
||||
msgstr "Bitti!"
|
||||
|
||||
msgid "Please, wait..."
|
||||
msgstr "Lütfen bekleyin ..."
|
||||
|
||||
msgid "Resizing..."
|
||||
msgstr "Yeniden boyutlandırılıyor ..."
|
||||
|
||||
msgid "Select paths!"
|
||||
msgstr "Yolları seç!"
|
||||
|
||||
msgid "No satellite is selected!"
|
||||
msgstr "Uydu seçilmedi!"
|
||||
|
||||
msgid "Please, select only one satellite!"
|
||||
msgstr "Lütfen sadece bir uydu seçin!"
|
||||
|
||||
msgid "Please check your parameters and try again."
|
||||
msgstr "Lütfen parametrelerinizi kontrol edip tekrar deneyin."
|
||||
|
||||
msgid "No satellites.xml file is selected!"
|
||||
msgstr "Hiçbir satellites.xml dosyası seçilmedi!"
|
||||
|
||||
msgid "Error. Verify the data!"
|
||||
msgstr "Hata. Verileri doğrulayın!"
|
||||
|
||||
msgid "Operation not allowed in this context!"
|
||||
msgstr "Bu bağlamda işleme izin verilmiyor!"
|
||||
|
||||
msgid "No VLC is found. Check that it is installed!"
|
||||
msgstr "VLC bulunamadı. Yüklü olduğundan emin olun!"
|
||||
|
||||
# Search unavailable streams dialog
|
||||
msgid "Please wait, streams testing in progress..."
|
||||
msgstr "Lütfen bekleyin, akış testi devam ediyor ..."
|
||||
|
||||
msgid "Found"
|
||||
msgstr "Bulundu"
|
||||
|
||||
msgid "unavailable streams."
|
||||
msgstr "mevcut olmayan akışlar."
|
||||
|
||||
msgid "No changes required!"
|
||||
msgstr "Hiçbir değişiklik gerekli!"
|
||||
|
||||
msgid "This list does not contains IPTV streams!"
|
||||
msgstr "Bu liste IPTV akışı içermiyor!"
|
||||
|
||||
msgid "New empty configuration"
|
||||
msgstr "Yeni boş yapılandırma"
|
||||
|
||||
msgid "No data to save!"
|
||||
msgstr "Kaydedilecek veri yok!"
|
||||
|
||||
msgid "Network"
|
||||
msgstr "Ağ"
|
||||
|
||||
msgid "Paths"
|
||||
msgstr "Yollar"
|
||||
|
||||
msgid "Program"
|
||||
msgstr "Program"
|
||||
|
||||
msgid "Backup:"
|
||||
msgstr "Yedekleme:"
|
||||
|
||||
msgid "Backup"
|
||||
msgstr "Yedekleme"
|
||||
|
||||
msgid "Backups"
|
||||
msgstr "Yedeklemeler"
|
||||
|
||||
msgid "Backup path:"
|
||||
msgstr "Yedekleme yolu:"
|
||||
|
||||
msgid "Restore bouquets"
|
||||
msgstr "Buketleri geri yükle"
|
||||
|
||||
msgid "Restore all"
|
||||
msgstr "Tümünü geri yükle"
|
||||
|
||||
msgid "Before saving"
|
||||
msgstr "Kaydetmeden önce"
|
||||
|
||||
msgid "Before downloading from the receiver"
|
||||
msgstr "Alıcıdan indirmeden önce"
|
||||
|
||||
msgid "Set background color for the services"
|
||||
msgstr "Hizmetler için arka plan rengini ayarla"
|
||||
|
||||
msgid "Marked as new:"
|
||||
msgstr "Yeni olarak işaretlendi:"
|
||||
|
||||
msgid "With an extra name in the bouquet:"
|
||||
msgstr "Bukette fazladan bir isim ile:"
|
||||
|
||||
msgid "Select"
|
||||
msgstr "Seç"
|
||||
|
||||
msgid "About"
|
||||
msgstr "Hakkında"
|
||||
|
||||
msgid "Exit"
|
||||
msgstr "Çıkış"
|
||||
|
||||
msgid "Tools"
|
||||
msgstr "Araçlar"
|
||||
|
||||
# Import
|
||||
msgid "Import"
|
||||
msgstr "İçe aktar"
|
||||
|
||||
msgid "Bouquet"
|
||||
msgstr "Buket"
|
||||
|
||||
msgid "Bouquets and services"
|
||||
msgstr "Buketler ve hizmetler"
|
||||
|
||||
msgid "The main list does not contain services for this bouquet!"
|
||||
msgstr "Ana liste bu buket için hizmet içermiyor!"
|
||||
|
||||
msgid "No bouquet file is selected!"
|
||||
msgstr "Hiçbir buket dosyası seçilmedi!"
|
||||
|
||||
msgid "Remove all unused"
|
||||
msgstr "Kullanılmayanların tümünü kaldır"
|
||||
|
||||
msgid "Test"
|
||||
msgstr "Test"
|
||||
|
||||
msgid "Test connection"
|
||||
msgstr "Bağlantıyı test et"
|
||||
|
||||
msgid "Double click on the service in the bouquet list:"
|
||||
msgstr "Buket listesindeki hizmete çift tıklayın:"
|
||||
|
||||
msgid "Zap"
|
||||
msgstr "Zap"
|
||||
|
||||
msgid "Play stream"
|
||||
msgstr "Akışı oynat"
|
||||
|
||||
msgid "Disabled"
|
||||
msgstr "Devre dışı"
|
||||
|
||||
msgid "Enable ver. 5 support (experimental)"
|
||||
msgstr "Sürüm 5 desteğini etkinleştir (deneysel)"
|
||||
|
||||
msgid "Enable HTTP API (experimental)"
|
||||
msgstr "HTTP API'sini etkinleştir (deneysel)"
|
||||
|
||||
msgid "Switch(zap) the channel(Ctrl + Z)"
|
||||
msgstr "Kanalı değiştir (zap) (Ctrl + Z)"
|
||||
|
||||
msgid "Switch the channel and watch in the program(Ctrl + W)"
|
||||
msgstr "Kanal değiştirme ve programda izleme (Ctrl + W)"
|
||||
|
||||
msgid "Play IPTV or other stream in the program(Ctrl + P)"
|
||||
msgstr "Programdaki IPTV veya diğer akışları oynat (Ctrl + P)"
|
||||
|
||||
msgid "Export to m3u"
|
||||
msgstr "Dışa aktar M3U"
|
||||
|
||||
msgid "EPG configuration"
|
||||
msgstr "EPG yapılandırması"
|
||||
|
||||
msgid "Apply"
|
||||
msgstr "Uygula"
|
||||
|
||||
msgid "EPG source"
|
||||
msgstr "EPG kaynağı"
|
||||
|
||||
msgid "Service names source:"
|
||||
msgstr "Hizmet adları kaynağı:"
|
||||
|
||||
msgid "Main service list"
|
||||
msgstr "Ana hizmet listesi"
|
||||
|
||||
msgid "XML file"
|
||||
msgstr "XML dosyası"
|
||||
|
||||
msgid "Use web source"
|
||||
msgstr "Web kaynağını kullan"
|
||||
|
||||
msgid "Url to *.xml.gz file:"
|
||||
msgstr "URL. * .xml.gz dosyasına:"
|
||||
|
||||
msgid "Enable filtering"
|
||||
msgstr "Filtrelemeyi etkinleştir"
|
||||
|
||||
msgid "Filter by presence in the epg.dat file."
|
||||
msgstr "Epg.dat dosyasındaki varlığına göre filtreleyin."
|
||||
|
||||
msgid "Paths to the epg.dat file:"
|
||||
msgstr "Epg.dat dosyasının yolları:"
|
||||
|
||||
msgid "Local path:"
|
||||
msgstr "Yerel yol:"
|
||||
|
||||
msgid "STB path:"
|
||||
msgstr "STB yolu:"
|
||||
|
||||
msgid "Update on start"
|
||||
msgstr "Başlangıçta güncelleme"
|
||||
|
||||
msgid "Auto configuration by service names."
|
||||
msgstr "Hizmet adlarına göre otomatik yapılandırma."
|
||||
|
||||
msgid "Save list to xml."
|
||||
msgstr "Listeyi xml'ye kaydet."
|
||||
|
||||
msgid "Download XML file error."
|
||||
msgstr "XML dosyası indir hatası."
|
||||
|
||||
msgid "Unsupported file type:"
|
||||
msgstr "Desteklenmeyen dosya türü:"
|
||||
|
||||
msgid "Unpacking data error."
|
||||
msgstr "Veri paketi açılırken hata oluştu."
|
||||
|
||||
msgid "XML parsing error:"
|
||||
msgstr "XML ayrıştırma hatası:"
|
||||
|
||||
msgid "Count of successfully configured services:"
|
||||
msgstr "Başarılı bir şekilde yapılandırılmış hizmetlerin sayısı:"
|
||||
|
||||
msgid "Current epg.dat file does not contains references for the services of this bouquet!"
|
||||
msgstr "Şu anki epg.dat dosyası bu buketin hizmetleri için referans içermiyor!"
|
||||
|
||||
msgid "Use HTTP"
|
||||
msgstr "HTTP kullan"
|
||||
|
||||
msgid "Close playback"
|
||||
msgstr "Oynatmayı kapat"
|
||||
|
||||
msgid "Import YouTube playlist"
|
||||
msgstr "YouTube oynatma listesini içe aktar"
|
||||
|
||||
msgid ""
|
||||
"Found a link to the YouTube resource!\n"
|
||||
"Try to get a direct link to the video?"
|
||||
msgstr ""
|
||||
"YouTube kaynağına bir bağlantı bulundu!\n"
|
||||
"Videoya doğrudan bağlantı almaya çalışılsın mı?"
|
||||
|
||||
msgid "Playlist import"
|
||||
msgstr "Oynatma listesi içe aktarma"
|
||||
|
||||
msgid "Getting link error:"
|
||||
msgstr "Bağlantı hatası alınıyor:"
|
||||
|
||||
msgid "Extra"
|
||||
msgstr "Ekstra"
|
||||
|
||||
msgid "Apply profile settings"
|
||||
msgstr "Profil ayarlarını uygula"
|
||||
|
||||
msgid "Settings type:"
|
||||
msgstr "Ayarlar türü:"
|
||||
|
||||
msgid "Set default"
|
||||
msgstr "Varsayılanı ayarla"
|
||||
|
||||
msgid "Language:"
|
||||
msgstr "Dil:"
|
||||
|
||||
msgid "Load the last open configuration at program startup"
|
||||
msgstr "Program açılışında son açık yapılandırmayı yükle"
|
||||
|
||||
msgid "Enable direct playback bar (experimental)"
|
||||
msgstr "Doğrudan oynatma çubuğunu etkinleştir (deneysel)"
|
||||
|
||||
msgid "Enables direct sending and playback of media links on the receiver"
|
||||
msgstr "Alıcıdaki medya bağlantılarının doğrudan gönderilmesini ve oynatılmasını sağlar"
|
||||
|
||||
msgid "Watch the channel in the program"
|
||||
msgstr "Programdaki kanalı izle"
|
||||
|
||||
msgid "Zap and Play"
|
||||
msgstr "Zap ve Oyna"
|
||||
|
||||
msgid "Drag or paste the link here"
|
||||
msgstr "Bağlantıyı buraya sürükleyin veya yapıştırın"
|
||||
|
||||
msgid "Remove added links in the playlist"
|
||||
msgstr "Oynatma listesine eklenen bağlantıları kaldır"
|
||||
|
||||
msgid "A bouquet with that name exists!"
|
||||
msgstr "Bu isimli bir buket var!"
|
||||
|
||||
msgid "Details"
|
||||
msgstr "Detaylar"
|
||||
|
||||
msgid "Profile"
|
||||
msgstr "Profil"
|
||||
|
||||
msgid "Reset"
|
||||
msgstr "Y.başlat"
|
||||
|
||||
msgid "File"
|
||||
msgstr "Dosya"
|
||||
|
||||
msgid "Picons manager"
|
||||
msgstr "Picon yöneticisi"
|
||||
|
||||
msgid "Explorer"
|
||||
msgstr "Explorer"
|
||||
|
||||
msgid "Satellite url:"
|
||||
msgstr "Uydu url:"
|
||||
|
||||
msgid "Cut"
|
||||
msgstr "Kes"
|
||||
|
||||
msgid "Paste"
|
||||
msgstr "Yapıştır"
|
||||
|
||||
msgid "To the top"
|
||||
msgstr "Başlangıçta"
|
||||
|
||||
msgid "To the end"
|
||||
msgstr "Sonunda"
|
||||
|
||||
msgid "View"
|
||||
msgstr "Görünüm"
|
||||
|
||||
msgid "Lock"
|
||||
msgstr "Kilit"
|
||||
|
||||
msgid "Parent lock"
|
||||
msgstr "Ebeveyn kilidi"
|
||||
|
||||
msgid "Hide/Skip"
|
||||
msgstr "Gizle/Atla"
|
||||
|
||||
msgid "IPTV tools"
|
||||
msgstr "IPTV araçları"
|
||||
|
||||
msgid "Make profile folder as default for the additional data"
|
||||
msgstr "Ek veriler için profil klasörünü varsayılan yap"
|
||||
|
||||
msgid "Default data path:"
|
||||
msgstr "Varsayılan veri yolu:"
|
||||
|
||||
msgid "Streams record path:"
|
||||
msgstr "Akış kayıt yolu:"
|
||||
|
||||
msgid "Record"
|
||||
msgstr "Kayıt"
|
||||
|
||||
msgid "Record:"
|
||||
msgstr "Kayıt:"
|
||||
|
||||
msgid "Record to disk:"
|
||||
msgstr "Diske kaydet:"
|
||||
|
||||
msgid "Streaming"
|
||||
msgstr "Yayın Akışı"
|
||||
|
||||
msgid "Activate transcoding"
|
||||
msgstr "Kod dönüştürmeyi etkinleştir"
|
||||
|
||||
msgid "Presets:"
|
||||
msgstr "Ön ayarlar:"
|
||||
|
||||
msgid "Video options:"
|
||||
msgstr "Video seçenekleri:"
|
||||
|
||||
msgid "Audio options:"
|
||||
msgstr "Ses seçenekleri:"
|
||||
|
||||
msgid "Bitrate (kb/s):"
|
||||
msgstr "Bit hızı (kb/s):"
|
||||
|
||||
msgid "Codec:"
|
||||
msgstr "Codec:"
|
||||
|
||||
msgid "Width (px):"
|
||||
msgstr "Genişlik (px):"
|
||||
|
||||
msgid "Height (px):"
|
||||
msgstr "Yükseklik (px):"
|
||||
|
||||
msgid "Channels:"
|
||||
msgstr "Kanallar:"
|
||||
|
||||
msgid "Sample rate (Hz):"
|
||||
msgstr "Örnekleme hızı (Hz):"
|
||||
|
||||
msgid "Play streams mode:"
|
||||
msgstr "Akışları oynatma modu:"
|
||||
|
||||
msgid "Built-in player"
|
||||
msgstr "Dahili oynatıcı"
|
||||
|
||||
msgid "VLC media player"
|
||||
msgstr "VLC media player"
|
||||
|
||||
msgid "Only get m3u file"
|
||||
msgstr "Sadece m3u dosyası al"
|
||||
|
||||
msgid "Save and restart the program to apply the settings."
|
||||
msgstr "Ayarları uygulamak için programı kaydedin ve yeniden başlatın."
|
||||
|
||||
msgid "Some images may have problems displaying the favorites list!"
|
||||
msgstr "Bazı resimler sık kullanılanlar listesini görüntülerken sorun yaşayabilir!"
|
||||
|
||||
msgid "Operates in standby mode or current active transponder!"
|
||||
msgstr "Bekleme modunda veya geçerli aktif transponderde çalışır!"
|
||||
|
||||
msgid "No connection to the receiver!"
|
||||
msgstr "Alıcıya bağlantı yok!"
|
||||
|
||||
msgid "Signal level"
|
||||
msgstr "Sinyal seviyesi"
|
||||
|
||||
msgid "Receiver info"
|
||||
msgstr "Alıcı bilgisi"
|
||||
|
||||
msgid "A profile with that name exists!"
|
||||
msgstr "Bu ada sahip bir profil var!"
|
||||
|
||||
msgid "Show short info as hints in the main services list"
|
||||
msgstr "Kısa bilgileri ana hizmetler listesinde ipuçları olarak göster"
|
||||
|
||||
msgid "Show detailed info as hints in the bouquet list"
|
||||
msgstr "Ayrıntılı bilgileri buket listesinde ipuçları olarak göster"
|
||||
|
||||
msgid "Enable alternate bouquet file naming"
|
||||
msgstr "Alternatif buket dosyası adlandırmasını etkinleştir"
|
||||
|
||||
msgid "Allows you to name bouquet files using their names."
|
||||
msgstr "Buket dosyalarını isimlerini kullanarak isimlendirmenizi sağlar."
|
||||
|
||||
msgid "Appearance"
|
||||
msgstr "Görünüm"
|
||||
|
||||
msgid "Enable Themes support"
|
||||
msgstr "Temalar desteğini etkinleştir"
|
||||
|
||||
msgid "Gtk3 Theme:"
|
||||
msgstr "Gtk3 Teması:"
|
||||
|
||||
msgid "Icon Theme:"
|
||||
msgstr "Simge Teması:"
|
||||
|
||||
msgid "Gtk3 Themes and Icons:"
|
||||
msgstr "Gtk3 Tema ve Simgeler:"
|
||||
34
start.py
34
start.py
@@ -1,29 +1,19 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
|
||||
|
||||
def update_icon():
|
||||
need_update = False
|
||||
icon_name = "DemonEditor.desktop"
|
||||
|
||||
with open(icon_name, "r") as f:
|
||||
lines = f.readlines()
|
||||
for i, line in enumerate(lines):
|
||||
if line.startswith("Icon="):
|
||||
icon_path = line.lstrip("Icon=")
|
||||
current_path = "{}/app/ui/icons/hicolor/96x96/apps/demon-editor.png".format(os.getcwd())
|
||||
if icon_path != current_path:
|
||||
need_update = True
|
||||
lines[i] = "Icon={}\n".format(current_path)
|
||||
break
|
||||
|
||||
if need_update:
|
||||
with open(icon_name, "w") as f:
|
||||
f.writelines(lines)
|
||||
|
||||
try:
|
||||
from Cocoa import NSBundle
|
||||
except ImportError as e:
|
||||
print(e)
|
||||
else:
|
||||
ns_bundle = NSBundle.mainBundle()
|
||||
if ns_bundle:
|
||||
ns_bundle = ns_bundle.localizedInfoDictionary() or ns_bundle.infoDictionary()
|
||||
if ns_bundle:
|
||||
ns_bundle["CFBundleName"] = "DemonEditor"
|
||||
|
||||
if __name__ == "__main__":
|
||||
from multiprocessing import set_start_method
|
||||
from app.ui.main_app_window import start_app
|
||||
|
||||
update_icon()
|
||||
set_start_method("fork") # For compatibility [Python > 3.7]
|
||||
start_app()
|
||||
|
||||
Reference in New Issue
Block a user