diff --git a/app/settings.py b/app/settings.py
index 0f6430e8..29e98777 100644
--- a/app/settings.py
+++ b/app/settings.py
@@ -619,8 +619,13 @@ class Settings:
self._settings["extra_color"] = value
@property
+ @lru_cache(1)
def dark_mode(self):
- return self._settings.get("dark_mode", False)
+ import subprocess
+
+ cmd = ["defaults", "read", "-g", "AppleInterfaceStyle"]
+ p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
+ return "Dark" in str(p[0])
@dark_mode.setter
def dark_mode(self, value):
diff --git a/app/tools/media.py b/app/tools/media.py
index e5c964de..62e2665b 100644
--- a/app/tools/media.py
+++ b/app/tools/media.py
@@ -3,7 +3,9 @@ import sys
from abc import ABC, abstractmethod
from datetime import datetime
-from app.commons import run_task, log, _DATE_FORMAT
+from gi.repository import Gdk, Gtk
+
+from app.commons import run_task, log, _DATE_FORMAT, run_with_delay
class Player(ABC):
@@ -69,11 +71,10 @@ class Player(ABC):
return get_pointer(gpointer)
def get_video_widget(self, widget):
- from gi.repository import Gtk, Gdk
-
area = Gtk.DrawingArea(visible=True)
area.connect("draw", self.on_drawing_area_draw)
- area.set_events(Gdk.ModifierType.BUTTON1_MASK)
+ area.connect("motion-notify-event", self.on_mouse_motion)
+ area.set_events(Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.POINTER_MOTION_MASK)
widget.add(area)
return area
@@ -83,6 +84,19 @@ class Player(ABC):
cr.set_source_rgb(0, 0, 0)
cr.paint()
+ def on_mouse_motion(self, widget, event):
+ display = widget.get_display()
+ window = widget.get_window()
+ cursor = Gdk.Cursor.new_from_name(display, "default")
+ window.set_cursor(cursor)
+
+ self.hide_mouse_cursor(window, display)
+
+ @run_with_delay(3)
+ def hide_mouse_cursor(self, window, display):
+ cursor = Gdk.Cursor.new_for_display(display, Gdk.CursorType.BLANK_CURSOR)
+ window.set_cursor(cursor)
+
@staticmethod
def make(name, mode, widget, buf_cb=None, position_cb=None, error_cb=None, playing_cb=None):
""" Factory method. We will not use a separate factory to return a specific implementation.
@@ -118,7 +132,10 @@ class MpvPlayer(Player):
try:
from app.tools import mpv
- self._player = mpv.MPV(wid=str(self.get_window_handle(self.get_video_widget(widget))))
+ self._player = mpv.MPV(wid=str(self.get_window_handle(self.get_video_widget(widget), )),
+ input_default_bindings=False,
+ input_cursor=False,
+ cursor_autohide="no")
except OSError as e:
log("{}: Load library error: {}".format(__class__.__name__, e))
raise ImportError("No libmpv is found. Check that it is installed!")
@@ -189,6 +206,11 @@ class GstPlayer(Player):
from gi.repository import Gst, GstVideo
# Initialization of GStreamer.
Gst.init(sys.argv)
+ gtk_sink = Gst.ElementFactory.make("gtksink")
+ if not gtk_sink:
+ msg = "GStreamer error: gtksink plugin not installed!"
+ log(msg)
+ raise ImportError(msg)
except (OSError, ValueError) as e:
log("{}: Load library error: {}".format(__class__.__name__, e))
raise ImportError("No GStreamer is found. Check that it is installed!")
@@ -203,10 +225,11 @@ class GstPlayer(Player):
self._is_playing = False
self._player = Gst.ElementFactory.make("playbin", "player")
# Initialization of the playback widget.
- vid_widget = self.get_video_widget(widget)
+ self._player.set_property("video-sink", gtk_sink)
+ vid_widget = gtk_sink.get_property("widget")
+ vid_widget.connect("motion-notify-event", self.on_mouse_motion)
widget.add(vid_widget)
vid_widget.show()
- self._player.set_window_handle(self.get_window_handle(vid_widget))
bus = self._player.get_bus()
bus.add_signal_watch()
@@ -316,6 +339,8 @@ class VlcPlayer(Player):
args = "--quiet {}".format("" if sys.platform == "darwin" else "--no-xlib")
self._player = vlc.Instance(args).media_player_new()
+ vlc.libvlc_video_set_key_input(self._player, False)
+ vlc.libvlc_video_set_mouse_input(self._player, False)
except (OSError, AttributeError) as e:
log("{}: Load library error: {}".format(__class__.__name__, e))
raise ImportError("No VLC is found. Check that it is installed!")
diff --git a/app/tools/picons.py b/app/tools/picons.py
index 39d47d57..7fce4992 100644
--- a/app/tools/picons.py
+++ b/app/tools/picons.py
@@ -173,20 +173,11 @@ class ProviderParser(HTMLParser):
url = attrs[0][1]
if any(d in url for d in self._DOMAINS):
self._current_row.append(url)
- if tag == "font" and len(attrs) == 1:
- atr = attrs[0]
- if len(atr) == 2 and atr[1] == "darkgreen":
- self._is_onid_tid = True
def handle_data(self, data):
""" Save content to a cell """
if self._is_td or self._is_th:
self._current_cell.append(data.strip())
- if self._is_onid_tid:
- m = self._ONID_TID_PATTERN.match(data)
- if m:
- self._on_id, tid = m.group().split("-")
- self._is_onid_tid = False
def handle_endtag(self, tag):
if tag == 'td':
@@ -208,32 +199,34 @@ class ProviderParser(HTMLParser):
len_row = len(row)
if len_row > 2:
- m = self._TRANSPONDER_FREQUENCY_PATTERN.match(row[1])
+ m = self._TRANSPONDER_FREQUENCY_PATTERN.match(row[0])
if m:
self._freq = m.group().split()[0]
- if len_row == 14:
+ if len_row > 12:
# Providers
- name = row[6]
+ name = row[5]
self._prv_names.add(name)
- m = self._ONID_TID_PATTERN.match(str(row[9]))
+ m = self._ONID_TID_PATTERN.match(str(row[-5]))
if m:
on_id, tid = m.group().split("-")
if on_id not in self._ids:
+ self._on_id = on_id
row[-2] = on_id
self._ids.add(on_id)
row[0] = self._positon
if name + on_id not in self._prv_names:
self._prv_names.add(name + on_id)
logo_data = None
- req = requests.get(self._BASE_URL + row[3], timeout=5)
- if req.status_code == 200:
- logo_data = req.content
- else:
- log("Downloading provider logo error: {}".format(req.reason))
- self.rows.append(Provider(logo=logo_data, name=name, pos=self._positon, url=row[5], on_id=on_id,
+ if row[2].startswith("/logo/"):
+ req = requests.get(self._BASE_URL + row[2], timeout=5)
+ if req.status_code == 200:
+ logo_data = req.content
+ else:
+ log("Downloading provider logo error: {}".format(req.reason))
+ self.rows.append(Provider(logo=logo_data, name=name, pos=self._positon, url=row[6], on_id=on_id,
ssid=None, single=False, selected=True))
- elif 6 < len_row < 14:
+ elif 6 < len_row < 12:
# Single services
name, url, ssid = None, None, None
if row[0].startswith("http"):
diff --git a/app/tools/satellites.py b/app/tools/satellites.py
index c0df73f6..7ca596bc 100644
--- a/app/tools/satellites.py
+++ b/app/tools/satellites.py
@@ -77,6 +77,8 @@ class Cell:
class SatellitesParser(HTMLParser):
""" Parser for satellite html page. """
+ POS_PAT = re.compile(r".*?(\d+\.\d°?[EW]).*")
+
def __init__(self, source=SatelliteSource.FLYSAT, entities=False, separator=' '):
HTMLParser.__init__(self)
@@ -150,40 +152,21 @@ 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(r"^https://www\.lyngsat\.com/[\w-]+\.html")
base_url = "https://www.lyngsat.com/"
sats = []
- names = set()
- current_pos = "0"
- for row in filter(lambda x: len(x) in (5, 7, 8), self._rows):
- r_len = len(row)
- if r_len == 7:
- current_pos = self.parse_position(row[2])
- name = row[1].rsplit("/")[-1].rstrip(".html").replace("-", " ")
- if name not in names:
- # [all in one] satellites
- sats.append((name, current_pos, row[5], base_url + row[1], False))
- names.add(name)
- name = row[4]
- if name not in names:
- sats.append((name, current_pos, row[5], base_url + row[3], False))
- names.add(name)
- if r_len == 8: # for a very limited number of satellites
- data = list(filter(None, row))
- urls = set()
- sat_type = ""
- for d in data:
- url = re.match(extra_pattern, d)
- if url:
- urls.add(url.group(0))
- if d in ("C", "Ku", "CKu"):
- sat_type = d
- 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, base_url + url, False))
- elif r_len == 5:
- sats.append((row[2], current_pos, row[3], base_url + row[1], False))
+ cur_pos = "0"
+ for row in filter(lambda x: 3 < len(x) < 8, self._rows):
+ if not row[0]:
+ row = row[1:]
+
+ pos = self.parse_position(row[1])
+ if not self.POS_PAT.match(pos):
+ if len(row) == 4 and row[0].endswith(".html"):
+ sats.append((row[1], cur_pos, row[-2], base_url + row[0], False))
+ continue
+
+ sats.append((row[-3], pos, row[-2], base_url + row[0], False))
+ cur_pos = pos
return sats
elif source is SatelliteSource.KINGOFSAT:
def get_sat(r):
@@ -321,11 +304,10 @@ class SatellitesParser(HTMLParser):
Since the *.ini file contains incomplete information, it is not used.
"""
zeros = "000"
- pos_pat = re.compile(r".*?(\d+\.\d°[EW]).*")
pat = re.compile(
r"(\d+).00\s+([RLHV])\s+(DVB-S[2]?)\s+(?:T2-MI, PLP (\d+)\s+)?(.*PSK).*?(?:Stream\s+(\d+))?\s+(\d+)\s+(\d+/\d+)$")
- for row in filter(lambda r: len(r) == 16 and pos_pat.match(r[0]), self._rows):
+ for row in filter(lambda r: len(r) == 16 and self.POS_PAT.match(r[0]), self._rows):
res = pat.search(" ".join((row[0], row[2], row[3], row[8], row[9], row[10])))
if res:
freq, sr, pol, fec, sys = res.group(1), res.group(7), res.group(2), res.group(8), res.group(3)
@@ -343,9 +325,10 @@ class ServicesParser(HTMLParser):
HTMLParser.__init__(self)
- self._S_TYPES = {"": "2", "MPEG-2 SD": "1", "SD": "1", "MPEG-4 SD": "22", "HEVC SD": "22", "MPEG-4 HD": "25",
- "MPEG-4 HD 1080": "25", "MPEG-4 HD 720": "25", "HEVC HD": "25", "HEVC UHD": "31",
- "HEVC UHD 4K": "31"}
+ self._S_TYPES = {"": "2", "MPEG-2 SD": "1", "MPEG-2/SD": "1", "SD": "1", "MPEG-4 SD": "22", "MPEG-4/SD": "22",
+ "MPEG-4": "22", "HEVC SD": "22", "MPEG-4/HD": "25", "MPEG-4 HD": "25", "MPEG-4 HD 1080": "25",
+ "MPEG-4 HD 720": "25", "HEVC HD": "25", "HEVC/HD": "25", "HEVC": "31", "HEVC/UHD": "31",
+ "HEVC UHD": "31", "HEVC UHD 4K": "31"}
self._TR_PAT = re.compile(
r".*?(\d+)\s+([RLHV]).*(DVB-S[2]?)/?(.*PSK)?\s(T2-MI)?\s?SR-FEC:\s(\d+)-(\d/\d)\s+.*ONID-TID:\s+(\d+)-(\d+).*")
self._POS_PAT = re.compile(r".*?(\d+\.\d°[EW]).*")
@@ -421,8 +404,8 @@ class ServicesParser(HTMLParser):
log(e)
else:
url = "https://www.lyngsat.com/muxes/"
- return [row[1] for row in
- filter(lambda x: x and len(x) > 8 and x[1].url and x[1].url.startswith(url), self._rows)]
+ return [row[0] for row in
+ filter(lambda x: x and len(x) > 8 and x[0].url and x[0].url.startswith(url), self._rows)]
return []
def get_transponder_services(self, tr_url, sat_position=None, use_pids=False):
diff --git a/app/ui/app_menu_bar.ui b/app/ui/app_menu_bar.ui
index 44694623..cb770e21 100644
--- a/app/ui/app_menu_bar.ui
+++ b/app/ui/app_menu_bar.ui
@@ -1,8 +1,30 @@
+
\ No newline at end of file
diff --git a/app/ui/ftp.glade b/app/ui/ftp.glade
index 3019ac8c..f81e836b 100644
--- a/app/ui/ftp.glade
+++ b/app/ui/ftp.glade
@@ -93,27 +93,97 @@ Author: Dmitriy Yefremov
0
in
-
@@ -132,7 +132,7 @@ Author: Dmitriy Yefremov
Paste
True
-
+
@@ -149,7 +149,7 @@ Author: Dmitriy Yefremov
Edit
True
-
+
@@ -184,6 +184,11 @@ Author: Dmitriy Yefremov
+
+ True
+ False
+ input-gaming-symbolic
+
@@ -223,7 +228,7 @@ Author: Dmitriy Yefremov
Cut
True
-
+
@@ -234,7 +239,7 @@ Author: Dmitriy Yefremov
Copy
True
-
+
@@ -245,7 +250,7 @@ Author: Dmitriy Yefremov
Paste
True
-
+
@@ -261,7 +266,7 @@ Author: Dmitriy Yefremov
Edit
True
-
+
@@ -308,6 +313,15 @@ Author: Dmitriy Yefremov
+
+
+
@@ -1098,6 +1116,7 @@ Author: Dmitriy Yefremov
center
demon-editor
center
+ DemonEditor
@@ -1108,128 +1127,18 @@ Author: Dmitriy Yefremov
False
vertical
-
+
True
False
- center
- 10
- 10
- 10
10
-
- True
+
False
- False
- Profile
- 0
-
-
-
- False
- True
- 0
-
-
-
-
- True
- False
- expand
-
-
- True
- False
- True
- Open
- app.on_data_open
- open_image
- True
-
-
- True
- True
- 0
-
-
-
-
-
- True
- False
- True
- FTP-transfer
- app.on_download
- ftp_image
- True
-
-
- True
- True
- 1
-
-
-
-
-
- True
- True
- Telnet
- app.on_telnet_client_show
- telnet_image
- True
-
-
- True
- True
- 2
-
-
-
-
-
- False
- True
- Save
- app.on_data_save
- save_image
- True
-
-
- True
- True
- 3
-
-
-
-
-
- True
- False
- True
- Backups
- app.on_backup_tool_show
- backups_image
- True
-
-
- True
- True
- 4
-
-
-
-
- False
- True
- 1
-
-
-
-
- False
+ True
True
2
diff --git a/app/ui/settings_dialog.glade b/app/ui/settings_dialog.glade
index 000211fa..513b9305 100644
--- a/app/ui/settings_dialog.glade
+++ b/app/ui/settings_dialog.glade
@@ -2676,7 +2676,7 @@ Author: Dmitriy Yefremov
5
- True
+ False
False
diff --git a/app/ui/settings_dialog.py b/app/ui/settings_dialog.py
index f4ec9a9f..07dae1f4 100644
--- a/app/ui/settings_dialog.py
+++ b/app/ui/settings_dialog.py
@@ -358,7 +358,6 @@ class SettingsDialog:
self._ext_settings.list_font = self._list_font_button.get_font()
if IS_WIN:
- self._ext_settings.dark_mode = self._dark_mode_switch.get_active()
self._ext_settings.alternate_layout = self._layout_switch.get_active()
self._ext_settings.is_themes_support = self._themes_support_switch.get_active()
self._ext_settings.theme = self._theme_combo_box.get_active_id()
@@ -796,7 +795,6 @@ class SettingsDialog:
@run_idle
def init_themes(self):
- self._dark_mode_switch.set_active(self._ext_settings.dark_mode)
t_support = self._ext_settings.is_themes_support
self._themes_support_switch.set_active(t_support)
if t_support: