Files
DemonEditor/app/eparser/ecommons.py
2022-07-03 12:44:03 +03:00

273 lines
8.7 KiB
Python

# -*- coding: utf-8 -*-
#
# The MIT License (MIT)
#
# Copyright (c) 2018-2022 Dmitriy Yefremov
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# Author: Dmitriy Yefremov
#
""" Common elements module. """
from collections import namedtuple
from enum import Enum
from app.commons import log
Service = namedtuple("Service", ["flags_cas", "transponder_type", "coded", "service", "locked", "hide", "package",
"service_type", "picon", "picon_id", "ssid", "freq", "rate", "pol", "fec",
"system", "pos", "data_id", "fav_id", "transponder"])
# ***************** Bouquets *******************#
class BqServiceType(Enum):
DEFAULT = "DEFAULT"
IPTV = "IPTV"
MARKER = "MARKER" # 64
SPACE = "SPACE" # 832 [hidden marker]
ALT = "ALT" # Service with alternatives
BOUQUET = "BOUQUET" # Sub bouquet.
@classmethod
def _missing_(cls, value):
return cls.DEFAULT
Bouquet = namedtuple("Bouquet", ["name", "type", "services", "locked", "hidden", "file"])
Bouquet.__new__.__defaults__ = (None, BqServiceType.DEFAULT, [], None, None, None) # For Python3 < 3.7
Bouquets = namedtuple("Bouquets", ["name", "type", "bouquets"])
BouquetService = namedtuple("BouquetService", ["name", "type", "data", "num"])
# *************** *.xml [Satellites, Terrestrial, Cable] ***************** #
Satellite = namedtuple("Satellite", ["name", "flags", "position", "transponders"])
Terrestrial = namedtuple("Terrestrial", ["name", "flags", "countrycode", "transponders"])
Cable = namedtuple("Cable", ["name", "flags", "satfeed", "countrycode", "transponders"])
Transponder = namedtuple("Transponder", ["frequency", "symbol_rate", "polarization", "fec_inner", "system",
"modulation", "pls_mode", "pls_code", "is_id", "t2mi_plp_id"])
TerTransponder = namedtuple("TerTransponder", ["centre_frequency", "system", "bandwidth", "constellation",
"code_rate_hp", "code_rate_lp", "guard_interval", "transmission_mode",
"hierarchy_information", "inversion", "plp_id"])
CableTransponder = namedtuple("CableTransponder", ["frequency", "symbol_rate", "fec_inner", "modulation"])
class TrType(Enum):
""" Transponders type """
Satellite = "s"
Terrestrial = "t"
Cable = "c"
ATSC = "a"
class BqType(Enum):
""" Bouquet type. """
BOUQUET = "bouquet"
TV = "tv"
RADIO = "radio"
WEBTV = "webtv"
MARKER = "marker"
@classmethod
def _missing_(cls, value):
return cls.TV
class Flag(Enum):
""" Service flags
K - last bit (1)
H - second from end (10)
P - third (100)
N - sixth (100000)
"""
KEEP = 1 # Do not automatically update the services parameters.
HIDE = 2
PIDS = 4 # Always use the cached instead of current pids.
LOCK = 8
NEW = 40 # Marked as new at the last scan
@staticmethod
def is_hide(value: int):
return value & 1 << 1
@staticmethod
def is_keep(value: int):
return value & 1 << 0
@staticmethod
def is_pids(value: int):
return value & 1 << 2
@staticmethod
def is_new(value: int):
return value & 1 << 5
@staticmethod
def parse(value: str) -> int:
""" Returns an int representation of the flag value.
The flag value is usually represented by the number [int],
but can also be appear in hex format.
"""
if len(value) < 3:
return 0
value = value[2:]
if value.isdigit():
return int(value)
return int(value, 16)
class Pids(Enum):
VIDEO = "c:00"
AUDIO = "c:01"
TELETEXT = "c:02"
PCR = "c:03"
AC3 = "c:04"
VIDEO_TYPE = "c:05"
AUDIO_CHANNEL = "c:06"
BIT_STREAM_DELAY = "c:07" # in ms
PCM_DELAY = "c:08" # in ms
SUBTITLE = "c:09"
class Inversion(Enum):
Off = "0"
On = "1"
Auto = "2"
@classmethod
def _missing_(cls, value):
return cls.Auto
class Pilot(Enum):
Off = "0"
On = "1"
Auto = "2"
@classmethod
def _missing_(cls, value):
return cls.Auto
class SystemCable(Enum):
""" System of cable service """
ANNEX_A = "0"
ANNEX_C = "1"
ROLL_OFF = {"0": "35%", "1": "25%", "2": "20%", "3": "Auto"}
POLARIZATION = {"0": "H", "1": "V", "2": "L", "3": "R"}
PLS_MODE = {"0": "Root", "1": "Gold", "2": "Combo"}
FEC = {"0": "Auto", "1": "1/2", "2": "2/3", "3": "3/4", "4": "5/6", "5": "7/8", "6": "8/9", "7": "3/5", "8": "4/5",
"9": "9/10", "10": "1/2", "11": "2/3", "12": "3/4", "13": "5/6", "14": "7/8", "15": "8/9", "16": "3/5",
"17": "4/5", "18": "9/10", "19": "1/2", "20": "2/3", "21": "3/4", "22": "5/6", "23": "7/8", "24": "8/9",
"25": "3/5", "26": "4/5", "27": "9/10", "28": "Auto"}
FEC_DEFAULT = {"0": "Auto", "1": "1/2", "2": "2/3", "3": "3/4", "4": "5/6", "5": "7/8", "6": "8/9", "7": "3/5",
"8": "4/5", "9": "9/10", "10": "6/7", "15": "None"}
SYSTEM = {"0": "DVB-S", "1": "DVB-S2"}
MODULATION = {"0": "Auto", "1": "QPSK", "2": "8PSK", "4": "16APSK", "5": "32APSK"}
SERVICE_TYPE = {"-2": "Data", "1": "TV", "2": "Radio", "3": "Data", "10": "Radio", "22": "TV (H264)",
"25": "TV (HD)", "31": "TV (UHD)"}
# Terrestrial
BANDWIDTH = {"0": "8MHz", "1": "7MHz", "2": "6MHz", "3": "Auto", "4": "5MHz", "5": "1/712MHz", "6": "10MHz"}
CONSTELLATION = {"0": "QPSK", "1": "16-QAM", "2": "64-QAM", "3": "Auto"}
T_MODULATION = {"0": "QPSK", "1": "QAM16", "2": "QAM64", "3": "Auto", "4": "QAM256"}
TRANSMISSION_MODE = {"0": "2k", "1": "8k", "2": "Auto", "3": "4k", "4": "1k", "5": "16k", "6": "32k"}
GUARD_INTERVAL = {"0": "1/32", "1": "1/16", "2": "1/8", "3": "1/4", "4": "Auto", "5": "1/128", "6": "19/128",
"7": "19/256"}
HIERARCHY = {"0": "None", "1": "1", "2": "2", "3": "4", "4": "Auto"}
T_FEC = {"0": "1/2", "1": "2/3", "2": "3/4", "3": "5/6", "4": "7/8", "5": "Auto", "6": "6/7", "7": "8/9"}
T_SYSTEM = {"0": "DVB-T", "1": "DVB-T2", "-1": "DVB-T/T2"}
# Cable
C_MODULATION = {"0": "QPSK", "1": "QAM16", "2": "QAM32", "3": "QAM64", "4": "QAM128", "5": "QAM256", "6": "Auto"}
# ATSC
A_MODULATION = {"0": "Auto", "1": "QAM16", "2": "QAM32", "3": "QAM64", "4": "QAM128", "5": "QAM256", "6": "8VSB",
"7": "16VSB"}
# CAS
CAS = {"C:26": "BISS", "C:0B": "Conax", "C:06": "Irdeto", "C:18": "Nagravision", "C:05": "Viaccess", "C:01": "SECA",
"C:0E": "PowerVu", "C:4A": "DRE-Crypt", "C:7B": "DRE-Crypt", "C:56": "Verimatrix", "C:09": "VideoGuard"}
# 'on' attribute 0070(hex) = 112(int) = ONID(ONID-TID on www.lyngsat.com)
PROVIDER = {112: "HTB+", 253: "Tricolor TV"}
# ************* subsidiary functions ****************
def get_key_by_value(dc: dict, value):
""" Returns key from dict by value """
for k, v in dc.items():
if v == value:
return k
def get_value_by_name(en, name):
""" Returns value by name from enums """
for n in en:
if n.name == name:
return n.value
def is_transponder_valid(tr: Transponder):
""" Checks transponder validity. """
try:
int(tr.frequency)
int(tr.symbol_rate)
tr.pls_mode is None or int(tr.pls_mode)
tr.pls_code is None or int(tr.pls_code)
tr.is_id is None or int(tr.is_id)
tr.t2mi_plp_id is None or int(tr.t2mi_plp_id)
except (TypeError, ValueError) as e:
log(f"Transponder validation error: {e}\n{tr}")
return False
if tr.polarization not in POLARIZATION:
return False
if tr.fec_inner not in FEC:
return False
if tr.system not in SYSTEM:
return False
if tr.modulation not in MODULATION:
return False
return True