mirror of
https://github.com/DYefremov/DemonEditor.git
synced 2026-07-20 02:00:19 +02:00
add basic streamrelay support (#199)
* marking services used with streamrelay in the fav list with an additional icon
This commit is contained in:
@@ -48,7 +48,7 @@ from app.settings import SettingsType
|
||||
BQ_FILES_LIST = ("tv", "radio", # Enigma2.
|
||||
"services.xml", "myservices.xml", "bouquets.xml", "ubouquets.xml") # Neutrino.
|
||||
|
||||
DATA_FILES_LIST = ("lamedb", "lamedb5", "blacklist", "whitelist",)
|
||||
DATA_FILES_LIST = ("lamedb", "lamedb5", "blacklist", "whitelist", "whitelist_streamrelay")
|
||||
|
||||
STC_XML_FILE = ("satellites.xml", "terrestrial.xml", "cables.xml")
|
||||
WEB_TV_XML_FILE = ("webtv.xml", "webtv_usr.xml")
|
||||
|
||||
76
app/eparser/enigma/streamrelay.py
Normal file
76
app/eparser/enigma/streamrelay.py
Normal file
@@ -0,0 +1,76 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2024 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
|
||||
#
|
||||
|
||||
|
||||
""" Additional module to use stream relay functionality.
|
||||
|
||||
Reads/Writes 'whitelist_streamrelay' file.
|
||||
"""
|
||||
import os.path
|
||||
from contextlib import suppress
|
||||
|
||||
from app.commons import log
|
||||
|
||||
_FILE_NAME = "whitelist_streamrelay"
|
||||
|
||||
|
||||
class StreamRelay(dict):
|
||||
""" Class to hold/process service references used by a stream relay. """
|
||||
|
||||
def refresh(self, path):
|
||||
self.clear()
|
||||
f_path = f"{path}{_FILE_NAME}"
|
||||
if os.path.isfile(f_path):
|
||||
log("Updating stream relay cache...")
|
||||
with suppress(FileNotFoundError):
|
||||
with open(f"{path}{_FILE_NAME}", "r", encoding="utf-8") as file:
|
||||
refs = filter(None, (x.rstrip(":\n") for x in file.readlines()))
|
||||
self.update(self.get_ref_data(ref) for ref in refs)
|
||||
|
||||
def get_ref_data(self, ref):
|
||||
""" Returns tuple from FAV ID and ref or ref and None for comments. """
|
||||
data = ref.split(":")
|
||||
if len(data) == 10:
|
||||
return f"{data[3]}:{data[4]}:{data[5]}:{data[6]}", ref
|
||||
return ref, None
|
||||
|
||||
def save(self, path):
|
||||
""" Saves current refs to a file.
|
||||
|
||||
If no refs is present, delites current relay file.
|
||||
"""
|
||||
f_name = f"{path}{_FILE_NAME}_"
|
||||
if len(self):
|
||||
with open(f_name, "w", encoding="utf-8") as file:
|
||||
file.writelines([f"{v if v else k}{':' if v else ''}\n\n" for k, v in self.items()])
|
||||
else:
|
||||
if os.path.exists(f_name):
|
||||
os.remove(f_name)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pass
|
||||
@@ -43,7 +43,9 @@ from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, KeyboardKey, MOD_MASK, Heade
|
||||
|
||||
KEEP_DATA = {"satellites.xml",
|
||||
"terrestrial.xml",
|
||||
"cables.xml"}
|
||||
"cables.xml",
|
||||
"whitelist",
|
||||
"whitelist_streamrelay"}
|
||||
|
||||
|
||||
class RestoreType(Enum):
|
||||
@@ -264,7 +266,7 @@ def restore_data(src, dst):
|
||||
|
||||
def clear_data_path(path):
|
||||
""" Clearing data at the specified path excluding *.xml file. """
|
||||
for file in filter(lambda f: not f.endswith(".xml") and os.path.isfile(os.path.join(path, f)), os.listdir(path)):
|
||||
for file in filter(lambda f: f not in KEEP_DATA and os.path.isfile(os.path.join(path, f)), os.listdir(path)):
|
||||
os.remove(os.path.join(path, file))
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2018-2023 Dmitriy Yefremov
|
||||
# Copyright (c) 2018-2024 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
|
||||
@@ -45,7 +45,7 @@ from app.connections import UtfFTP
|
||||
from app.settings import IS_LINUX, IS_DARWIN, IS_WIN, SEP, USE_HEADER_BAR
|
||||
from app.ui.dialogs import show_dialog, DialogType, get_builder, translate
|
||||
from app.ui.main_helper import on_popup_menu
|
||||
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, KeyboardKey, MOD_MASK, Page
|
||||
from .uicommons import Gtk, Gdk, UI_RESOURCES_PATH, KeyboardKey, MOD_MASK, Page, LINK_ICON, FOLDER_ICON
|
||||
|
||||
File = namedtuple("File", ["icon", "name", "size", "date", "attr", "extra"])
|
||||
|
||||
@@ -296,12 +296,6 @@ class FtpClientBox(Gtk.HBox):
|
||||
# Force Ctrl
|
||||
self._ftp_view.connect("key-press-event", self._app.force_ctrl)
|
||||
self._file_view.connect("key-press-event", self._app.force_ctrl)
|
||||
# Icons
|
||||
theme = Gtk.IconTheme.get_default()
|
||||
folder_icon = "folder-symbolic" if settings.is_darwin else "folder"
|
||||
self._folder_icon = theme.load_icon(folder_icon, 16, 0) if theme.lookup_icon(folder_icon, 16, 0) else None
|
||||
self._link_icon = theme.load_icon("emblem-symbolic-link", 16, 0) if theme.lookup_icon("emblem-symbolic-link",
|
||||
16, 0) else None
|
||||
# Initialization
|
||||
self.init_drag_and_drop()
|
||||
self.init_ftp()
|
||||
@@ -377,10 +371,10 @@ class FtpClientBox(Gtk.HBox):
|
||||
icon = None
|
||||
if is_dir:
|
||||
r_size = self.FOLDER
|
||||
icon = self._folder_icon
|
||||
icon = FOLDER_ICON
|
||||
elif p.is_symlink():
|
||||
r_size = self.LINK
|
||||
icon = self._link_icon
|
||||
icon = LINK_ICON
|
||||
else:
|
||||
r_size = get_size_from_bytes(size)
|
||||
|
||||
@@ -401,10 +395,10 @@ class FtpClientBox(Gtk.HBox):
|
||||
icon = None
|
||||
if is_dir:
|
||||
r_size = self.FOLDER
|
||||
icon = self._folder_icon
|
||||
icon = FOLDER_ICON
|
||||
elif is_link:
|
||||
r_size = self.LINK
|
||||
icon = self._link_icon
|
||||
icon = LINK_ICON
|
||||
else:
|
||||
r_size = get_size_from_bytes(size)
|
||||
|
||||
@@ -675,7 +669,7 @@ class FtpClientBox(Gtk.HBox):
|
||||
log(e)
|
||||
self._app.show_error_message(str(e))
|
||||
else:
|
||||
itr = self._file_model.append(File(self._folder_icon, path.name, self.FOLDER, "", str(path.resolve()), "0"))
|
||||
itr = self._file_model.append(File(FOLDER_ICON, path.name, self.FOLDER, "", str(path.resolve()), "0"))
|
||||
renderer.set_property("editable", True)
|
||||
self._file_view.set_cursor(self._file_model.get_path(itr), self._file_view.get_column(0), True)
|
||||
|
||||
@@ -695,7 +689,7 @@ class FtpClientBox(Gtk.HBox):
|
||||
log(e)
|
||||
else:
|
||||
if resp == f"{cur_path}/{name}":
|
||||
itr = self._ftp_model.append(File(self._folder_icon, name, self.FOLDER, "", "drwxr-xr-x", "0"))
|
||||
itr = self._ftp_model.append(File(FOLDER_ICON, name, self.FOLDER, "", "drwxr-xr-x", "0"))
|
||||
renderer.set_property("editable", True)
|
||||
self._ftp_view.set_cursor(self._ftp_model.get_path(itr), self._ftp_view.get_column(0), True)
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ from app.eparser import get_blacklist, write_blacklist, write_bouquet
|
||||
from app.eparser import get_services, get_bouquets, write_bouquets, write_services, Bouquets, Bouquet, Service
|
||||
from app.eparser.ecommons import CAS, Flag, BouquetService
|
||||
from app.eparser.enigma.bouquets import BqServiceType
|
||||
from app.eparser.enigma.streamrelay import StreamRelay
|
||||
from app.eparser.iptv import export_to_m3u, StreamType
|
||||
from app.eparser.neutrino.bouquets import BqType
|
||||
from app.settings import (SettingsType, Settings, SettingsException, SettingsReadException, IS_DARWIN, IS_LINUX,
|
||||
@@ -70,7 +71,7 @@ from .search import SearchProvider
|
||||
from .service_details_dialog import ServiceDetailsDialog, Action
|
||||
from .settings_dialog import SettingsDialog
|
||||
from .uicommons import (Gtk, Gdk, UI_RESOURCES_PATH, LOCKED_ICON, HIDE_ICON, IPTV_ICON, MOVE_KEYS, KeyboardKey, Column,
|
||||
MOD_MASK, APP_FONT, Page, HeaderBar)
|
||||
MOD_MASK, APP_FONT, Page, HeaderBar, LINK_ICON)
|
||||
from .xml.dialogs import ServicesUpdateDialog
|
||||
from .xml.edit import SatellitesTool
|
||||
|
||||
@@ -255,6 +256,7 @@ class Application(Gtk.Application):
|
||||
# For bouquets with different names of services in bouquet and main list
|
||||
self._extra_bouquets = {}
|
||||
self._blacklist = set()
|
||||
self._stream_relay = StreamRelay()
|
||||
self._current_bq_name = None
|
||||
self._bq_selected = "" # Current selected bouquet
|
||||
self._select_enabled = True # Multiple selection
|
||||
@@ -2330,6 +2332,7 @@ class Application(Gtk.Application):
|
||||
|
||||
prf = self._s_type
|
||||
black_list = get_blacklist(data_path)
|
||||
self._stream_relay.refresh(data_path)
|
||||
bouquets = get_bouquets(data_path, prf)
|
||||
yield True
|
||||
services = get_services(data_path, prf, self.get_format_version() if prf is SettingsType.ENIGMA_2 else 0)
|
||||
@@ -2777,13 +2780,14 @@ class Application(Gtk.Application):
|
||||
ex_srv_name = ex_services.get(srv_id)
|
||||
if srv:
|
||||
background = self._EXTRA_COLOR if self._use_colors and ex_srv_name else None
|
||||
coded = LINK_ICON if srv_id in self._stream_relay else srv.coded
|
||||
|
||||
srv_type = srv.service_type
|
||||
is_marker = srv_type in self.MARKER_TYPES
|
||||
if not is_marker:
|
||||
num += 1
|
||||
|
||||
self._fav_model.append((0 if is_marker else num, srv.coded, ex_srv_name if ex_srv_name else srv.service,
|
||||
self._fav_model.append((0 if is_marker else num, coded, ex_srv_name if ex_srv_name else srv.service,
|
||||
srv.locked, srv.hide, srv_type, srv.pos, srv.fav_id,
|
||||
None, None, background))
|
||||
|
||||
|
||||
@@ -119,6 +119,8 @@ LOCKED_ICON = get_icon("changes-prevent-symbolic", 16, _IMAGE_MISSING)
|
||||
HIDE_ICON = get_icon("go-jump", 16, _IMAGE_MISSING)
|
||||
TV_ICON = get_icon("tv-symbolic", 16, _IMAGE_MISSING)
|
||||
IPTV_ICON = get_icon("emblem-shared", 16, _IMAGE_MISSING)
|
||||
LINK_ICON = get_icon("emblem-symbolic-link", 16, _IMAGE_MISSING)
|
||||
FOLDER_ICON = get_icon("folder-symbolic" if IS_DARWIN else "folder", 16, _IMAGE_MISSING)
|
||||
EPG_ICON = get_icon("gtk-index", 16, _IMAGE_MISSING)
|
||||
DEFAULT_ICON = get_icon("emblem-default", 16, get_icon("emblem-default-symbolic", 16, _IMAGE_MISSING))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user