diff --git a/DemonEditor.spec b/DemonEditor.spec
index 6fe9bde6..859d9b16 100644
--- a/DemonEditor.spec
+++ b/DemonEditor.spec
@@ -1,67 +1,48 @@
-import os
-import datetime
-import distutils.util
+# -*- mode: python ; coding: utf-8 -*-
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
-BUILD_DATE = datetime.datetime.now().strftime("%Y%m%d")
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')
+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,
+ binaries=[],
datas=ui_files,
- hiddenimports=['fileinput', 'uuid'],
+ hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=['youtube_dl', 'tkinter'],
win_no_prefer_redirects=False,
win_private_assemblies=False,
+ cipher=block_cipher,
+ noarchive=False)
+pyz = PYZ(a.pure, a.zipped_data,
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,
+ bootloader_ignore_signals=False,
+ strip=False,
upx=True,
- console=False)
-
+ console=False, icon='icon.ico')
coll = COLLECT(exe,
a.binaries,
a.zipfiles,
a.datas,
- strip=STRIP,
+ strip=False,
upx=True,
+ upx_exclude=[],
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",
- 'LSApplicationCategoryType': 'public.app-category.utilities',
- 'CFBundleShortVersionString': "1.0.4 Beta (Build: {})".format(BUILD_DATE),
- 'NSHumanReadableCopyright': u"Copyright © 2020, Dmitriy Yefremov",
- 'NSRequiresAquaSystemAppearance': 'false'
- })
diff --git a/README.md b/README.md
index 24fcf925..9fe892d0 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,6 @@
#
DemonEditor
-[](LICENSE) 
-## Enigma2 channel and satellite list editor for macOS (experimental).
-
-
+[](LICENSE) 
+## Enigma2 channel and satellite list editor for MS Windows (experimental).
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).
@@ -22,61 +20,36 @@ Focused on the convenience of working in lists from the keyboard. The mouse is a
* Control panel with the ability to view EPG and manage timers (via HTTP API, experimental).
* Simple FTP client (experimental).
-#### Keyboard shortcuts
-* **⌘ + X** - only in bouquet list.
-* **⌘ + C** - only in services list.
-Clipboard is **"rubber"**. There is an accumulation before the insertion!
-* **⌘ + 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.
+#### Keyboard shortcuts
+* **Ctrl + X** - only in bouquet list.
+* **Ctrl + C** - only in services list.
+Clipboard is **"rubber"**. There is an accumulation before the insertion!
+* **Ctrl + Insert** - copies the selected channels from the main list to the bouquet
+ beginning or inserts (creates) a new bouquet.
+* **Ctrl + BackSpace** - copies the selected channels from the main list to the bouquet end.
+* **Ctrl + E** - edit.
+* **Ctrl + R, F2** - rename.
+* **Ctrl + S, T** in Satellites edit tool for create satellite or transponder.
+* **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.
+* **Ctrl + I** - extra info, details.
+* **Ctrl + F** - show/hide search bar.
+* **Ctrl + Shift + F** - show/hide filter bar.
-For **multiple** selection with the mouse, press and hold the **⌘** key!
+For **multiple** selection with the mouse, press and hold the **Ctrl** key!
## Minimum requirements
-*Python >= 3.5.2, GTK+ >= 3.16 with PyGObject bindings, python3-requests.*
+*Python >= 3.4.4, GTK+ >= 3.16 with PyGObject bindings, python3-requests.*
-## Installation and Launch
-To run the program on macOS, you need to install [brew](https://brew.sh/).
-Then install the required components via terminal:
-```brew install python3 gtk+3 pygobject3 adwaita-icon-theme```
-```pip3 install requests```
-#### Optional:
-```brew install wget```
-```pip3 install pillow, pyobjc```
-
-To start the program, just download the [archive](https://github.com/DYefremov/DemonEditor/archive/experimental-mac.zip), unpack and run it from the terminal
-with the command: ```./start.py```
-## Standalone package
-You can also download the ready-made package as a ***.dmg** file from the [releases](https://github.com/DYefremov/DemonEditor/releases) page.
-Recommended copy the package to the **Application** directory.
-Perhaps in the security settings it will be necessary to allow the launch of this application!
-**The package may not contain all the latest changes. Not all features can be supported and tested!**
-
-THIS SOFTWARE COMES WITH ABSOLUTELY NO WARRANTY.
-AUTHOR IS NOT LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY CONNECTION WITH THIS SOFTWARE.
-The package may contain components distributed under the GPL [v3](http://www.gnu.org/licenses/gpl-3.0.html) or lower license.
-By downloading and using this 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!
-
-#### Building your own package
-Install [PyInstaller](https://www.pyinstaller.org/) with the command from the terminal:
-
-```pip3 install pyinstaller```
-
-and in the root dir run command:
-
-```pyinstaller DemonEditor.spec```
## Important
**This version is not fully tested and has experimental status!**
@@ -88,6 +61,7 @@ When using the multiple import feature, from *lamedb* will be taken data **only
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.
+
#### Command line arguments:
* **-l** - write logs to file.
* **-d on/off** - turn on/off debug mode. Allows to display more information in the logs.
diff --git a/app/eparser/enigma/lamedb.py b/app/eparser/enigma/lamedb.py
index d6ca6798..59de230b 100644
--- a/app/eparser/enigma/lamedb.py
+++ b/app/eparser/enigma/lamedb.py
@@ -274,7 +274,7 @@ class LameDbWriter:
def write(self):
if self._fmt == 4:
# Writing lamedb file ver.4
- with open(self._path + _FILE_NAME, "w") as file:
+ with open(self._path + _FILE_NAME, "w", encoding="utf-8") as file:
file.writelines(LameDbReader.get_services_lines(self._services))
elif self._fmt == 5:
self.write_to_lamedb5()
diff --git a/app/settings.py b/app/settings.py
index 44e22c52..3a739174 100644
--- a/app/settings.py
+++ b/app/settings.py
@@ -5,14 +5,14 @@ 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
+SEP = os.sep
HOME_PATH = os.path.expanduser("~")
-CONFIG_PATH = HOME_PATH + "/.config/demon-editor/"
+CONFIG_PATH = HOME_PATH + "{}.config{}demon-editor{}".format(SEP, SEP, SEP)
CONFIG_FILE = CONFIG_PATH + "config.json"
-DATA_PATH = HOME_PATH + "/DemonEditor/data/"
+DATA_PATH = HOME_PATH + "{}DemonEditor{}data{}".format(SEP, SEP, SEP)
IS_DARWIN = sys.platform == "darwin"
IS_WIN = sys.platform == "win32"
@@ -34,9 +34,9 @@ class Defaults(Enum):
FAV_CLICK_MODE = 0
PLAY_STREAMS_MODE = 1 if IS_DARWIN else 0
PROFILE_FOLDER_DEFAULT = False
- RECORDS_PATH = DATA_PATH + "records/"
+ RECORDS_PATH = DATA_PATH + "records{}".format(SEP)
ACTIVATE_TRANSCODING = False
- ACTIVE_TRANSCODING_PRESET = "720p TV/device"
+ ACTIVE_TRANSCODING_PRESET = "720p TV{}device".format(SEP)
def get_settings():
@@ -82,13 +82,13 @@ def write_settings(config):
def set_local_paths(settings, profile_name, data_path=DATA_PATH, use_profile_folder=False):
- settings["data_local_path"] = "{}{}/".format(data_path, profile_name)
+ settings["data_local_path"] = "{}{}{}".format(data_path, profile_name, SEP)
if use_profile_folder:
- settings["picons_local_path"] = "{}{}/{}/".format(data_path, profile_name, "picons")
- settings["backup_local_path"] = "{}{}/{}/".format(data_path, profile_name, "backup")
+ settings["picons_local_path"] = "{}{}{}{}{}".format(data_path, profile_name, SEP, "picons", SEP)
+ settings["backup_local_path"] = "{}{}{}{}{}".format(data_path, profile_name, SEP, "backup", SEP)
else:
- settings["picons_local_path"] = "{}{}/{}/".format(data_path, "picons", profile_name)
- settings["backup_local_path"] = "{}{}/{}/".format(data_path, "backup", profile_name)
+ settings["picons_local_path"] = "{}{}{}{}{}".format(data_path, "picons", SEP, profile_name, SEP)
+ settings["backup_local_path"] = "{}{}{}{}{}".format(data_path, "backup", SEP, profile_name, SEP)
class SettingsType(IntEnum):
@@ -98,29 +98,29 @@ class SettingsType(IntEnum):
def get_default_settings(self):
""" Returns default settings for current type """
- print(self.value)
- if self.value == 0:
+ if self is SettingsType.ENIGMA_2:
return {"setting_type": self.value,
"host": "127.0.0.1", "port": "21", "timeout": 5,
"user": "root", "password": "root",
"http_port": "80", "http_timeout": 5, "http_use_ssl": False,
"telnet_port": "23", "telnet_timeout": 5,
"services_path": "/etc/enigma2/", "user_bouquet_path": "/etc/enigma2/",
- "satellites_xml_path": "/etc/tuxbox/", "data_local_path": DATA_PATH + "enigma2/",
+ "satellites_xml_path": "/etc/tuxbox/", "data_local_path": "{}enigma2{}".format(DATA_PATH, SEP),
"picons_path": "/usr/share/enigma2/picon/",
- "picons_local_path": DATA_PATH + "enigma2/picons/",
- "backup_local_path": DATA_PATH + "enigma2/backup/"}
- elif self.value == 1:
+ "picons_local_path": "{}enigma2{}picons{}".format(DATA_PATH, SEP, SEP),
+ "backup_local_path": "{}enigma2{}backup{}".format(DATA_PATH, SEP, SEP)}
+ elif self is SettingsType.NEUTRINO_MP:
return {"setting_type": self,
"host": "127.0.0.1", "port": "21", "timeout": 5,
"user": "root", "password": "root",
"http_port": "80", "http_timeout": 2, "http_use_ssl": False,
"telnet_port": "23", "telnet_timeout": 1,
"services_path": "/var/tuxbox/config/zapit/", "user_bouquet_path": "/var/tuxbox/config/zapit/",
- "satellites_xml_path": "/var/tuxbox/config/", "data_local_path": DATA_PATH + "neutrino/",
+ "satellites_xml_path": "/var/tuxbox/config/",
+ "data_local_path": "{}neutrino{}".format(DATA_PATH, SEP),
"picons_path": "/usr/share/tuxbox/neutrino/icons/logo/",
- "picons_local_path": DATA_PATH + "neutrino/picons/",
- "backup_local_path": DATA_PATH + "neutrino/backup/"}
+ "picons_local_path": "{}neutrino{}picons{}".format(DATA_PATH, SEP, SEP),
+ "backup_local_path": "{}neutrino{}backup{}".format(DATA_PATH, SEP, SEP)}
class SettingsException(Exception):
@@ -182,7 +182,7 @@ class Settings:
self._cp_settings[k] = v
def_path = self.default_data_path
- def_path += "enigma2/" if self.setting_type is SettingsType.ENIGMA_2 else "neutrino/"
+ def_path += "enigma2{}".format(SEP) if self.setting_type is SettingsType.ENIGMA_2 else "neutrino{}".format(SEP)
set_local_paths(self._cp_settings, self._current_profile, def_path, self.profile_folder_is_default)
if force_write:
diff --git a/app/ui/app_menu_bar.ui b/app/ui/app_menu_bar.ui
index 00371fa8..44694623 100644
--- a/app/ui/app_menu_bar.ui
+++ b/app/ui/app_menu_bar.ui
@@ -1,25 +1,5 @@
-