diff --git a/.gitignore b/.gitignore index 68bc17f..b24d71e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,160 +1,50 @@ -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore -# Distribution / packaging -.Python -build/ -develop-eggs/ +# Node artifact files +node_modules/ dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -share/python-wheels/ -*.egg-info/ -.installed.cfg -*.egg -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec -# Installer logs -pip-log.txt -pip-delete-this-directory.txt +# Compiled Java class files +*.class -# Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -*.py,cover -.hypothesis/ -.pytest_cache/ -cover/ - -# Translations -*.mo -*.pot +# Compiled Python bytecode +*.py[cod] -# Django stuff: +# Log files *.log -local_settings.py -db.sqlite3 -db.sqlite3-journal -# Flask stuff: -instance/ -.webassets-cache +# Package files +*.jar -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -.pybuilder/ +# Maven target/ +dist/ -# Jupyter Notebook -.ipynb_checkpoints - -# IPython -profile_default/ -ipython_config.py - -# pyenv -# For a library or package, you might want to ignore these files since the code is -# intended to run in multiple environments; otherwise, check them in: -# .python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# poetry -# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control -#poetry.lock - -# pdm -# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. -#pdm.lock -# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it -# in version control. -# https://pdm.fming.dev/#use-with-ide -.pdm.toml - -# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm -__pypackages__/ - -# Celery stuff -celerybeat-schedule -celerybeat.pid - -# SageMath parsed files -*.sage.py - -# Environments -.env -.venv -env/ -venv/ -ENV/ -env.bak/ -venv.bak/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject +# JetBrains IDE +.idea/ -# mkdocs documentation -/site +# Unit test reports +TEST*.xml -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json +# Generated by MacOS +.DS_Store -# Pyre type checker -.pyre/ +# Generated by Windows +Thumbs.db -# pytype static type analyzer -.pytype/ +# Applications +*.app +*.exe +*.war -# Cython debug symbols -cython_debug/ +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv -# PyCharm -# JetBrains specific template is maintained in a separate JetBrains.gitignore that can -# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore -# and can be added to the global gitignore or merged into this file. For a more nuclear -# option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ diff --git a/.pylintrc b/.pylintrc new file mode 100644 index 0000000..6d571a9 --- /dev/null +++ b/.pylintrc @@ -0,0 +1,548 @@ +[MASTER] + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code +extension-pkg-whitelist= + +# Add files or directories to the blacklist. They should be base names, not +# paths. +ignore=CVS + +# Add files or directories matching the regex patterns to the blacklist. The +# regex matches against base names, not paths. +ignore-patterns= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Use multiple processes to speed up Pylint. +jobs=1 + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins= + +# Pickle collected data for later comparisons. +persistent=yes + +# Specify a configuration file. +#rcfile= + +# When enabled, pylint would attempt to guess common misconfiguration and emit +# user-friendly hints instead of false-positive error messages +suggestion-mode=yes + +# Allow loading of arbitrary C extensions. Extensions are imported into the +# active Python interpreter and may run arbitrary code. +unsafe-load-any-extension=no + + +[MESSAGES CONTROL] + +# Only show warnings with the listed confidence levels. Leave empty to show +# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED +confidence= + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once).You can also use "--disable=all" to +# disable everything first and then reenable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use"--disable=all --enable=classes +# --disable=W" +disable=print-statement, + parameter-unpacking, + unpacking-in-except, + old-raise-syntax, + backtick, + long-suffix, + old-ne-operator, + old-octal-literal, + import-star-module-level, + non-ascii-bytes-literal, + raw-checker-failed, + bad-inline-option, + locally-disabled, + locally-enabled, + file-ignored, + suppressed-message, + useless-suppression, + deprecated-pragma, + apply-builtin, + basestring-builtin, + buffer-builtin, + cmp-builtin, + coerce-builtin, + execfile-builtin, + file-builtin, + long-builtin, + raw_input-builtin, + reduce-builtin, + standarderror-builtin, + unicode-builtin, + xrange-builtin, + coerce-method, + delslice-method, + getslice-method, + setslice-method, + no-absolute-import, + old-division, + dict-iter-method, + dict-view-method, + next-method-called, + metaclass-assignment, + indexing-exception, + raising-string, + reload-builtin, + oct-method, + hex-method, + nonzero-method, + cmp-method, + input-builtin, + round-builtin, + intern-builtin, + unichr-builtin, + map-builtin-not-iterating, + zip-builtin-not-iterating, + range-builtin-not-iterating, + filter-builtin-not-iterating, + using-cmp-argument, + eq-without-hash, + div-method, + idiv-method, + rdiv-method, + exception-message-attribute, + invalid-str-codec, + sys-max-int, + bad-python3-import, + deprecated-string-function, + deprecated-str-translate-call, + deprecated-itertools-function, + deprecated-types-field, + next-method-defined, + dict-items-not-iterating, + dict-keys-not-iterating, + dict-values-not-iterating, + + R0201, R0205, + C0103, C0114, C0326, C0330, + W0122, W0123, W0201, W0311, W0312, W0603, W0703, W1505, + E0401, E0611, E1101 + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time (only on the command line, not in the configuration file where +# it should appear only once). See also the "--disable" option for examples. +enable=c-extension-no-member + + +[REPORTS] + +# Python expression which should return a note less than 10 (10 is the highest +# note). You have access to the variables errors warning, statement which +# respectively contain the number of errors / warnings messages and the total +# number of statements analyzed. This is used by the global evaluation report +# (RP0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Template used to display messages. This is a python new-style format string +# used to format the message information. See doc for all details +msg-template='{msg_id}:{line:3d},{column}: {obj}: {msg}' + +# Set the output format. Available formats are text, parseable, colorized, json +# and msvs (visual studio).You can also give a reporter class, eg +# mypackage.mymodule.MyReporterClass. +output-format=text + +# Tells whether to display a full report or only the messages +reports=no + +# Activate the evaluation score. +score=yes + + +[REFACTORING] + +# Maximum number of nested blocks for function / method body +max-nested-blocks=10 + +# Complete name of functions that never returns. When checking for +# inconsistent-return-statements if a never returning function is called then +# it will be considered as an explicit return statement and no message will be +# printed. +never-returning-functions=optparse.Values,sys.exit + + +[SPELLING] + +# Limits count of emitted suggestions for spelling mistakes +max-spelling-suggestions=4 + +# Spelling dictionary name. Available dictionaries: none. To make it working +# install python-enchant package. +spelling-dict= + +# List of comma separated words that should not be checked. +spelling-ignore-words= + +# A path to a file that contains private dictionary; one word per line. +spelling-private-dict-file= + +# Tells whether to store unknown words to indicated private dictionary in +# --spelling-private-dict-file option instead of raising a message. +spelling-store-unknown-words=no + + +[SIMILARITIES] + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + +# Ignore imports when computing similarities. +ignore-imports=no + +# Minimum lines number of a similarity. +min-similarity-lines=50 + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME, + XXX, + TODO + + +[FORMAT] + +# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. +expected-line-ending-format= + +# Regexp for a line that is allowed to be longer than the limit. +ignore-long-lines=^\s*(# )??$ + +# Number of spaces of indent required inside a hanging or continued line. +indent-after-paren=4 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + +# Maximum number of characters on a single line. +max-line-length=300 + +# Maximum number of lines in a module +max-module-lines=1000 + +# List of optional constructs for which whitespace checking is disabled. `dict- +# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. +# `trailing-comma` allows a space between comma and closing bracket: (a, ). +# `empty-line` allows space-only lines. +no-space-check=trailing-comma, + dict-separator + +# Allow the body of a class to be on the same line as the declaration if body +# contains single statement. +single-line-class-stmt=no + +# Allow the body of an if to be on the same line as the test if there is no +# else. +single-line-if-stmt=no + + +[LOGGING] + +# Logging modules to check that the string format arguments are in logging +# function parameter format +logging-modules=logging + + +[VARIABLES] + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid to define new builtins when possible. +additional-builtins= + +# Tells whether unused global variables should be treated as a violation. +allow-global-unused-variables=yes + +# List of strings which can identify a callback function by name. A callback +# name must start or end with one of those strings. +callbacks=cb_, + _cb + +# A regular expression matching the name of dummy variables (i.e. expectedly +# not used). +#dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ +dummy-variables-rgx=(_+[a-zA-Z0-9_]*?$)|dummy + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore +ignored-argument-names=_.*|^ignored_|^unused_ + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# List of qualified module names which can have objects that can redefine +# builtins. +redefining-builtins-modules=six.moves,past.builtins,future.builtins + + +[TYPECHECK] + +# List of decorators that produce context managers, such as +# contextlib.contextmanager. Add to this list to register other decorators that +# produce valid context managers. +contextmanager-decorators=contextlib.contextmanager + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E1101 when accessed. Python regular +# expressions are accepted. +generated-members= + +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# This flag controls whether pylint should warn about no-member and similar +# checks whenever an opaque object is returned when inferring. The inference +# can return multiple potential results while evaluating a Python object, but +# some branches might not be evaluated, which results in partial inference. In +# that case, it might be useful to still emit no-member and other checks for +# the rest of the inferred objects. +ignore-on-opaque-inference=yes + +# List of class names for which member attributes should not be checked (useful +# for classes with dynamically set attributes). This supports the use of +# qualified names. +ignored-classes=optparse.Values,thread._local,_thread._local + +# List of module names for which member attributes should not be checked +# (useful for modules/projects where namespaces are manipulated during runtime +# and thus existing member attributes cannot be deduced by static analysis. It +# supports qualified module names, as well as Unix pattern matching. +ignored-modules= + +# Show a hint with possible names when a member name was not found. The aspect +# of finding the hint is based on edit distance. +missing-member-hint=yes + +# The minimum edit distance a name should have in order to be considered a +# similar match for a missing member name. +missing-member-hint-distance=1 + +# The total number of similar names that should be taken in consideration when +# showing a hint for a missing member. +missing-member-max-choices=1 + + +[BASIC] + +# Naming style matching correct argument names +argument-naming-style=snake_case + +# Regular expression matching correct argument names. Overrides argument- +# naming-style +#argument-rgx= + +# Naming style matching correct attribute names +attr-naming-style=snake_case + +# Regular expression matching correct attribute names. Overrides attr-naming- +# style +#attr-rgx= + +# Bad variable names which should always be refused, separated by a comma +bad-names=foo, + bar, + baz, + toto, + tutu, + tata + +# Naming style matching correct class attribute names +class-attribute-naming-style=any + +# Regular expression matching correct class attribute names. Overrides class- +# attribute-naming-style +#class-attribute-rgx= + +# Naming style matching correct class names +class-naming-style=PascalCase + +# Regular expression matching correct class names. Overrides class-naming-style +#class-rgx= + +# Naming style matching correct constant names +const-naming-style=UPPER_CASE + +# Regular expression matching correct constant names. Overrides const-naming- +# style +#const-rgx= + +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length=1000 + +# Naming style matching correct function names +function-naming-style=camelCase + +# Regular expression matching correct function names. Overrides function- +# naming-style +#function-rgx= + +# Good variable names which should always be accepted, separated by a comma +good-names=i, + j, + k, + ex, + Run, + _ + +# Include a hint for the correct naming format with invalid-name +include-naming-hint=no + +# Naming style matching correct inline iteration names +inlinevar-naming-style=any + +# Regular expression matching correct inline iteration names. Overrides +# inlinevar-naming-style +#inlinevar-rgx= + +# Naming style matching correct method names +method-naming-style=camelCase + +# Regular expression matching correct method names. Overrides method-naming- +# style +#method-rgx= + +# Naming style matching correct module names +module-naming-style=any + +# Regular expression matching correct module names. Overrides module-naming- +# style +#module-rgx= + +# Colon-delimited sets of names that determine each other's naming style when +# the name regexes allow several styles. +name-group= + +# Regular expression which should only match function or class names that do +# not require a docstring. +no-docstring-rgx=^_ + +# List of decorators that produce properties, such as abc.abstractproperty. Add +# to this list to register other decorators that produce valid properties. +property-classes=abc.abstractproperty + +# Naming style matching correct variable names +variable-naming-style=snake_case + +# Regular expression matching correct variable names. Overrides variable- +# naming-style +#variable-rgx= + + +[IMPORTS] + +# Allow wildcard imports from modules that define __all__. +allow-wildcard-with-all=no + +# Analyse import fallback blocks. This can be used to support both Python 2 and +# 3 compatible code, which means that the block might have code that exists +# only in one or another interpreter, leading to false positives when analysed. +analyse-fallback-blocks=no + +# Deprecated modules which should not be used, separated by a comma +deprecated-modules=regsub, + TERMIOS, + Bastion, + rexec + +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled) +ext-import-graph= + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled) +import-graph= + +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled) +int-import-graph= + +# Force import order to recognize a module as part of the standard +# compatibility libraries. +known-standard-library= + +# Force import order to recognize a module as part of a third party library. +known-third-party=enchant + + +[DESIGN] + +# Maximum number of arguments for function / method +max-args=100 + +# Maximum number of attributes for a class (see R0902). +max-attributes=100 + +# Maximum number of boolean expressions in a if statement +max-bool-expr=100 + +# Maximum number of branch for function / method body +max-branches=100 + +# Maximum number of locals for function / method body +max-locals=100 + +# Maximum number of parents for a class (see R0901). +max-parents=100 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=100 + +# Maximum number of return / yield for function / method body +max-returns=100 + +# Maximum number of statements in function / method body +max-statements=200 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=0 + + +[CLASSES] + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__, + __new__, + setUp + +# List of member names, which should be excluded from the protected access +# warning. +exclude-protected=_asdict, + _fields, + _replace, + _source, + _make + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg=mcs + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when being caught. Defaults to +# "Exception" +overgeneral-exceptions=Exception diff --git a/CONTROL/control b/CONTROL/control new file mode 100644 index 0000000..7797ca7 --- /dev/null +++ b/CONTROL/control @@ -0,0 +1,6 @@ +Description: TVMagazineCockpit +Maintainer: dream-alpha +Package: enigma2-plugin-extensions-tvmagazinecockpit +Version: 1.7.8 +Architecture: all +Depends: enigma2-plugin-skincomponents-extmultilistselection diff --git a/CONTROL/postinst b/CONTROL/postinst new file mode 100755 index 0000000..2882138 --- /dev/null +++ b/CONTROL/postinst @@ -0,0 +1,4 @@ +#!/bin/sh +echo "Plugin successfully installed." +echo "Please restart DreamOS now!" +exit 0 diff --git a/CONTROL/postrm b/CONTROL/postrm new file mode 100755 index 0000000..ac69089 --- /dev/null +++ b/CONTROL/postrm @@ -0,0 +1,8 @@ +#!/bin/sh +if [ "$1" = "remove" ]; then + rm -rf /usr/lib/enigma2/python/Plugins/Extensions/TVMagazineCockpit > /dev/null 2>&1 + echo "Plugin removed successfully." +else + find /usr/lib/enigma2/python/Plugins/Extensions/TVMagazineCockpit -type f -name "*.pyo" -exec rm -f {} \; > /dev/null 2>&1 +fi +exit 0 diff --git a/CONTROL/preinst b/CONTROL/preinst new file mode 100755 index 0000000..039e4d0 --- /dev/null +++ b/CONTROL/preinst @@ -0,0 +1,2 @@ +#!/bin/sh +exit 0 diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..fa59349 --- /dev/null +++ b/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = po src channels logos diff --git a/README.md b/README.md new file mode 100644 index 0000000..232cfb7 --- /dev/null +++ b/README.md @@ -0,0 +1,27 @@ +[![Codacy Badge](https://app.codacy.com/project/badge/Grade/4c6ef88b6fa0459090e9dc786aee6343)](https://app.codacy.com/gh/dream-alpha/TVMagazineCockpit/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) +[![Gemfury](https://badge.fury.io/fp/gemfury.svg)](https://gemfury.com/f/partner) + +# TVMagazineCockpit (TVC) +![Screenshot](tvc1.png) + +![Screenshot](tvc2.png) + +DreamOS plugin to browse TV magazine(s) + +## Features +- Displays event data +- Supports bouquets (favorites, sky, etc.) +- Integrates zap and add timer functions +- Allows mediathek downloads (if plugin MediathekCockpit is installed) +- Provides additional TMDB event information (if plugin TMDBCockpit is installed) +- Uses JSON interface to fetch data from content provider (instead of html page parsing) +- Supports HD, FHD, and WQHD skin resolutions. + +## Languages +- english +- german + +## Links +- Installation: https://dream-alpha.github.io/TVMagazineCockpit +- Support: https://github.com/dream-alpha/TVMagazineCockpit/discussions +- Package feed: https://gemfury.com/dream-alpha diff --git a/channels/Makefile.am b/channels/Makefile.am new file mode 100644 index 0000000..3b7d40b --- /dev/null +++ b/channels/Makefile.am @@ -0,0 +1,2 @@ +installdir = $(libdir)/enigma2/python/Plugins/Extensions/TVMagazineCockpit +install_DATA = *.json diff --git a/channels/tvspielfilm_channel_dict_default.json b/channels/tvspielfilm_channel_dict_default.json new file mode 100644 index 0000000..3da025e --- /dev/null +++ b/channels/tvspielfilm_channel_dict_default.json @@ -0,0 +1,3716 @@ +{ + "PULS4_uhd": { + "tname": "PULS 4", + "ename": "", + "id": "PULS4", + "service": "" + }, + "QVC_hd": { + "tname": "QVC", + "ename": "QVC HD", + "id": "QVC", + "service": "1:0:19:526F:41D:1:C00000:0:0:0:" + }, + "CPLUSC_sd": { + "tname": "Canal+ Cin\u00e9ma", + "ename": "CANAL+CINEMA", + "id": "CPLUSC", + "service": "1:0:19:2263:438:1:C00000:0:0:0:" + }, + "ATV_uhd": { + "tname": "ATV", + "ename": "", + "id": "ATV", + "service": "" + }, + "RBB_uhd": { + "tname": "RBB", + "ename": "", + "id": "RBB", + "service": "" + }, + "FR24E_sd": { + "tname": "France 24 (engl.)", + "ename": "France 24 (In English)", + "id": "FR24E", + "service": "1:0:1:1AFA:3FE:1:C00000:0:0:0:" + }, + "SF1_sd": { + "tname": "SRF 1", + "ename": "", + "id": "SF1", + "service": "" + }, + "EURO_hd": { + "tname": "Eurosport 1", + "ename": "Eurosport 1 HD", + "id": "EURO", + "service": "1:0:19:30D6:413:1:C00000:0:0:0:" + }, + "RBTV_sd": { + "tname": "Rocket Beans TV", + "ename": "", + "id": "RBTV", + "service": "" + }, + "EURO2_uhd": { + "tname": "Eurosport 2", + "ename": "", + "id": "EURO2", + "service": "" + }, + "SKYAT_uhd": { + "tname": "Sky Atlantic HD", + "ename": "", + "id": "SKYAT", + "service": "" + }, + "BRN_sd": { + "tname": "BR", + "ename": "BR Fernsehen Nord", + "id": "BR", + "service": "1:0:1:6DCE:44D:1:C00000:0:0:0:" + }, + "BRS_hd": { + "tname": "BR", + "ename": "BR Fernsehen Süd", + "id": "BR", + "service": "1:0:19:2855:401:1:C00000:0:0:0:" + }, + "HR_sd": { + "tname": "HR", + "ename": "hr-fernsehen", + "id": "HR", + "service": "1:0:1:6DCC:44D:1:C00000:0:0:0:" + }, + "SKYSPL_hd": { + "tname": "Sky Sport Premier League", + "ename": "Sky Sport Premier League HD", + "id": "SKYSPL", + "service": "1:0:19:91:9:85:C00000:0:0:0:" + }, + "NICKT_sd": { + "tname": "Nicktoons", + "ename": "Nicktoons", + "id": "NICKT", + "service": "1:0:16:1B:D:85:C00000:0:0:0:" + }, + "MASPO_sd": { + "tname": "Magenta Sport", + "ename": "", + "id": "MASPO", + "service": "" + }, + "SKYSM_uhd": { + "tname": "Sky Sport Mix", + "ename": "", + "id": "SKYSM", + "service": "" + }, + "ES1_sd": { + "tname": "eSports1", + "ename": "eSPORTS1", + "id": "ES1", + "service": "1:0:19:10CE:418:1:C00000:0:0:0:" + }, + "TRAVELXP_uhd": { + "tname": "travelxp 4K", + "ename": "", + "id": "TRAVELXP", + "service": "" + }, + "STTV_uhd": { + "tname": "STAR TV", + "ename": "", + "id": "STTV", + "service": "" + }, + "RTLPL_sd": { + "tname": "RTLup", + "ename": "RTLup", + "id": "RTLPL", + "service": "1:0:1:2F30:441:1:C00000:0:0:0:" + }, + "JUKE_uhd": { + "tname": "Jukebox", + "ename": "", + "id": "JUKE", + "service": "" + }, + "TLC_uhd": { + "tname": "TLC", + "ename": "", + "id": "TLC", + "service": "" + }, + "TAG24_hd": { + "tname": "tagesschau 24", + "ename": "tagesschau24 HD", + "id": "TAG24", + "service": "1:0:19:2887:40F:1:C00000:0:0:0:" + }, + "SKYAT_sd": { + "tname": "Sky Atlantic HD", + "ename": "", + "id": "SKYAT", + "service": "" + }, + "BBC-E_uhd": { + "tname": "BBC Entertainment", + "ename": "", + "id": "BBC-E", + "service": "" + }, + "BULI_hd": { + "tname": "Sky Bundesliga", + "ename": "", + "id": "BULI", + "service": "" + }, + "PRO7F_hd": { + "tname": "ProSieben Fun", + "ename": "", + "id": "PRO7F", + "service": "" + }, + "HDDIS_uhd": { + "tname": "Discovery HD", + "ename": "", + "id": "HDDIS", + "service": "" + }, + "TMAX_hd": { + "tname": "Turkmax Gurme", + "ename": "", + "id": "TMAX", + "service": "" + }, + "3PLUS_uhd": { + "tname": "3+", + "ename": "", + "id": "3PLUS", + "service": "" + }, + "DMF_sd": { + "tname": "Deutsches Musik Fernsehen", + "ename": "Deutsches Musik Fernsehen", + "id": "DMF", + "service": "1:0:1:313C:459:1:C00000:0:0:0:" + }, + "FRA3_hd": { + "tname": "France 3", + "ename": "", + "id": "FRA3", + "service": "" + }, + "DAZN_sd": { + "tname": "DAZN", + "ename": "", + "id": "DAZN", + "service": "" + }, + "SKYRP_uhd": { + "tname": "sky replay", + "ename": "", + "id": "SKYRP", + "service": "" + }, + "RTL2_hd": { + "tname": "RTL II", + "ename": "RTLZWEI HD", + "id": "RTL2", + "service": "1:0:19:EF15:421:1:C00000:0:0:0:" + }, + "SKYCS_uhd": { + "tname": "Sky Cinema Special HD", + "ename": "", + "id": "SKYCS", + "service": "" + }, + "DR2_hd": { + "tname": "DR2", + "ename": "", + "id": "DR2", + "service": "" + }, + "SPTVW_uhd": { + "tname": "Curiosity Channel", + "ename": "", + "id": "SPTVW", + "service": "" + }, + "BBC1_sd": { + "tname": "BBC One", + "ename": "", + "id": "BBC1", + "service": "" + }, + "SP-GE_sd": { + "tname": "SPIEGEL Geschichte", + "ename": "", + "id": "SP-GE", + "service": "" + }, + "SKYSM_hd": { + "tname": "Sky Sport Mix", + "ename": "Sky Sport Mix HD", + "id": "SKYSM", + "service": "1:0:19:8D:9:85:C00000:0:0:0:" + }, + "MTV-B_sd": { + "tname": "MTV Base", + "ename": "", + "id": "MTV-B", + "service": "" + }, + "SKYCS_sd": { + "tname": "Sky Cinema Special HD", + "ename": "", + "id": "SKYCS", + "service": "" + }, + "NAUCH_uhd": { + "tname": "Nautical Channel", + "ename": "", + "id": "NAUCH", + "service": "" + }, + "DAZN_uhd": { + "tname": "DAZN", + "ename": "", + "id": "DAZN", + "service": "" + }, + "ORF3_uhd": { + "tname": "ORF III", + "ename": "", + "id": "ORF3", + "service": "" + }, + "EX-SP_uhd": { + "tname": "EXTREME SPORTS", + "ename": "", + "id": "EX-SP", + "service": "" + }, + "ORF2_hd": { + "tname": "ORF 2", + "ename": "ORF2B HD", + "id": "ORF2", + "service": "1:0:19:33F7:3ED:1:C00000:0:0:0:" + }, + "HSE_uhd": { + "tname": "HSE24", + "ename": "", + "id": "HSE", + "service": "" + }, + "NICKJ_uhd": { + "tname": "Nick Jr.", + "ename": "", + "id": "NICKJ", + "service": "" + }, + "TNT-F_sd": { + "tname": "Warner TV Film", + "ename": "", + "id": "TNT-F", + "service": "" + }, + "HDDIS_sd": { + "tname": "Discovery HD", + "ename": "", + "id": "HDDIS", + "service": "" + }, + "ORF2_sd": { + "tname": "ORF 2", + "ename": "ORF2", + "id": "ORF2", + "service": "1:0:1:32CA:45D:1:C00000:0:0:0:" + }, + "CPLUS_hd": { + "tname": "Canal+", + "ename": "", + "id": "CPLUS", + "service": "" + }, + "KTV_sd": { + "tname": "K-TV", + "ename": "K-TV", + "id": "KTV", + "service": "1:0:1:3139:459:1:C00000:0:0:0:" + }, + "AXN_sd": { + "tname": "AXN", + "ename": "AXN Deutschland", + "id": "AXN", + "service": "1:0:16:101D:451:35:C00000:0:0:0:" + }, + "LAUNE_hd": { + "tname": "Gute Laune TV", + "ename": "", + "id": "LAUNE", + "service": "" + }, + "EURO-D_sd": { + "tname": "Euro D", + "ename": "", + "id": "EURO-D", + "service": "" + }, + "3SAT_hd": { + "tname": "3sat", + "ename": "3sat HD", + "id": "3SAT", + "service": "1:0:19:2B8E:3F2:1:C00000:0:0:0:" + }, + "TNT-F_uhd": { + "tname": "Warner TV Film", + "ename": "", + "id": "TNT-F", + "service": "" + }, + "GEO_hd": { + "tname": "GEO Television", + "ename": "", + "id": "GEO", + "service": "" + }, + "SAT1G_sd": { + "tname": "SAT.1 Gold", + "ename": "SAT.1 Gold", + "id": "SAT1G", + "service": "1:0:1:4460:453:1:C00000:0:0:0:" + }, + "BBC4_hd": { + "tname": "BBC Four", + "ename": "", + "id": "BBC4", + "service": "" + }, + "PRO7F_sd": { + "tname": "ProSieben Fun", + "ename": "", + "id": "PRO7F", + "service": "" + }, + "SKYST_hd": { + "tname": "Sky Sport Tennis", + "ename": "Sky Sport Tennis HD", + "id": "SKYST", + "service": "1:0:19:72:D:85:C00000:0:0:0:" + }, + "FR24E_uhd": { + "tname": "France 24 (engl.)", + "ename": "", + "id": "FR24E", + "service": "" + }, + "SAT1E_hd": { + "tname": "SAT.1 emotions", + "ename": "", + "id": "SAT1E", + "service": "" + }, + "SKY-CR_uhd": { + "tname": "Sky Crime", + "ename": "", + "id": "SKY-CR", + "service": "" + }, + "FR24E_hd": { + "tname": "France 24 (engl.)", + "ename": "", + "id": "FR24E", + "service": "" + }, + "LEITV_sd": { + "tname": "Leipzig Fernsehen", + "ename": "", + "id": "LEITV", + "service": "" + }, + "DISNE_sd": { + "tname": "Disney Channel", + "ename": "Disney Channel", + "id": "DISNE", + "service": "1:0:1:701:5:85:C00000:0:0:0:" + }, + "N-GHD_sd": { + "tname": "National Geographic HD", + "ename": "", + "id": "N-GHD", + "service": "" + }, + "FRA3_sd": { + "tname": "France 3", + "ename": "FRANCE 3", + "id": "FRA3", + "service": "1:0:19:245D:440:1:C00000:0:0:0:" + }, + "MTV-B_hd": { + "tname": "MTV Base", + "ename": "", + "id": "MTV-B", + "service": "" + }, + "PULS8_uhd": { + "tname": "PULS acht", + "ename": "", + "id": "PULS8", + "service": "" + }, + "RIC_uhd": { + "tname": "RiC", + "ename": "", + "id": "RIC", + "service": "" + }, + "NHK_sd": { + "tname": "NHK WORLD TV", + "ename": "NHK WORLD-JPN", + "id": "NHK", + "service": "1:0:1:139D:3EA:1:C00000:0:0:0:" + }, + "HISHD_hd": { + "tname": "HISTORY HD", + "ename": "HISTORY Channel HD", + "id": "HISHD", + "service": "1:0:19:71:B:85:C00000:0:0:0:" + }, + "DWTV_hd": { + "tname": "DW (Europe)", + "ename": "", + "id": "DWTV", + "service": "" + }, + "GUSTO_hd": { + "tname": "BonGusto", + "ename": "", + "id": "GUSTO", + "service": "" + }, + "STTV_sd": { + "tname": "STAR TV", + "ename": "", + "id": "STTV", + "service": "" + }, + "SONY_hd": { + "tname": "Sony Channel", + "ename": "", + "id": "SONY", + "service": "" + }, + "SKY-CO_uhd": { + "tname": "Sky Comedy", + "ename": "", + "id": "SKY-CO", + "service": "" + }, + "SKY-NA_hd": { + "tname": "Sky Nature", + "ename": "Sky Nature HD", + "id": "SKY-NA", + "service": "1:0:19:F:2:85:C00000:0:0:0:" + }, + "CC_uhd": { + "tname": "COMEDY CENTRAL", + "ename": "", + "id": "CC", + "service": "" + }, + "FRA2_uhd": { + "tname": "France 2", + "ename": "", + "id": "FRA2", + "service": "" + }, + "QVCP_hd": { + "tname": "QVC2", + "ename": "QVC ZWEI HD", + "id": "QVCP", + "service": "1:0:19:1580:41F:1:C00000:0:0:0:" + }, + "LAUNE_sd": { + "tname": "Gute Laune TV", + "ename": "", + "id": "LAUNE", + "service": "" + }, + "BERG_uhd": { + "tname": "Bergblick", + "ename": "", + "id": "BERG", + "service": "" + }, + "BBC4_uhd": { + "tname": "BBC Four", + "ename": "", + "id": "BBC4", + "service": "" + }, + "UNIVE_uhd": { + "tname": "Universal Channel HD", + "ename": "", + "id": "UNIVE", + "service": "" + }, + "TELE5_uhd": { + "tname": "TELE 5", + "ename": "", + "id": "TELE5", + "service": "" + }, + "DMC_uhd": { + "tname": "DELUXE MUSIC", + "ename": "", + "id": "DMC", + "service": "" + }, + "HH1_hd": { + "tname": "Hamburg 1", + "ename": "", + "id": "HH1", + "service": "" + }, + "PASS_uhd": { + "tname": "RTL Passion", + "ename": "", + "id": "PASS", + "service": "" + }, + "BUTV_uhd": { + "tname": "Beate-Uhse.TV", + "ename": "", + "id": "BUTV", + "service": "" + }, + "SKY-CR_sd": { + "tname": "Sky Crime", + "ename": "", + "id": "SKY-CR", + "service": "" + }, + "AXN_hd": { + "tname": "AXN", + "ename": "", + "id": "AXN", + "service": "" + }, + "2NEO_sd": { + "tname": "ZDFneo", + "ename": "zdf_neo", + "id": "2NEO", + "service": "1:0:1:6D6E:437:1:C00000:0:0:0:" + }, + "MAPO_hd": { + "tname": "Marco Polo TV", + "ename": "", + "id": "MAPO", + "service": "" + }, + "LAUNE_uhd": { + "tname": "Gute Laune TV", + "ename": "", + "id": "LAUNE", + "service": "" + }, + "N-GHD_hd": { + "tname": "National Geographic HD", + "ename": "NatGeo HD", + "id": "N-GHD", + "service": "1:0:19:70:D:85:C00000:0:0:0:" + }, + "ZINFO_sd": { + "tname": "ZDFinfo", + "ename": "ZDFinfo", + "id": "ZINFO", + "service": "1:0:1:6D6B:437:1:C00000:0:0:0:" + }, + "PULS4_hd": { + "tname": "PULS 4", + "ename": "PULS 4 HD Austria", + "id": "PULS4", + "service": "1:0:19:14B7:407:1:C00000:0:0:0:" + }, + "C5_uhd": { + "tname": "Canale 5", + "ename": "", + "id": "C5", + "service": "" + }, + "TVB_uhd": { + "tname": "tv.berlin", + "ename": "", + "id": "TVB", + "service": "" + }, + "CH21_sd": { + "tname": "Channel21", + "ename": "Channel21", + "id": "CH21", + "service": "1:0:1:301:7:85:C00000:0:0:0:" + }, + "SERVUSA_uhd": { + "tname": "Servus TV \u00d6sterreich", + "ename": "", + "id": "SERVUSA", + "service": "" + }, + "DR1_uhd": { + "tname": "DR1", + "ename": "", + "id": "DR1", + "service": "" + }, + "BBC1_uhd": { + "tname": "BBC One", + "ename": "", + "id": "BBC1", + "service": "" + }, + "NOWUS_sd": { + "tname": "NOW US", + "ename": "", + "id": "NOWUS", + "service": "" + }, + "EURO-S_hd": { + "tname": "Euro Star", + "ename": "", + "id": "EURO-S", + "service": "" + }, + "N24DOKU_sd": { + "tname": "N24 Doku", + "ename": "N24 DOKU", + "id": "N24DOKU", + "service": "1:0:1:30:5:85:C00000:0:0:0:" + }, + "MTV-H_hd": { + "tname": "MTV Hits", + "ename": "", + "id": "MTV-H", + "service": "" + }, + "SKYRP_sd": { + "tname": "sky replay", + "ename": "", + "id": "SKYRP", + "service": "" + }, + "SKLAR_uhd": { + "tname": "sonnenklar TV", + "ename": "", + "id": "SKLAR", + "service": "" + }, + "13TH_hd": { + "tname": "13th Street", + "ename": "13th Street HD", + "id": "13TH", + "service": "1:0:19:7F:D:85:C00000:0:0:0:" + }, + "NHK_hd": { + "tname": "NHK WORLD TV", + "ename": "", + "id": "NHK", + "service": "" + }, + "RTL-C_uhd": { + "tname": "RTL Crime", + "ename": "", + "id": "RTL-C", + "service": "" + }, + "S1PLU_sd": { + "tname": "SPORT1+", + "ename": "SPORT1+", + "id": "S1PLU", + "service": "1:0:19:10CD:418:1:C00000:0:0:0:" + }, + "PRO7_hd": { + "tname": "ProSieben", + "ename": "ProSieben HD", + "id": "PRO7", + "service": "1:0:19:EF75:3F9:1:C00000:0:0:0:" + }, + "C-NET_hd": { + "tname": "Cartoon Network", + "ename": "", + "id": "C-NET", + "service": "" + }, + "NTV_uhd": { + "tname": "n-tv", + "ename": "", + "id": "NTV", + "service": "" + }, + "GUSTO_uhd": { + "tname": "BonGusto", + "ename": "", + "id": "GUSTO", + "service": "" + }, + "TVM_uhd": { + "tname": "m\u00fcnchen.tv", + "ename": "", + "id": "TVM", + "service": "" + }, + "NOWUS_hd": { + "tname": "NOW US", + "ename": "", + "id": "NOWUS", + "service": "" + }, + "MTV-L_uhd": { + "tname": "MTV Live HD", + "ename": "", + "id": "MTV-L", + "service": "" + }, + "SCIFI_hd": { + "tname": "Syfy", + "ename": "SYFY HD", + "id": "SCIFI", + "service": "1:0:19:7E:C:85:C00000:0:0:0:" + }, + "VH1_uhd": { + "tname": "VH1 Classic", + "ename": "", + "id": "VH1", + "service": "" + }, + "MDR_sd": { + "tname": "MDR", + "ename": "MDR Sachsen", + "id": "MDR", + "service": "1:0:1:6E44:431:1:C00000:0:0:0:" + }, + "NICK_uhd": { + "tname": "nick/MTV+", + "ename": "", + "id": "NICK", + "service": "" + }, + "HH1_sd": { + "tname": "Hamburg 1", + "ename": "", + "id": "HH1", + "service": "" + }, + "ORFSP_sd": { + "tname": "ORF SPORT +", + "ename": "ORF SPORT+", + "id": "ORFSP", + "service": "1:0:1:33A5:3EB:1:C00000:0:0:0:" + }, + "SERVU_sd": { + "tname": "ServusTV Deutschland", + "ename": "ServusTV Deutschland", + "id": "SERVU", + "service": "1:0:1:3336:45B:1:C00000:0:0:0:" + }, + "APLAN_hd": { + "tname": "Animal Planet", + "ename": "", + "id": "APLAN", + "service": "" + }, + "ARD_hd": { + "tname": "Das Erste", + "ename": "Das Erste HD", + "id": "ARD", + "service": "1:0:19:283D:3FB:1:C00000:0:0:0:" + }, + "PRO7M_sd": { + "tname": "ProSieben MAXX", + "ename": "Pro7 MAXX", + "id": "PRO7M", + "service": "1:0:1:4461:453:1:C00000:0:0:0:" + }, + "SKYTH_hd": { + "tname": "Sky Cinema Thriller HD", + "ename": "Sky Cinema Thriller HD", + "id": "SKYTH", + "service": "1:0:19:B:4:85:C00000:0:0:0:" + }, + "SHOT_sd": { + "tname": "Show Turk", + "ename": "", + "id": "SHOT", + "service": "" + }, + "VOXUP_hd": { + "tname": "VOXup", + "ename": "", + "id": "VOXUP", + "service": "" + }, + "SHOT_hd": { + "tname": "Show Turk", + "ename": "", + "id": "SHOT", + "service": "" + }, + "UNIVE_sd": { + "tname": "Universal Channel HD", + "ename": "", + "id": "UNIVE", + "service": "" + }, + "RTL-N_hd": { + "tname": "NITRO", + "ename": "NITRO HD", + "id": "RTL-N", + "service": "1:0:19:2EAF:411:1:C00000:0:0:0:" + }, + "ZDF_sd": { + "tname": "ZDF", + "ename": "ZDF", + "id": "ZDF", + "service": "1:0:1:6D66:437:1:C00000:0:0:0:" + }, + "MOVTV_uhd": { + "tname": "Motorvision TV", + "ename": "", + "id": "MOVTV", + "service": "" + }, + "KIKA_uhd": { + "tname": "KiKA", + "ename": "", + "id": "KIKA", + "service": "" + }, + "SKY-H_hd": { + "tname": "Sky Cinema Best Of", + "ename": "Sky Cinema Best Of HD", + "id": "SKY-H", + "service": "1:0:19:6B:C:85:C00000:0:0:0:" + }, + "RTL-L_uhd": { + "tname": "RTL Living", + "ename": "", + "id": "RTL-L", + "service": "" + }, + "LUSTP_sd": { + "tname": "LUST PUR", + "ename": "", + "id": "LUSTP", + "service": "" + }, + "CPLUSS_hd": { + "tname": "Canal+ Sport", + "ename": "", + "id": "CPLUSS", + "service": "" + }, + "ADULT_uhd": { + "tname": "Adult Channel", + "ename": "", + "id": "ADULT", + "service": "" + }, + "TMAX_uhd": { + "tname": "Turkmax Gurme", + "ename": "", + "id": "TMAX", + "service": "" + }, + "SKYSTE_uhd": { + "tname": "Sky Sport Top Event", + "ename": "", + "id": "SKYSTE", + "service": "" + }, + "BBC_hd": { + "tname": "BBC World News", + "ename": "BBC World News Europe HD", + "id": "BBC", + "service": "1:0:1:1389:3EA:1:C00000:0:0:0:" + }, + "RTL_sd": { + "tname": "RTL", + "ename": "RTL Television", + "id": "RTL", + "service": "1:0:1:2EE3:441:1:C00000:0:0:0:" + }, + "BERG_hd": { + "tname": "Bergblick", + "ename": "", + "id": "BERG", + "service": "" + }, + "CNBC_sd": { + "tname": "CNBC", + "ename": "CNBC Europe", + "id": "CNBC", + "service": "1:0:1:272E:402:1:C00000:0:0:0:" + }, + "BE1_sd": { + "tname": "Belgien 1", + "ename": "", + "id": "BE1", + "service": "" + }, + "ATV_sd": { + "tname": "ATV", + "ename": "ATV", + "id": "ATV", + "service": "1:0:1:32D4:45D:1:C00000:0:0:0:" + }, + "KIKA_hd": { + "tname": "KiKA", + "ename": "KiKA HD", + "id": "KIKA", + "service": "1:0:19:2B98:3F2:1:C00000:0:0:0:" + }, + "13TH_sd": { + "tname": "13th Street", + "ename": "", + "id": "13TH", + "service": "" + }, + "TRACE_hd": { + "tname": "Trace TV", + "ename": "", + "id": "TRACE", + "service": "" + }, + "EURON_sd": { + "tname": "euronews", + "ename": "EURONEWS GERMAN SD", + "id": "EURON", + "service": "1:0:1:79FE:443:1:C00000:0:0:0:" + }, + "TVB_sd": { + "tname": "tv.berlin", + "ename": "", + "id": "TVB", + "service": "" + }, + "C5_sd": { + "tname": "Canale 5", + "ename": "", + "id": "C5", + "service": "" + }, + "SKY-C_sd": { + "tname": "Sky Cinema Fun", + "ename": "Sky Cinema Fun HD", + "id": "SKY-C", + "service": "1:0:16:8:3:85:C00000:0:0:0:" + }, + "FRA3_uhd": { + "tname": "France 3", + "ename": "", + "id": "FRA3", + "service": "" + }, + "SKY1_uhd": { + "tname": "Sky 1", + "ename": "", + "id": "SKY1", + "service": "" + }, + "ATV2_hd": { + "tname": "ATV II", + "ename": "", + "id": "ATV2", + "service": "" + }, + "SCIFI_sd": { + "tname": "Syfy", + "ename": "", + "id": "SCIFI", + "service": "" + }, + "STTV_hd": { + "tname": "STAR TV", + "ename": "", + "id": "STTV", + "service": "" + }, + "SNHD_hd": { + "tname": "Sky Sport News", + "ename": "Sky Sport News HD", + "id": "SNHD", + "service": "1:0:19:6C:C:85:C00000:0:0:0:" + }, + "SPO-D_hd": { + "tname": "sportdigital Fussball", + "ename": "SPORTDIGITAL FUSSBALL HD_alt", + "id": "SPO-D", + "service": "1:0:19:1194:406:1:C00000:0:0:0:" + }, + "TRACE_sd": { + "tname": "Trace TV", + "ename": "TRACE URBAN", + "id": "TRACE", + "service": "1:0:19:24C6:43C:1:C00000:0:0:0:" + }, + "PASS_sd": { + "tname": "RTL Passion", + "ename": "", + "id": "PASS", + "service": "" + }, + "APLAN_sd": { + "tname": "Animal Planet", + "ename": "", + "id": "APLAN", + "service": "" + }, + "TV2_sd": { + "tname": "TV2", + "ename": "", + "id": "TV2", + "service": "" + }, + "MTV-L_hd": { + "tname": "MTV Live HD", + "ename": "", + "id": "MTV-L", + "service": "" + }, + "TAG24_uhd": { + "tname": "tagesschau 24", + "ename": "", + "id": "TAG24", + "service": "" + }, + "SNHD_sd": { + "tname": "Sky Sport News", + "ename": "Sky Sport News", + "id": "SNHD", + "service": "1:0:1:25:F:85:C00000:0:0:0:" + }, + "MTV-H_uhd": { + "tname": "MTV Hits", + "ename": "", + "id": "MTV-H", + "service": "" + }, + "SKY-K_sd": { + "tname": "Sky Krimi", + "ename": "", + "id": "SKY-K", + "service": "" + }, + "N3_uhd": { + "tname": "NDR", + "ename": "", + "id": "N3", + "service": "" + }, + "HISHD_sd": { + "tname": "HISTORY HD", + "ename": "", + "id": "HISHD", + "service": "" + }, + "S1PLU_uhd": { + "tname": "SPORT1+", + "ename": "", + "id": "S1PLU", + "service": "" + }, + "DMAX_hd": { + "tname": "DMAX", + "ename": "DMAX HD", + "id": "DMAX", + "service": "1:0:19:151A:455:1:C00000:0:0:0:" + }, + "MASPO_uhd": { + "tname": "Magenta Sport", + "ename": "", + "id": "MASPO", + "service": "" + }, + "BLM_hd": { + "tname": "Bloomberg Europe TV", + "ename": "", + "id": "BLM", + "service": "" + }, + "SF2_sd": { + "tname": "SRF zwei", + "ename": "", + "id": "SF2", + "service": "" + }, + "FES_sd": { + "tname": "ONE", + "ename": "ONE", + "id": "FES", + "service": "1:0:1:7032:41B:1:C00000:0:0:0:" + }, + "WDWTV_uhd": { + "tname": "Welt der Wunder TV", + "ename": "", + "id": "WDWTV", + "service": "" + }, + "SKY1_sd": { + "tname": "Sky 1", + "ename": "", + "id": "SKY1", + "service": "" + }, + "DMAX_sd": { + "tname": "DMAX", + "ename": "DMAX", + "id": "DMAX", + "service": "1:0:1:3F:21:85:C00000:0:0:0:" + }, + "PHOEN_sd": { + "tname": "PHOENIX", + "ename": "phoenix", + "id": "PHOEN", + "service": "1:0:1:7035:41B:1:C00000:0:0:0:" + }, + "K1_sd": { + "tname": "kabel eins", + "ename": "kabel eins", + "id": "K1", + "service": "1:0:1:445E:453:1:C00000:0:0:0:" + }, + "N3_hd": { + "tname": "NDR", + "ename": "NDR FS HH HD", + "id": "N3", + "service": "1:0:19:2859:401:1:C00000:0:0:0:" + }, + "3PLUS_sd": { + "tname": "3+", + "ename": "3+", + "id": "3PLUS", + "service": "1:0:19:1260:3F7:1:C00000:0:0:0:" + }, + "MOVTV_hd": { + "tname": "Motorvision TV", + "ename": "", + "id": "MOVTV", + "service": "" + }, + "PBOY_uhd": { + "tname": "Playboy TV", + "ename": "", + "id": "PBOY", + "service": "" + }, + "TOGGO_hd": { + "tname": "TOGGO plus", + "ename": "", + "id": "TOGGO", + "service": "" + }, + "ATV_hd": { + "tname": "ATV", + "ename": "ATV HD", + "id": "ATV", + "service": "1:0:19:33AC:3EB:1:C00000:0:0:0:" + }, + "AXN_uhd": { + "tname": "AXN", + "ename": "", + "id": "AXN", + "service": "" + }, + "TRAVELXP_sd": { + "tname": "travelxp 4K", + "ename": "", + "id": "TRAVELXP", + "service": "" + }, + "ZINFO_uhd": { + "tname": "ZDFinfo", + "ename": "", + "id": "ZINFO", + "service": "" + }, + "TNT-S_sd": { + "tname": "Warner TV Serie", + "ename": "", + "id": "TNT-S", + "service": "" + }, + "FES_uhd": { + "tname": "ONE", + "ename": "", + "id": "FES", + "service": "" + }, + "OE24TV_hd": { + "tname": "oe24.TV", + "ename": "oe24.TV HD", + "id": "OE24TV", + "service": "1:0:19:3402:3ED:1:C00000:0:0:0:" + }, + "UHD1_sd": { + "tname": "UHD1", + "ename": "", + "id": "UHD1", + "service": "" + }, + "CNN_uhd": { + "tname": "CNN International", + "ename": "", + "id": "CNN", + "service": "" + }, + "AMS_hd": { + "tname": "Auto Motor und Sport", + "ename": "AutoMotorSport HD temp", + "id": "AMS", + "service": "1:0:19:22:F:85:C00000:0:0:0:" + }, + "SKY-F_hd": { + "tname": "Sky Family", + "ename": "Sky Cinema Family HD", + "id": "SKY-F", + "service": "1:0:19:8B:2:85:C00000:0:0:0:" + }, + "JUKE_sd": { + "tname": "Jukebox", + "ename": "Jukebox", + "id": "JUKE", + "service": "1:0:16:191:9:85:C00000:0:0:0:" + }, + "C-NET_sd": { + "tname": "Cartoon Network", + "ename": "Cartoon Network", + "id": "C-NET", + "service": "1:0:16:194:B:85:C00000:0:0:0:" + }, + "TV5_hd": { + "tname": "TV5 Monde", + "ename": "", + "id": "TV5", + "service": "" + }, + "MTV-B_uhd": { + "tname": "MTV Base", + "ename": "", + "id": "MTV-B", + "service": "" + }, + "TRAVELXP_hd": { + "tname": "travelxp 4K", + "ename": "", + "id": "TRAVELXP", + "service": "" + }, + "GUSTO_sd": { + "tname": "BonGusto", + "ename": "", + "id": "GUSTO", + "service": "" + }, + "N-GHD_uhd": { + "tname": "National Geographic HD", + "ename": "", + "id": "N-GHD", + "service": "" + }, + "SONY_uhd": { + "tname": "Sony Channel", + "ename": "", + "id": "SONY", + "service": "" + }, + "SKY-K_uhd": { + "tname": "Sky Krimi", + "ename": "", + "id": "SKY-K", + "service": "" + }, + "EURON_hd": { + "tname": "euronews", + "ename": "", + "id": "EURON", + "service": "" + }, + "SAT1_hd": { + "tname": "SAT.1", + "ename": "SAT.1 HD", + "id": "SAT1", + "service": "1:0:19:EF74:3F9:1:C00000:0:0:0:" + }, + "PASS_hd": { + "tname": "RTL Passion", + "ename": "", + "id": "PASS", + "service": "" + }, + "CLASS_sd": { + "tname": "Classica", + "ename": "", + "id": "CLASS", + "service": "" + }, + "QVC_uhd": { + "tname": "QVC", + "ename": "QVC UHD", + "id": "QVC", + "service": "1:0:1F:1086:3EE:1:C00000:0:0:0:" + }, + "SPO-A_sd": { + "tname": "Sky Sport Austria", + "ename": "Sky Sport Austria 1", + "id": "SPO-A", + "service": "1:0:16:1E:2:85:C00000:0:0:0:" + }, + "2NEO_uhd": { + "tname": "ZDFneo", + "ename": "", + "id": "2NEO", + "service": "" + }, + "MAPO_sd": { + "tname": "Marco Polo TV", + "ename": "", + "id": "MAPO", + "service": "" + }, + "SWR_sd": { + "tname": "SWR/SR", + "ename": "SWR Fernsehen BW", + "id": "SWR", + "service": "1:0:1:6DD1:44D:1:C00000:0:0:0:" + }, + "SKYSTE_sd": { + "tname": "Sky Sport Top Event", + "ename": "Sky Sport Top Event", + "id": "SKYSTE", + "service": "1:0:16:DD:4:85:C00000:0:0:0:" + }, + "FRA2_hd": { + "tname": "France 2", + "ename": "", + "id": "FRA2", + "service": "" + }, + "KTV_hd": { + "tname": "K-TV", + "ename": "", + "id": "KTV", + "service": "" + }, + "SKLAR_sd": { + "tname": "sonnenklar TV", + "ename": "Sonnenklar TV", + "id": "SKLAR", + "service": "1:0:1:20:21:85:C00000:0:0:0:" + }, + "SPO-A_hd": { + "tname": "Sky Sport Austria", + "ename": "11170H SID 0x8f", + "id": "SPO-A", + "service": "1:0:19:8F:9:85:C00000:0:0:0:" + }, + "RBB_sd": { + "tname": "RBB", + "ename": "rbb Berlin", + "id": "RBB", + "service": "1:0:1:6E2E:431:1:C00000:0:0:0:" + }, + "SF2_hd": { + "tname": "SRF zwei", + "ename": "SRF zwei HD", + "id": "SF2", + "service": "1:0:19:4332:300C:13E:820000:0:0:0:" + }, + "PHOEN_hd": { + "tname": "PHOENIX", + "ename": "phoenix HD", + "id": "PHOEN", + "service": "1:0:19:285B:401:1:C00000:0:0:0:" + }, + "SIXX_uhd": { + "tname": "sixx", + "ename": "", + "id": "SIXX", + "service": "" + }, + "CPLUSC_uhd": { + "tname": "Canal+ Cin\u00e9ma", + "ename": "", + "id": "CPLUSC", + "service": "" + }, + "ADULT_hd": { + "tname": "Adult Channel", + "ename": "", + "id": "ADULT", + "service": "" + }, + "BBC-E_hd": { + "tname": "BBC Entertainment", + "ename": "", + "id": "BBC-E", + "service": "" + }, + "ALPHA_uhd": { + "tname": "ARD-alpha", + "ename": "", + "id": "ALPHA", + "service": "" + }, + "RMTV_sd": { + "tname": "rheinmain tv", + "ename": "rhein main tv", + "id": "RMTV", + "service": "1:0:1:3146:459:1:C00000:0:0:0:" + }, + "BBC-N_uhd": { + "tname": "BBC News", + "ename": "", + "id": "BBC-N", + "service": "" + }, + "DR1_hd": { + "tname": "DR1", + "ename": "", + "id": "DR1", + "service": "" + }, + "RIC_sd": { + "tname": "RiC", + "ename": "RiC", + "id": "RIC", + "service": "1:0:1:32DB:45D:1:C00000:0:0:0:" + }, + "BBC1_hd": { + "tname": "BBC One", + "ename": "", + "id": "BBC1", + "service": "" + }, + "FRA4_sd": { + "tname": "France 4", + "ename": "FRANCE 4", + "id": "FRA4", + "service": "1:0:19:21FD:44C:1:C00000:0:0:0:" + }, + "BBC2_sd": { + "tname": "BBC Two", + "ename": "", + "id": "BBC2", + "service": "" + }, + "DAZN_hd": { + "tname": "DAZN", + "ename": "", + "id": "DAZN", + "service": "" + }, + "SKY-CO_hd": { + "tname": "Sky Comedy", + "ename": "Sky Comedy HD", + "id": "SKY-CO", + "service": "1:0:19:E:2:85:C00000:0:0:0:" + }, + "S1PLU_hd": { + "tname": "SPORT1+", + "ename": "", + "id": "S1PLU", + "service": "" + }, + "SKYSH_uhd": { + "tname": "sky showcase", + "ename": "", + "id": "SKYSH", + "service": "" + }, + "MTV_sd": { + "tname": "MTV", + "ename": "MTV", + "id": "MTV", + "service": "1:0:1:7006:436:1:C00000:0:0:0:" + }, + "BULI_sd": { + "tname": "Sky Bundesliga", + "ename": "Sky Sport Bundesliga", + "id": "BULI", + "service": "1:0:16:DF:4:85:C00000:0:0:0:" + }, + "SPTVW_sd": { + "tname": "Curiosity Channel", + "ename": "Curiosity Channel powered by Spiegel", + "id": "SPTVW", + "service": "1:0:16:31:D:85:C00000:0:0:0:" + }, + "SILVE_hd": { + "tname": "Silverline", + "ename": "", + "id": "SILVE", + "service": "" + }, + "VOXUP_uhd": { + "tname": "VOXup", + "ename": "", + "id": "VOXUP", + "service": "" + }, + "13TH_uhd": { + "tname": "13th Street", + "ename": "", + "id": "13TH", + "service": "" + }, + "123TV_hd": { + "tname": "123.tv", + "ename": "1-2-3.tv HD", + "id": "123TV", + "service": "1:0:19:157E:41F:1:C00000:0:0:0:" + }, + "K1CLA_uhd": { + "tname": "kabel eins CLASSICS", + "ename": "", + "id": "K1CLA", + "service": "" + }, + "SKYCS_hd": { + "tname": "Sky Cinema Special HD", + "ename": "Sky Cinema 007 HD", + "id": "SKYCS", + "service": "1:0:19:6F:D:85:C00000:0:0:0:" + }, + "SAT1_sd": { + "tname": "SAT.1", + "ename": "SAT.1", + "id": "SAT1", + "service": "1:0:1:445C:453:1:C00000:0:0:0:" + }, + "3PLUS_hd": { + "tname": "3+", + "ename": "", + "id": "3PLUS", + "service": "" + }, + "SILVE_sd": { + "tname": "Silverline", + "ename": "", + "id": "SILVE", + "service": "" + }, + "SKY-NA_uhd": { + "tname": "Sky Nature", + "ename": "", + "id": "SKY-NA", + "service": "" + }, + "PRO7M_uhd": { + "tname": "ProSieben MAXX", + "ename": "", + "id": "PRO7M", + "service": "" + }, + "KINOW_sd": { + "tname": "KinoweltTV", + "ename": "Kinowelt TV", + "id": "KINOW", + "service": "1:0:16:196:2:85:C00000:0:0:0:" + }, + "BULI_uhd": { + "tname": "Sky Bundesliga", + "ename": "Sky Sport Bundesliga UHD", + "id": "BULI", + "service": "1:0:1F:228:10:85:C00000:0:0:0:" + }, + "SKY-C_uhd": { + "tname": "Sky Cinema Fun", + "ename": "", + "id": "SKY-C", + "service": "" + }, + "SKYST_uhd": { + "tname": "Sky Sport Tennis", + "ename": "", + "id": "SKYST", + "service": "" + }, + "RBB_hd": { + "tname": "RBB", + "ename": "rbb Berlin HD", + "id": "RBB", + "service": "1:0:19:286F:425:1:C00000:0:0:0:" + }, + "APLAN_uhd": { + "tname": "Animal Planet", + "ename": "", + "id": "APLAN", + "service": "" + }, + "SKY-N_uhd": { + "tname": "Sky Cinema Classics", + "ename": "", + "id": "SKY-N", + "service": "" + }, + "NICKT_uhd": { + "tname": "Nicktoons", + "ename": "", + "id": "NICKT", + "service": "" + }, + "BBC-E_sd": { + "tname": "BBC Entertainment", + "ename": "", + "id": "BBC-E", + "service": "" + }, + "CIN_sd": { + "tname": "Sky Cinema Premieren", + "ename": "Sky Cinema Premieren", + "id": "CIN", + "service": "1:0:16:A:4:85:C00000:0:0:0:" + }, + "SHOT_uhd": { + "tname": "Show Turk", + "ename": "", + "id": "SHOT", + "service": "" + }, + "VH1_sd": { + "tname": "VH1 Classic", + "ename": "MTV 80s", + "id": "VH1", + "service": "1:0:1:6FF1:436:1:C00000:0:0:0:" + }, + "ROM_hd": { + "tname": "Romance TV", + "ename": "", + "id": "ROM", + "service": "" + }, + "SAT1G_uhd": { + "tname": "SAT.1 Gold", + "ename": "", + "id": "SAT1G", + "service": "" + }, + "ADULT_sd": { + "tname": "Adult Channel", + "ename": "", + "id": "ADULT", + "service": "" + }, + "RIC_hd": { + "tname": "RiC", + "ename": "", + "id": "RIC", + "service": "" + }, + "PRO7F_uhd": { + "tname": "ProSieben Fun", + "ename": "", + "id": "PRO7F", + "service": "" + }, + "FR24F_uhd": { + "tname": "France 24 (franz.)", + "ename": "", + "id": "FR24F", + "service": "" + }, + "ARD_sd": { + "tname": "Das Erste", + "ename": "Das Erste", + "id": "ARD", + "service": "1:0:1:6DCA:44D:1:C00000:0:0:0:" + }, + "NTV_sd": { + "tname": "n-tv", + "ename": "ntv", + "id": "NTV", + "service": "1:0:1:2F3A:441:1:C00000:0:0:0:" + }, + "SKLAR_hd": { + "tname": "sonnenklar TV", + "ename": "", + "id": "SKLAR", + "service": "" + }, + "HEALTH_uhd": { + "tname": "Health TV", + "ename": "", + "id": "HEALTH", + "service": "" + }, + "K1DOKU_uhd": { + "tname": "kabel eins Doku", + "ename": "", + "id": "K1DOKU", + "service": "" + }, + "SKY-A_uhd": { + "tname": "Sky Action", + "ename": "", + "id": "SKY-A", + "service": "" + }, + "TNT-S_hd": { + "tname": "Warner TV Serie", + "ename": "Warner TV Serie HD", + "id": "TNT-S", + "service": "1:0:19:7B:9:85:C00000:0:0:0:" + }, + "MTV_hd": { + "tname": "MTV", + "ename": "MTV HD", + "id": "MTV", + "service": "1:0:19:2777:409:1:C00000:0:0:0:" + }, + "SKY-A_sd": { + "tname": "Sky Action", + "ename": "Sky Cinema Action", + "id": "SKY-A", + "service": "1:0:16:9:3:85:C00000:0:0:0:" + }, + "CPLUS_uhd": { + "tname": "Canal+", + "ename": "", + "id": "CPLUS", + "service": "" + }, + "BLM_sd": { + "tname": "Bloomberg Europe TV", + "ename": "Bloomberg Europe TV", + "id": "BLM", + "service": "1:0:1:1C20:457:1:C00000:0:0:0:" + }, + "HGTV_hd": { + "tname": "Home & Garden TV", + "ename": "", + "id": "HGTV", + "service": "" + }, + "EX-SP_hd": { + "tname": "EXTREME SPORTS", + "ename": "", + "id": "EX-SP", + "service": "" + }, + "BBC2_hd": { + "tname": "BBC Two", + "ename": "", + "id": "BBC2", + "service": "" + }, + "SKYTH_uhd": { + "tname": "Sky Cinema Thriller HD", + "ename": "", + "id": "SKYTH", + "service": "" + }, + "HISHD_uhd": { + "tname": "HISTORY HD", + "ename": "", + "id": "HISHD", + "service": "" + }, + "SERVUSA_sd": { + "tname": "Servus TV \u00d6sterreich", + "ename": "", + "id": "SERVUSA", + "service": "" + }, + "EOTV_hd": { + "tname": "More than Sports TV", + "ename": "", + "id": "EOTV", + "service": "" + }, + "KINOW_hd": { + "tname": "KinoweltTV", + "ename": "", + "id": "KINOW", + "service": "" + }, + "QVC_sd": { + "tname": "QVC", + "ename": "QVC", + "id": "QVC", + "service": "1:0:1:702:5:85:C00000:0:0:0:" + }, + "FRA4_uhd": { + "tname": "France 4", + "ename": "", + "id": "FRA4", + "service": "" + }, + "EX-SP_sd": { + "tname": "EXTREME SPORTS", + "ename": "", + "id": "EX-SP", + "service": "" + }, + "HDDIS_hd": { + "tname": "Discovery HD", + "ename": "Discovery HD", + "id": "HDDIS", + "service": "1:0:19:82:6:85:C00000:0:0:0:" + }, + "SKY-A_hd": { + "tname": "Sky Action", + "ename": "Sky Cinema Action HD", + "id": "SKY-A", + "service": "1:0:19:74:9:85:C00000:0:0:0:" + }, + "NAUCH_hd": { + "tname": "Nautical Channel", + "ename": "", + "id": "NAUCH", + "service": "" + }, + "HEALTH_sd": { + "tname": "Health TV", + "ename": "health.tv", + "id": "HEALTH", + "service": "1:0:1:3138:459:1:C00000:0:0:0:" + }, + "ROM_uhd": { + "tname": "Romance TV", + "ename": "", + "id": "ROM", + "service": "" + }, + "GEO_sd": { + "tname": "GEO Television", + "ename": "", + "id": "GEO", + "service": "" + }, + "SF2_uhd": { + "tname": "SRF zwei", + "ename": "", + "id": "SF2", + "service": "" + }, + "SUPER_sd": { + "tname": "SUPER RTL", + "ename": "SUPER RTL", + "id": "SUPER", + "service": "1:0:1:2F08:441:1:C00000:0:0:0:" + }, + "ATV2_uhd": { + "tname": "ATV II", + "ename": "", + "id": "ATV2", + "service": "" + }, + "FRA2_sd": { + "tname": "France 2", + "ename": "FRANCE 2", + "id": "FRA2", + "service": "1:0:19:245A:440:1:C00000:0:0:0:" + }, + "EURO_sd": { + "tname": "Eurosport 1", + "ename": "Eurosport 1 Deutschland", + "id": "EURO", + "service": "1:0:1:79E0:443:1:C00000:0:0:0:" + }, + "SF1_hd": { + "tname": "SRF 1", + "ename": "SRF 1 HD", + "id": "SF1", + "service": "1:0:19:4331:300C:13E:820000:0:0:0:" + }, + "TRACE_uhd": { + "tname": "Trace TV", + "ename": "", + "id": "TRACE", + "service": "" + }, + "N-GW_uhd": { + "tname": "NAT GEO WILD", + "ename": "", + "id": "N-GW", + "service": "" + }, + "EURO_uhd": { + "tname": "Eurosport 1", + "ename": "", + "id": "EURO", + "service": "" + }, + "CNBC_uhd": { + "tname": "CNBC", + "ename": "", + "id": "CNBC", + "service": "" + }, + "VH1_hd": { + "tname": "VH1 Classic", + "ename": "", + "id": "VH1", + "service": "" + }, + "FRA5_hd": { + "tname": "France 5", + "ename": "", + "id": "FRA5", + "service": "" + }, + "SKYSG_uhd": { + "tname": "Sky Sport Golf", + "ename": "", + "id": "SKYSG", + "service": "" + }, + "ZDF_uhd": { + "tname": "ZDF", + "ename": "", + "id": "ZDF", + "service": "" + }, + "SKYSG_sd": { + "tname": "Sky Sport Golf", + "ename": "", + "id": "SKYSG", + "service": "" + }, + "ANIXE_sd": { + "tname": "ANIXE", + "ename": "", + "id": "ANIXE", + "service": "" + }, + "WDR_uhd": { + "tname": "WDR", + "ename": "", + "id": "WDR", + "service": "" + }, + "RMTV_uhd": { + "tname": "rheinmain tv", + "ename": "", + "id": "RMTV", + "service": "" + }, + "FATV_uhd": { + "tname": "Fashion TV", + "ename": "", + "id": "FATV", + "service": "" + }, + "BBC_uhd": { + "tname": "BBC World News", + "ename": "", + "id": "BBC", + "service": "" + }, + "HGTV_sd": { + "tname": "Home & Garden TV", + "ename": "HGTV", + "id": "HGTV", + "service": "1:0:1:26:F:85:C00000:0:0:0:" + }, + "PULS4_sd": { + "tname": "PULS 4", + "ename": "PULS 4 Austria", + "id": "PULS4", + "service": "1:0:1:4E27:43A:1:C00000:0:0:0:" + }, + "SKY-C_hd": { + "tname": "Sky Cinema Fun", + "ename": "", + "id": "SKY-C", + "service": "" + }, + "BIBEL_hd": { + "tname": "Bibel TV", + "ename": "Bibel TV HD", + "id": "BIBEL", + "service": "1:0:19:33A8:3EB:1:C00000:0:0:0:" + }, + "DR2_sd": { + "tname": "DR2", + "ename": "", + "id": "DR2", + "service": "" + }, + "SAT1E_uhd": { + "tname": "SAT.1 emotions", + "ename": "", + "id": "SAT1E", + "service": "" + }, + "CIN24_sd": { + "tname": "Sky Cinema Premieren +24", + "ename": "Sky Cinema Premieren +24", + "id": "CIN24", + "service": "1:0:16:2B:6:85:C00000:0:0:0:" + }, + "SKYSM_sd": { + "tname": "Sky Sport Mix", + "ename": "", + "id": "SKYSM", + "service": "" + }, + "RTLPL_hd": { + "tname": "RTLup", + "ename": "", + "id": "RTLPL", + "service": "" + }, + "TELE5_hd": { + "tname": "TELE 5", + "ename": "TELE 5 HD", + "id": "TELE5", + "service": "1:0:19:1519:455:1:C00000:0:0:0:" + }, + "MTV-D_uhd": { + "tname": "Club MTV", + "ename": "", + "id": "MTV-D", + "service": "" + }, + "SKYRP_hd": { + "tname": "sky replay", + "ename": "Sky Replay HD", + "id": "SKYRP", + "service": "1:0:19:7C:C:85:C00000:0:0:0:" + }, + "SKYF1_uhd": { + "tname": "SKY Sport F1", + "ename": "", + "id": "SKYF1", + "service": "" + }, + "GEO_uhd": { + "tname": "GEO Television", + "ename": "", + "id": "GEO", + "service": "" + }, + "FR24F_hd": { + "tname": "France 24 (franz.)", + "ename": "", + "id": "FR24F", + "service": "" + }, + "RTL-L_hd": { + "tname": "RTL Living", + "ename": "", + "id": "RTL-L", + "service": "" + }, + "SKY-NA_sd": { + "tname": "Sky Nature", + "ename": "", + "id": "SKY-NA", + "service": "" + }, + "DISNE_hd": { + "tname": "Disney Channel", + "ename": "Disney Channel HD", + "id": "DISNE", + "service": "1:0:19:157C:41F:1:C00000:0:0:0:" + }, + "HSE_sd": { + "tname": "HSE24", + "ename": "HSE SD", + "id": "HSE", + "service": "1:0:1:28:21:85:C00000:0:0:0:" + }, + "RTL-C_hd": { + "tname": "RTL Crime", + "ename": "", + "id": "RTL-C", + "service": "" + }, + "MEZZO_hd": { + "tname": "Mezzo", + "ename": "", + "id": "MEZZO", + "service": "" + }, + "SP-GE_hd": { + "tname": "SPIEGEL Geschichte", + "ename": "Spiegel Geschichte HD", + "id": "SP-GE", + "service": "1:0:19:89:10:85:C00000:0:0:0:" + }, + "SERVU_hd": { + "tname": "ServusTV Deutschland", + "ename": "", + "id": "SERVU", + "service": "" + }, + "HSE_hd": { + "tname": "HSE24", + "ename": "HSE HD", + "id": "HSE", + "service": "1:0:19:5270:41D:1:C00000:0:0:0:" + }, + "CRIN_uhd": { + "tname": "Crime + Investigation", + "ename": "", + "id": "CRIN", + "service": "" + }, + "SPORT_sd": { + "tname": "SPORT1", + "ename": "SPORT1", + "id": "SPORT", + "service": "1:0:1:384:21:85:C00000:0:0:0:" + }, + "DMC_hd": { + "tname": "DELUXE MUSIC", + "ename": "Deluxe Music HD", + "id": "DMC", + "service": "1:0:19:157F:41F:1:C00000:0:0:0:" + }, + "ANIXE_hd": { + "tname": "ANIXE", + "ename": "ANIXE HD", + "id": "ANIXE", + "service": "1:0:19:526C:41D:1:C00000:0:0:0:" + }, + "GOLD_sd": { + "tname": "GoldStar TV", + "ename": "", + "id": "GOLD", + "service": "" + }, + "RTL-N_uhd": { + "tname": "NITRO", + "ename": "", + "id": "RTL-N", + "service": "" + }, + "CIN_hd": { + "tname": "Sky Cinema Premieren", + "ename": "Sky Cinema Premieren HD", + "id": "CIN", + "service": "1:0:19:83:6:85:C00000:0:0:0:" + }, + "SKYSPL_uhd": { + "tname": "Sky Sport Premier League", + "ename": "", + "id": "SKYSPL", + "service": "" + }, + "SNHD_uhd": { + "tname": "Sky Sport News", + "ename": "", + "id": "SNHD", + "service": "" + }, + "CRIN_hd": { + "tname": "Crime + Investigation", + "ename": "", + "id": "CRIN", + "service": "" + }, + "PULS8_hd": { + "tname": "PULS acht", + "ename": "", + "id": "PULS8", + "service": "" + }, + "MEZZO_uhd": { + "tname": "Mezzo", + "ename": "", + "id": "MEZZO", + "service": "" + }, + "NICKT_hd": { + "tname": "Nicktoons", + "ename": "", + "id": "NICKT", + "service": "" + }, + "SAT1G_hd": { + "tname": "SAT.1 Gold", + "ename": "SAT.1 Gold HD", + "id": "SAT1G", + "service": "1:0:19:30D4:413:1:C00000:0:0:0:" + }, + "BBC2_uhd": { + "tname": "BBC Two", + "ename": "", + "id": "BBC2", + "service": "" + }, + "PRO7M_hd": { + "tname": "ProSieben MAXX", + "ename": "Pro7 MAXX HD", + "id": "PRO7M", + "service": "1:0:19:EF78:3F9:1:C00000:0:0:0:" + }, + "LUSTP_uhd": { + "tname": "LUST PUR", + "ename": "", + "id": "LUSTP", + "service": "" + }, + "EURO-D_hd": { + "tname": "Euro D", + "ename": "", + "id": "EURO-D", + "service": "" + }, + "RTL-L_sd": { + "tname": "RTL Living", + "ename": "", + "id": "RTL-L", + "service": "" + }, + "UHD1_uhd": { + "tname": "UHD1", + "ename": "UHD1 by ASTRA / HD+", + "id": "UHD1", + "service": "1:0:1F:2:40B:1:C00000:0:0:0:" + }, + "TNT-S_uhd": { + "tname": "Warner TV Serie", + "ename": "", + "id": "TNT-S", + "service": "" + }, + "UNIVE_hd": { + "tname": "Universal Channel HD", + "ename": "Universal TV HD", + "id": "UNIVE", + "service": "1:0:19:65:9:85:C00000:0:0:0:" + }, + "K1DOKU_sd": { + "tname": "kabel eins Doku", + "ename": "kabel eins Doku", + "id": "K1DOKU", + "service": "1:0:1:4465:453:1:C00000:0:0:0:" + }, + "TELE5_sd": { + "tname": "TELE 5", + "ename": "TELE 5", + "id": "TELE5", + "service": "1:0:1:33:21:85:C00000:0:0:0:" + }, + "CC_sd": { + "tname": "COMEDY CENTRAL", + "ename": "Comedy Central", + "id": "CC", + "service": "1:0:1:7004:436:1:C00000:0:0:0:" + }, + "BBC4_sd": { + "tname": "BBC Four", + "ename": "", + "id": "BBC4", + "service": "" + }, + "BERG_sd": { + "tname": "Bergblick", + "ename": "Bergblick", + "id": "BERG", + "service": "1:0:16:1013:451:35:C00000:0:0:0:" + }, + "CNN-T_hd": { + "tname": "CNN T\u00fcrk", + "ename": "", + "id": "CNN-T", + "service": "" + }, + "SERVU_uhd": { + "tname": "ServusTV Deutschland", + "ename": "", + "id": "SERVU", + "service": "" + }, + "OE24TV_uhd": { + "tname": "oe24.TV", + "ename": "", + "id": "OE24TV", + "service": "" + }, + "CPLUSC_hd": { + "tname": "Canal+ Cin\u00e9ma", + "ename": "", + "id": "CPLUSC", + "service": "" + }, + "TOGGO_uhd": { + "tname": "TOGGO plus", + "ename": "", + "id": "TOGGO", + "service": "" + }, + "CC_hd": { + "tname": "COMEDY CENTRAL", + "ename": "ShopLC HD", + "id": "CC", + "service": "1:0:19:5273:41D:1:C00000:0:0:0:" + }, + "TOGGO_sd": { + "tname": "TOGGO plus", + "ename": "TOGGO plus", + "id": "TOGGO", + "service": "1:0:1:2EFE:441:1:C00000:0:0:0:" + }, + "MEZZO_sd": { + "tname": "Mezzo", + "ename": "MEZZO", + "id": "MEZZO", + "service": "1:0:19:1F4A:42E:1:C00000:0:0:0:" + }, + "SIXX_sd": { + "tname": "sixx", + "ename": "SIXX", + "id": "SIXX", + "service": "1:0:1:308:5:85:C00000:0:0:0:" + }, + "SPO-A_uhd": { + "tname": "Sky Sport Austria", + "ename": "", + "id": "SPO-A", + "service": "" + }, + "HEALTH_hd": { + "tname": "Health TV", + "ename": "", + "id": "HEALTH", + "service": "" + }, + "NAUCH_sd": { + "tname": "Nautical Channel", + "ename": "", + "id": "NAUCH", + "service": "" + }, + "SPORT_hd": { + "tname": "SPORT1", + "ename": "SPORT1 HD", + "id": "SPORT", + "service": "1:0:19:1581:41F:1:C00000:0:0:0:" + }, + "CNN-T_uhd": { + "tname": "CNN T\u00fcrk", + "ename": "", + "id": "CNN-T", + "service": "" + }, + "FR24F_sd": { + "tname": "France 24 (franz.)", + "ename": "France 24 (en Francais)", + "id": "FR24F", + "service": "1:0:1:1AF9:3FE:1:C00000:0:0:0:" + }, + "GOLD_hd": { + "tname": "GoldStar TV", + "ename": "", + "id": "GOLD", + "service": "" + }, + "ORF3_sd": { + "tname": "ORF III", + "ename": "ORF III", + "id": "ORF3", + "service": "1:0:1:332D:45B:1:C00000:0:0:0:" + }, + "BIBEL_sd": { + "tname": "Bibel TV", + "ename": "Bibel TV", + "id": "BIBEL", + "service": "1:0:1:2F5A:454:1:C00000:0:0:0:" + }, + "TNT-F_hd": { + "tname": "Warner TV Film", + "ename": "Warner TV Film HD", + "id": "TNT-F", + "service": "1:0:19:8C:4:85:C00000:0:0:0:" + }, + "MASPO_hd": { + "tname": "Magenta Sport", + "ename": "", + "id": "MASPO", + "service": "" + }, + "BR_uhd": { + "tname": "BR", + "ename": "", + "id": "BR", + "service": "" + }, + "MDR_uhd": { + "tname": "MDR", + "ename": "", + "id": "MDR", + "service": "" + }, + "HR_hd": { + "tname": "HR", + "ename": "hr-fernsehen HD", + "id": "HR", + "service": "1:0:19:2873:425:1:C00000:0:0:0:" + }, + "RTL2_sd": { + "tname": "RTL II", + "ename": "RTLZWEI", + "id": "RTL2", + "service": "1:0:1:2EF4:441:1:C00000:0:0:0:" + }, + "DMC_sd": { + "tname": "DELUXE MUSIC", + "ename": "DELUXE MUSIC", + "id": "DMC", + "service": "1:0:1:41:7:85:C00000:0:0:0:" + }, + "KINOW_uhd": { + "tname": "KinoweltTV", + "ename": "", + "id": "KINOW", + "service": "" + }, + "RBTV_uhd": { + "tname": "Rocket Beans TV", + "ename": "", + "id": "RBTV", + "service": "" + }, + "2NEO_hd": { + "tname": "ZDFneo", + "ename": "zdf_neo HD", + "id": "2NEO", + "service": "1:0:19:2B7A:3F3:1:C00000:0:0:0:" + }, + "ALJAZ_uhd": { + "tname": "Al Jazeera", + "ename": "", + "id": "ALJAZ", + "service": "" + }, + "LEITV_hd": { + "tname": "Leipzig Fernsehen", + "ename": "", + "id": "LEITV", + "service": "" + }, + "SIXX_hd": { + "tname": "sixx", + "ename": "SIXX HD", + "id": "SIXX", + "service": "1:0:19:EF77:3F9:1:C00000:0:0:0:" + }, + "TVM_sd": { + "tname": "m\u00fcnchen.tv", + "ename": "", + "id": "TVM", + "service": "" + }, + "BE1_uhd": { + "tname": "Belgien 1", + "ename": "", + "id": "BE1", + "service": "" + }, + "BE1_hd": { + "tname": "Belgien 1", + "ename": "", + "id": "BE1", + "service": "" + }, + "SKYSTE_hd": { + "tname": "Sky Sport Top Event", + "ename": "Sky Sport Top Event HD", + "id": "SKYSTE", + "service": "1:0:19:81:6:85:C00000:0:0:0:" + }, + "FFTV_uhd": { + "tname": "FIX & FOXI", + "ename": "", + "id": "FFTV", + "service": "" + }, + "SKY-F_sd": { + "tname": "Sky Family", + "ename": "Sky Cinema Family", + "id": "SKY-F", + "service": "1:0:16:197:4:85:C00000:0:0:0:" + }, + "EOTV_uhd": { + "tname": "More than Sports TV", + "ename": "", + "id": "EOTV", + "service": "" + }, + "TVB_hd": { + "tname": "tv.berlin", + "ename": "", + "id": "TVB", + "service": "" + }, + "C5_hd": { + "tname": "Canale 5", + "ename": "", + "id": "C5", + "service": "" + }, + "N24DOKU_hd": { + "tname": "N24 Doku", + "ename": "", + "id": "N24DOKU", + "service": "" + }, + "MTV-H_sd": { + "tname": "MTV Hits", + "ename": "MTV Hits", + "id": "MTV-H", + "service": "1:0:1:6FEE:436:1:C00000:0:0:0:" + }, + "SPORT_uhd": { + "tname": "SPORT1", + "ename": "", + "id": "SPORT", + "service": "" + }, + "PRO7_sd": { + "tname": "ProSieben", + "ename": "ProSieben", + "id": "PRO7", + "service": "1:0:1:445D:453:1:C00000:0:0:0:" + }, + "SPO-D_uhd": { + "tname": "sportdigital Fussball", + "ename": "", + "id": "SPO-D", + "service": "" + }, + "BUTV_hd": { + "tname": "Beate-Uhse.TV", + "ename": "Beate Uhse HD", + "id": "BUTV", + "service": "1:0:19:85:3:85:C00000:0:0:0:" + }, + "SKY-N_sd": { + "tname": "Sky Cinema Classics", + "ename": "Sky Cinema Classics HD", + "id": "SKY-N", + "service": "1:0:16:204:6:85:C00000:0:0:0:" + }, + "TV5_uhd": { + "tname": "TV5 Monde", + "ename": "", + "id": "TV5", + "service": "" + }, + "ZINFO_hd": { + "tname": "ZDFinfo", + "ename": "ZDFinfo HD", + "id": "ZINFO", + "service": "1:0:19:2BA2:3F2:1:C00000:0:0:0:" + }, + "SKY-H_uhd": { + "tname": "Sky Cinema Best Of", + "ename": "", + "id": "SKY-H", + "service": "" + }, + "ATV2_sd": { + "tname": "ATV II", + "ename": "ATV2", + "id": "ATV2", + "service": "1:0:1:33A7:3EB:1:C00000:0:0:0:" + }, + "CH21_uhd": { + "tname": "Channel21", + "ename": "", + "id": "CH21", + "service": "" + }, + "FES_hd": { + "tname": "ONE", + "ename": "ONE HD", + "id": "FES", + "service": "1:0:19:2888:40F:1:C00000:0:0:0:" + }, + "HH1_uhd": { + "tname": "Hamburg 1", + "ename": "", + "id": "HH1", + "service": "" + }, + "MDR_hd": { + "tname": "MDR", + "ename": "MDR Sachsen HD", + "id": "MDR", + "service": "1:0:19:2870:425:1:C00000:0:0:0:" + }, + "CNN-T_sd": { + "tname": "CNN T\u00fcrk", + "ename": "", + "id": "CNN-T", + "service": "" + }, + "FFTV_sd": { + "tname": "FIX & FOXI", + "ename": "", + "id": "FFTV", + "service": "" + }, + "SKY-D_uhd": { + "tname": "Sky Documentaries", + "ename": "", + "id": "SKY-D", + "service": "" + }, + "ORF3_hd": { + "tname": "ORF III", + "ename": "ORF III HD", + "id": "ORF3", + "service": "1:0:19:33FC:3ED:1:C00000:0:0:0:" + }, + "WELT_uhd": { + "tname": "WELT", + "ename": "", + "id": "WELT", + "service": "" + }, + "TV2_uhd": { + "tname": "TV2", + "ename": "", + "id": "TV2", + "service": "" + }, + "BLM_uhd": { + "tname": "Bloomberg Europe TV", + "ename": "", + "id": "BLM", + "service": "" + }, + "LEITV_uhd": { + "tname": "Leipzig Fernsehen", + "ename": "", + "id": "LEITV", + "service": "" + }, + "ORF1_uhd": { + "tname": "ORF eins", + "ename": "", + "id": "ORF1", + "service": "" + }, + "CPLUSS_sd": { + "tname": "Canal+ Sport", + "ename": "CANAL+SPORT", + "id": "CPLUSS", + "service": "1:0:19:2264:438:1:C00000:0:0:0:" + }, + "3SAT_sd": { + "tname": "3sat", + "ename": "3sat", + "id": "3SAT", + "service": "1:0:1:6D67:437:1:C00000:0:0:0:" + }, + "CLASS_uhd": { + "tname": "Classica", + "ename": "", + "id": "CLASS", + "service": "" + }, + "ALJAZ_sd": { + "tname": "Al Jazeera", + "ename": "Al Jazeera English", + "id": "ALJAZ", + "service": "1:0:1:1158:404:1:C00000:0:0:0:" + }, + "BBC-N_sd": { + "tname": "BBC News", + "ename": "", + "id": "BBC-N", + "service": "" + }, + "WDWTV_hd": { + "tname": "Welt der Wunder TV", + "ename": "", + "id": "WDWTV", + "service": "" + }, + "CPLUS_sd": { + "tname": "Canal+", + "ename": "CANAL+", + "id": "CPLUS", + "service": "1:0:19:2261:438:1:C00000:0:0:0:" + }, + "DWTV_uhd": { + "tname": "DW (Europe)", + "ename": "", + "id": "DWTV", + "service": "" + }, + "CNN_sd": { + "tname": "CNN International", + "ename": "CNN Int.", + "id": "CNN", + "service": "1:0:1:1146:404:1:C00000:0:0:0:" + }, + "RTL-N_sd": { + "tname": "NITRO", + "ename": "NITRO", + "id": "RTL-N", + "service": "1:0:1:2F1D:441:1:C00000:0:0:0:" + }, + "VOXUP_sd": { + "tname": "VOXup", + "ename": "VOXup", + "id": "VOXUP", + "service": "1:0:1:7094:443:1:C00000:0:0:0:" + }, + "LUSTP_hd": { + "tname": "LUST PUR", + "ename": "", + "id": "LUSTP", + "service": "" + }, + "BBC-N_hd": { + "tname": "BBC News", + "ename": "", + "id": "BBC-N", + "service": "" + }, + "ALPHA_hd": { + "tname": "ARD-alpha", + "ename": "ARD alpha HD", + "id": "ALPHA", + "service": "1:0:19:2889:40F:1:C00000:0:0:0:" + }, + "TVM_hd": { + "tname": "m\u00fcnchen.tv", + "ename": "m\u00fcnchen.tv HD", + "id": "TVM", + "service": "1:0:19:16A9:3FF:1:C00000:0:0:0:" + }, + "SKY-CO_sd": { + "tname": "Sky Comedy", + "ename": "", + "id": "SKY-CO", + "service": "" + }, + "DMF_uhd": { + "tname": "Deutsches Musik Fernsehen", + "ename": "", + "id": "DMF", + "service": "" + }, + "SKY-K_hd": { + "tname": "Sky Krimi", + "ename": "Sky Krimi HD", + "id": "SKY-K", + "service": "1:0:19:17:4:85:C00000:0:0:0:" + }, + "MTV-D_hd": { + "tname": "Club MTV", + "ename": "", + "id": "MTV-D", + "service": "" + }, + "SPO-D_sd": { + "tname": "sportdigital Fussball", + "ename": "", + "id": "SPO-D", + "service": "" + }, + "KTV_uhd": { + "tname": "K-TV", + "ename": "", + "id": "KTV", + "service": "" + }, + "SCIFI_uhd": { + "tname": "Syfy", + "ename": "", + "id": "SCIFI", + "service": "" + }, + "EURO2_hd": { + "tname": "Eurosport 2", + "ename": "Eurosport 2 HD", + "id": "EURO2", + "service": "1:0:19:6D:B:85:C00000:0:0:0:" + }, + "N-GW_hd": { + "tname": "NAT GEO WILD", + "ename": "Nat Geo Wild HD", + "id": "N-GW", + "service": "1:0:19:76:6:85:C00000:0:0:0:" + }, + "TV5_sd": { + "tname": "TV5 Monde", + "ename": "TV5 MONDE", + "id": "TV5", + "service": "1:0:19:26B6:43E:1:C00000:0:0:0:" + }, + "K1_hd": { + "tname": "kabel eins", + "ename": "kabel eins HD", + "id": "K1", + "service": "1:0:19:EF76:3F9:1:C00000:0:0:0:" + }, + "ORF1_hd": { + "tname": "ORF eins", + "ename": "ORF1 HD", + "id": "ORF1", + "service": "1:0:19:132F:3EF:1:C00000:0:0:0:" + }, + "RNF_sd": { + "tname": "Rhein-Neckar Fernsehen", + "ename": "", + "id": "RNF", + "service": "" + }, + "CLASS_hd": { + "tname": "Classica", + "ename": "", + "id": "CLASS", + "service": "" + }, + "123TV_sd": { + "tname": "123.tv", + "ename": "1-2-3.tv", + "id": "123TV", + "service": "1:0:1:296:5:85:C00000:0:0:0:" + }, + "SONY_sd": { + "tname": "Sony Channel", + "ename": "", + "id": "SONY", + "service": "" + }, + "DWTV_sd": { + "tname": "DW (Europe)", + "ename": "DW English", + "id": "DWTV", + "service": "1:0:1:114E:404:1:C00000:0:0:0:" + }, + "HGTV_uhd": { + "tname": "Home & Garden TV", + "ename": "", + "id": "HGTV", + "service": "" + }, + "TNT-C_uhd": { + "tname": "Warner TV Comedy", + "ename": "", + "id": "TNT-C", + "service": "" + }, + "EURO2_sd": { + "tname": "Eurosport 2", + "ename": "Elevensports 1 FR", + "id": "EURO2", + "service": "1:0:16:100A:451:35:C00000:0:0:0:" + }, + "DISNE_uhd": { + "tname": "Disney Channel", + "ename": "", + "id": "DISNE", + "service": "" + }, + "123TV_uhd": { + "tname": "123.tv", + "ename": "", + "id": "123TV", + "service": "" + }, + "ZDF_hd": { + "tname": "ZDF", + "ename": "ZDF HD", + "id": "ZDF", + "service": "1:0:19:2B66:3F3:1:C00000:0:0:0:" + }, + "TV2_hd": { + "tname": "TV2", + "ename": "", + "id": "TV2", + "service": "" + }, + "MTV-L_sd": { + "tname": "MTV Live HD", + "ename": "", + "id": "MTV-L", + "service": "" + }, + "ES1_uhd": { + "tname": "eSports1", + "ename": "", + "id": "ES1", + "service": "" + }, + "K1CLA_sd": { + "tname": "kabel eins CLASSICS", + "ename": "kabel eins classics", + "id": "K1CLA", + "service": "1:0:16:14C2:407:1:C00000:0:0:0:" + }, + "PULS8_sd": { + "tname": "PULS acht", + "ename": "", + "id": "PULS8", + "service": "" + }, + "MAPO_uhd": { + "tname": "Marco Polo TV", + "ename": "", + "id": "MAPO", + "service": "" + }, + "SF1_uhd": { + "tname": "SRF 1", + "ename": "", + "id": "SF1", + "service": "" + }, + "SKYSH_sd": { + "tname": "sky showcase", + "ename": "", + "id": "SKYSH", + "service": "" + }, + "DR1_sd": { + "tname": "DR1", + "ename": "", + "id": "DR1", + "service": "" + }, + "NICK_hd": { + "tname": "nick/MTV+", + "ename": "", + "id": "NICK", + "service": "" + }, + "SKYF1_hd": { + "tname": "SKY Sport F1", + "ename": "Sky Sport F1 HD", + "id": "SKYF1", + "service": "1:0:19:11:3:85:C00000:0:0:0:" + }, + "WDR_hd": { + "tname": "WDR", + "ename": "WDR HD Bielefeld", + "id": "WDR", + "service": "1:0:19:6EAE:3FD:1:C00000:0:0:0:" + }, + "FATV_hd": { + "tname": "Fashion TV", + "ename": "", + "id": "FATV", + "service": "" + }, + "MOVTV_sd": { + "tname": "Motorvision TV", + "ename": "Motorvision TV", + "id": "MOVTV", + "service": "1:0:16:A8:B:85:C00000:0:0:0:" + }, + "NICKJ_hd": { + "tname": "Nick Jr.", + "ename": "", + "id": "NICKJ", + "service": "" + }, + "N-GW_sd": { + "tname": "NAT GEO WILD", + "ename": "", + "id": "N-GW", + "service": "" + }, + "SKY-F_uhd": { + "tname": "Sky Family", + "ename": "", + "id": "SKY-F", + "service": "" + }, + "ANIXE_uhd": { + "tname": "ANIXE", + "ename": "", + "id": "ANIXE", + "service": "" + }, + "SKYTH_sd": { + "tname": "Sky Cinema Thriller HD", + "ename": "", + "id": "SKYTH", + "service": "" + }, + "ES1_hd": { + "tname": "eSports1", + "ename": "", + "id": "ES1", + "service": "" + }, + "OE24TV_sd": { + "tname": "oe24.TV", + "ename": "", + "id": "OE24TV", + "service": "" + }, + "RTL2_uhd": { + "tname": "RTL II", + "ename": "RTLII UHD", + "id": "RTL2", + "service": "1:0:1:3070:3F5:1:C00000:0:0:0:" + }, + "KIKA_sd": { + "tname": "KiKA", + "ename": "KiKA", + "id": "KIKA", + "service": "1:0:1:6D68:437:1:C00000:0:0:0:" + }, + "JUKE_hd": { + "tname": "Jukebox", + "ename": "", + "id": "JUKE", + "service": "" + }, + "BUTV_sd": { + "tname": "Beate-Uhse.TV", + "ename": "", + "id": "BUTV", + "service": "" + }, + "SKY-N_hd": { + "tname": "Sky Cinema Classics", + "ename": "", + "id": "SKY-N", + "service": "" + }, + "VOX_uhd": { + "tname": "VOX", + "ename": "", + "id": "VOX", + "service": "" + }, + "DR2_uhd": { + "tname": "DR2", + "ename": "", + "id": "DR2", + "service": "" + }, + "SKY-H_sd": { + "tname": "Sky Cinema Best Of", + "ename": "Sky Cinema Best Of", + "id": "SKY-H", + "service": "1:0:16:29:4:85:C00000:0:0:0:" + }, + "MTV_uhd": { + "tname": "MTV", + "ename": "", + "id": "MTV", + "service": "" + }, + "SERVUSA_hd": { + "tname": "Servus TV \u00d6sterreich", + "ename": "", + "id": "SERVUSA", + "service": "" + }, + "FFTV_hd": { + "tname": "FIX & FOXI", + "ename": "", + "id": "FFTV", + "service": "" + }, + "ORF1_sd": { + "tname": "ORF eins", + "ename": "ORF1", + "id": "ORF1", + "service": "1:0:1:32C9:45D:1:C00000:0:0:0:" + }, + "SKY-CR_hd": { + "tname": "Sky Crime", + "ename": "Sky Crime HD", + "id": "SKY-CR", + "service": "1:0:19:D:6:85:C00000:0:0:0:" + }, + "WELT_hd": { + "tname": "WELT", + "ename": "WELT HD", + "id": "WELT", + "service": "1:0:19:5274:41D:1:C00000:0:0:0:" + }, + "ORFSP_hd": { + "tname": "ORF SPORT +", + "ename": "ORF SPORT+ HD", + "id": "ORFSP", + "service": "1:0:19:33FD:3ED:1:C00000:0:0:0:" + }, + "MTV-D_sd": { + "tname": "Club MTV", + "ename": "MTV Dance", + "id": "MTV-D", + "service": "1:0:1:6FEF:436:1:C00000:0:0:0:" + }, + "EURO-S_uhd": { + "tname": "Euro Star", + "ename": "", + "id": "EURO-S", + "service": "" + }, + "SKY1_hd": { + "tname": "Sky 1", + "ename": "Sky One HD", + "id": "SKY1", + "service": "1:0:19:93:2:85:C00000:0:0:0:" + }, + "K1CLA_hd": { + "tname": "kabel eins CLASSICS", + "ename": "", + "id": "K1CLA", + "service": "" + }, + "ALPHA_sd": { + "tname": "ARD-alpha", + "ename": "ARD-alpha bis 14.12.2021 zu HD wechseln", + "id": "ALPHA", + "service": "1:0:1:6F47:445:1:C00000:0:0:0:" + }, + "NHK_uhd": { + "tname": "NHK WORLD TV", + "ename": "", + "id": "NHK", + "service": "" + }, + "RMTV_hd": { + "tname": "rheinmain tv", + "ename": "", + "id": "RMTV", + "service": "" + }, + "PRO7_uhd": { + "tname": "ProSieben", + "ename": "", + "id": "PRO7", + "service": "" + }, + "RNF_uhd": { + "tname": "Rhein-Neckar Fernsehen", + "ename": "", + "id": "RNF", + "service": "" + }, + "TNT-C_sd": { + "tname": "Warner TV Comedy", + "ename": "", + "id": "TNT-C", + "service": "" + }, + "ALJAZ_hd": { + "tname": "Al Jazeera", + "ename": "Al Jazeera English HD", + "id": "ALJAZ", + "service": "1:0:19:13A7:3EA:1:C00000:0:0:0:" + }, + "VOX_hd": { + "tname": "VOX", + "ename": "VOX HD", + "id": "VOX", + "service": "1:0:19:EF11:421:1:C00000:0:0:0:" + }, + "ORF2_uhd": { + "tname": "ORF 2", + "ename": "", + "id": "ORF2", + "service": "" + }, + "BIBEL_uhd": { + "tname": "Bibel TV", + "ename": "", + "id": "BIBEL", + "service": "" + }, + "SKYSPL_sd": { + "tname": "Sky Sport Premier League", + "ename": "", + "id": "SKYSPL", + "service": "" + }, + "SAT1_uhd": { + "tname": "SAT.1", + "ename": "", + "id": "SAT1", + "service": "" + }, + "AMS_uhd": { + "tname": "Auto Motor und Sport", + "ename": "", + "id": "AMS", + "service": "" + }, + "SKYSG_hd": { + "tname": "Sky Sport Golf", + "ename": "Sky Sport Golf HD", + "id": "SKYSG", + "service": "1:0:19:90:D:85:C00000:0:0:0:" + }, + "UHD1_hd": { + "tname": "UHD1", + "ename": "", + "id": "UHD1", + "service": "" + }, + "FRA5_sd": { + "tname": "France 5", + "ename": "FRANCE 5", + "id": "FRA5", + "service": "1:0:19:2330:442:1:C00000:0:0:0:" + }, + "FRA4_hd": { + "tname": "France 4", + "ename": "", + "id": "FRA4", + "service": "" + }, + "SKY-D_sd": { + "tname": "Sky Documentaries", + "ename": "", + "id": "SKY-D", + "service": "" + }, + "TAG24_sd": { + "tname": "tagesschau 24", + "ename": "tagesschau24", + "id": "TAG24", + "service": "1:0:1:7031:41B:1:C00000:0:0:0:" + }, + "SKYF1_sd": { + "tname": "SKY Sport F1", + "ename": "", + "id": "SKYF1", + "service": "" + }, + "GOLD_uhd": { + "tname": "GoldStar TV", + "ename": "", + "id": "GOLD", + "service": "" + }, + "SAT1E_sd": { + "tname": "SAT.1 emotions", + "ename": "SAT.1 emotions", + "id": "SAT1E", + "service": "1:0:16:14C1:407:1:C00000:0:0:0:" + }, + "EURON_uhd": { + "tname": "euronews", + "ename": "", + "id": "EURON", + "service": "" + }, + "RTL_hd": { + "tname": "RTL", + "ename": "RTL HD", + "id": "RTL", + "service": "1:0:19:EF10:421:1:C00000:0:0:0:" + }, + "TMAX_sd": { + "tname": "Turkmax Gurme", + "ename": "", + "id": "TMAX", + "service": "" + }, + "HEIMA_uhd": { + "tname": "Heimatkanal", + "ename": "", + "id": "HEIMA", + "service": "" + }, + "SWR_uhd": { + "tname": "SWR/SR", + "ename": "", + "id": "SWR", + "service": "" + }, + "ARTE_uhd": { + "tname": "ARTE", + "ename": "", + "id": "ARTE", + "service": "" + }, + "CNBC_hd": { + "tname": "CNBC", + "ename": "CNBC HD", + "id": "CNBC", + "service": "1:0:19:7D:9:85:C00000:0:0:0:" + }, + "K1DOKU_hd": { + "tname": "kabel eins Doku", + "ename": "", + "id": "K1DOKU", + "service": "" + }, + "SUPER_uhd": { + "tname": "SUPER RTL", + "ename": "", + "id": "SUPER", + "service": "" + }, + "WDWTV_sd": { + "tname": "Welt der Wunder TV", + "ename": "Welt der Wunder", + "id": "WDWTV", + "service": "1:0:1:332F:45B:1:C00000:0:0:0:" + }, + "VOX_sd": { + "tname": "VOX", + "ename": "VOX", + "id": "VOX", + "service": "1:0:1:2F1C:441:1:C00000:0:0:0:" + }, + "SKY-D_hd": { + "tname": "Sky Documentaries", + "ename": "Sky Documentaries HD", + "id": "SKY-D", + "service": "1:0:19:10:3:85:C00000:0:0:0:" + }, + "TLC_sd": { + "tname": "TLC", + "ename": "TLC", + "id": "TLC", + "service": "1:0:1:304:5:85:C00000:0:0:0:" + }, + "K1_uhd": { + "tname": "kabel eins", + "ename": "", + "id": "K1", + "service": "" + }, + "SWR_hd": { + "tname": "SWR/SR", + "ename": "SWR BW HD", + "id": "SWR", + "service": "1:0:19:283F:3FB:1:C00000:0:0:0:" + }, + "RNF_hd": { + "tname": "Rhein-Neckar Fernsehen", + "ename": "", + "id": "RNF", + "service": "" + }, + "CH21_hd": { + "tname": "Channel21", + "ename": "Channel21 HD", + "id": "CH21", + "service": "1:0:19:2778:409:1:C00000:0:0:0:" + }, + "ARTE_hd": { + "tname": "ARTE", + "ename": "arte HD", + "id": "ARTE", + "service": "1:0:19:283E:3FB:1:C00000:0:0:0:" + }, + "QVCP_sd": { + "tname": "QVC2", + "ename": "QVC2", + "id": "QVCP", + "service": "1:0:1:D42:454:1:C00000:0:0:0:" + }, + "RTLPL_uhd": { + "tname": "RTLup", + "ename": "", + "id": "RTLPL", + "service": "" + }, + "WELT_sd": { + "tname": "WELT", + "ename": "WELT", + "id": "WELT", + "service": "1:0:1:445F:453:1:C00000:0:0:0:" + }, + "PBOY_sd": { + "tname": "Playboy TV", + "ename": "PLAYBOY TV", + "id": "PBOY", + "service": "1:0:1:778B:424:1:C00000:0:0:0:" + }, + "HR_uhd": { + "tname": "HR", + "ename": "", + "id": "HR", + "service": "" + }, + "ROM_sd": { + "tname": "Romance TV", + "ename": "Romance TV", + "id": "ROM", + "service": "1:0:16:206:2:85:C00000:0:0:0:" + }, + "SPTVW_hd": { + "tname": "Curiosity Channel", + "ename": "", + "id": "SPTVW", + "service": "" + }, + "TNT-C_hd": { + "tname": "Warner TV Comedy", + "ename": "Warner TV Comedy HD", + "id": "TNT-C", + "service": "1:0:19:88:B:85:C00000:0:0:0:" + }, + "RTL-C_sd": { + "tname": "RTL Crime", + "ename": "", + "id": "RTL-C", + "service": "" + }, + "CPLUSS_uhd": { + "tname": "Canal+ Sport", + "ename": "", + "id": "CPLUSS", + "service": "" + }, + "QVCP_uhd": { + "tname": "QVC2", + "ename": "QVC ZWEI UHD", + "id": "QVCP", + "service": "1:0:1F:7DA:449:1:C00000:0:0:0:" + }, + "PBOY_hd": { + "tname": "Playboy TV", + "ename": "", + "id": "PBOY", + "service": "" + }, + "CRIN_sd": { + "tname": "Crime + Investigation", + "ename": "12382H SID 0x192", + "id": "CRIN", + "service": "1:0:16:192:B:85:C00000:0:0:0:" + }, + "BR_hd": { + "tname": "BR", + "ename": "BR Fernsehen Nord HD", + "id": "BR", + "service": "1:0:19:2856:401:1:C00000:0:0:0:" + }, + "CNN_hd": { + "tname": "CNN International", + "ename": "", + "id": "CNN", + "service": "" + }, + "RBTV_hd": { + "tname": "Rocket Beans TV", + "ename": "", + "id": "RBTV", + "service": "" + }, + "ORFSP_uhd": { + "tname": "ORF SPORT +", + "ename": "", + "id": "ORFSP", + "service": "" + }, + "NOWUS_uhd": { + "tname": "NOW US", + "ename": "", + "id": "NOWUS", + "service": "" + }, + "CIN24_uhd": { + "tname": "Sky Cinema Premieren +24", + "ename": "", + "id": "CIN24", + "service": "" + }, + "HEIMA_sd": { + "tname": "Heimatkanal", + "ename": "Heimatkanal", + "id": "HEIMA", + "service": "1:0:16:16:2:85:C00000:0:0:0:" + }, + "SP-GE_uhd": { + "tname": "SPIEGEL Geschichte", + "ename": "", + "id": "SP-GE", + "service": "" + }, + "SKYSH_hd": { + "tname": "sky showcase", + "ename": "Sky Showcase HD", + "id": "SKYSH", + "service": "1:0:19:8E:B:85:C00000:0:0:0:" + }, + "NICK_sd": { + "tname": "nick/MTV+", + "ename": "Nick/Comedy Central+1", + "id": "NICK", + "service": "1:0:1:7008:436:1:C00000:0:0:0:" + }, + "EURO-S_sd": { + "tname": "Euro Star", + "ename": "", + "id": "EURO-S", + "service": "" + }, + "C-NET_uhd": { + "tname": "Cartoon Network", + "ename": "", + "id": "C-NET", + "service": "" + }, + "SKYAT_hd": { + "tname": "Sky Atlantic HD", + "ename": "Sky Atlantic HD", + "id": "SKYAT", + "service": "1:0:19:6E:D:85:C00000:0:0:0:" + }, + "FATV_sd": { + "tname": "Fashion TV", + "ename": "", + "id": "FATV", + "service": "" + }, + "WDR_sd": { + "tname": "WDR", + "ename": "WDR Bielefeld", + "id": "WDR", + "service": "1:0:1:6E92:4B1:1:C00000:0:0:0:" + }, + "SKYST_sd": { + "tname": "Sky Sport Tennis", + "ename": "Sky Sport Tennis", + "id": "SKYST", + "service": "1:0:16:DE:2:85:C00000:0:0:0:" + }, + "NTV_hd": { + "tname": "n-tv", + "ename": "ntv HD", + "id": "NTV", + "service": "1:0:19:EF14:421:1:C00000:0:0:0:" + }, + "SILVE_uhd": { + "tname": "Silverline", + "ename": "", + "id": "SILVE", + "service": "" + }, + "N3_sd": { + "tname": "NDR", + "ename": "NDR FS HH", + "id": "N3", + "service": "1:0:1:6E41:431:1:C00000:0:0:0:" + }, + "BBC_sd": { + "tname": "BBC World News", + "ename": "", + "id": "BBC", + "service": "" + }, + "EURO-D_uhd": { + "tname": "Euro D", + "ename": "", + "id": "EURO-D", + "service": "" + }, + "EOTV_sd": { + "tname": "More than Sports TV", + "ename": "", + "id": "EOTV", + "service": "" + }, + "NICKJ_sd": { + "tname": "Nick Jr.", + "ename": "Nick.Jr.", + "id": "NICKJ", + "service": "1:0:1:6FFB:436:1:C00000:0:0:0:" + }, + "CIN24_hd": { + "tname": "Sky Cinema Premieren +24", + "ename": "Sky Cinema Premieren +24 HD", + "id": "CIN24", + "service": "1:0:19:87:B:85:C00000:0:0:0:" + }, + "ARD_uhd": { + "tname": "Das Erste", + "ename": "", + "id": "ARD", + "service": "" + }, + "RTL_uhd": { + "tname": "RTL", + "ename": "RTL UHD", + "id": "RTL", + "service": "1:0:1F:307A:3F5:1:C00000:0:0:0:" + }, + "HEIMA_hd": { + "tname": "Heimatkanal", + "ename": "", + "id": "HEIMA", + "service": "" + }, + "CIN_uhd": { + "tname": "Sky Cinema Premieren", + "ename": "", + "id": "CIN", + "service": "" + }, + "N24DOKU_uhd": { + "tname": "N24 Doku", + "ename": "", + "id": "N24DOKU", + "service": "" + }, + "3SAT_uhd": { + "tname": "3sat", + "ename": "", + "id": "3SAT", + "service": "" + }, + "FRA5_uhd": { + "tname": "France 5", + "ename": "", + "id": "FRA5", + "service": "" + }, + "DMF_hd": { + "tname": "Deutsches Musik Fernsehen", + "ename": "", + "id": "DMF", + "service": "" + }, + "TLC_hd": { + "tname": "TLC", + "ename": "TLC HD", + "id": "TLC", + "service": "1:0:19:2774:409:1:C00000:0:0:0:" + }, + "AMS_sd": { + "tname": "Auto Motor und Sport", + "ename": "", + "id": "AMS", + "service": "" + }, + "SUPER_hd": { + "tname": "SUPER RTL", + "ename": "SUPER RTL HD", + "id": "SUPER", + "service": "1:0:19:2E9B:411:1:C00000:0:0:0:" + }, + "ARTE_sd": { + "tname": "ARTE", + "ename": "arte", + "id": "ARTE", + "service": "1:0:1:7034:41B:1:C00000:0:0:0:" + }, + "DMAX_uhd": { + "tname": "DMAX", + "ename": "", + "id": "DMAX", + "service": "" + }, + "PHOEN_uhd": { + "tname": "PHOENIX", + "ename": "", + "id": "PHOEN", + "service": "" + } +} diff --git a/channels/tvspielfilm_channel_list_all.json b/channels/tvspielfilm_channel_list_all.json new file mode 100644 index 0000000..2b1292c --- /dev/null +++ b/channels/tvspielfilm_channel_list_all.json @@ -0,0 +1,209 @@ +[ + "123TV_hd", + "13TH_hd", + "2NEO_hd", + "3PLUS_hd", + "3SAT_hd", + "ADULT_hd", + "ALJAZ_hd", + "ALPHA_hd", + "AMS_hd", + "ANIXE_hd", + "APLAN_hd", + "ARD_hd", + "ARTE_hd", + "ATV_hd", + "ATV2_hd", + "AXN_hd", + "BBC_hd", + "BBC-E_hd", + "BBC-N_hd", + "BBC1_hd", + "BBC2_hd", + "BBC4_hd", + "BE1_hd", + "BERG_hd", + "BIBEL_hd", + "BILD_hd", + "BLM_hd", + "BR_hd", + "BULI_hd", + "BUTV_hd", + "C-NET_hd", + "C5_hd", + "CC_hd", + "CH21_hd", + "CIN_hd", + "CIN24_hd", + "CLASS_hd", + "CNBC_hd", + "CNN_hd", + "CNN-T_hd", + "CPLUS_hd", + "CPLUSC_hd", + "CPLUSS_hd", + "CRIN_hd", + "DAZN_hd", + "DISNE_hd", + "DMAX_hd", + "DMC_hd", + "DMF_hd", + "DR1_hd", + "DR2_hd", + "DWTV_hd", + "EOTV_hd", + "ES1_hd", + "EURO_hd", + "EURO-D_hd", + "EURO-S_hd", + "EURO2_hd", + "EURON_hd", + "EX-SP_hd", + "FATV_hd", + "FES_hd", + "FFTV_hd", + "FR24E_hd", + "FR24F_hd", + "FRA2_hd", + "FRA3_hd", + "FRA4_hd", + "FRA5_hd", + "GEO_hd", + "GOLD_hd", + "GUSTO_hd", + "HDDIS_hd", + "HEALTH_hd", + "HEIMA_hd", + "HGTV_hd", + "HH1_hd", + "HISHD_hd", + "HR_hd", + "HSE_hd", + "JUKE_hd", + "K1_hd", + "K1CLA_hd", + "K1DOKU_hd", + "KIKA_hd", + "KINOW_hd", + "KTV_hd", + "LAUNE_hd", + "LEITV_hd", + "LUSTP_hd", + "MAPO_hd", + "MASPO_hd", + "MDR_hd", + "MEZZO_hd", + "MOVTV_hd", + "MTV_hd", + "MTV-B_hd", + "MTV-D_hd", + "MTV-H_hd", + "MTV-L_hd", + "N-GHD_hd", + "N-GW_hd", + "N24DOKU_hd", + "N3_hd", + "NAUCH_hd", + "NHK_hd", + "NICK_hd", + "NICKJ_hd", + "NICKT_hd", + "NOWUS_hd", + "NTV_hd", + "OE24TV_hd", + "ORF1_hd", + "ORF2_hd", + "ORF3_hd", + "ORFSP_hd", + "PASS_hd", + "PBOY_hd", + "PHOEN_hd", + "PRO7_hd", + "PRO7F_hd", + "PRO7M_hd", + "PULS4_hd", + "PULS8_hd", + "QVC_hd", + "QVCP_hd", + "RBB_hd", + "RBTV_hd", + "RIC_hd", + "RMTV_hd", + "RNF_hd", + "ROM_hd", + "RTL_hd", + "RTL-C_hd", + "RTL-L_hd", + "RTL-N_hd", + "RTL2_hd", + "RTLPL_hd", + "S1PLU_hd", + "SAT1_hd", + "SAT1E_hd", + "SAT1G_hd", + "SCIFI_hd", + "SERVU_hd", + "SERVUSA_hd", + "SF1_hd", + "SF2_hd", + "SHOT_hd", + "SILVE_hd", + "SIXX_hd", + "SKLAR_hd", + "SKY-A_hd", + "SKY-C_hd", + "SKY-CO_hd", + "SKY-CR_hd", + "SKY-D_hd", + "SKY-F_hd", + "SKY-H_hd", + "SKY-K_hd", + "SKY-N_hd", + "SKY-NA_hd", + "SKY1_hd", + "SKYAT_hd", + "SKYCS_hd", + "SKYF1_hd", + "SKYRP_hd", + "SKYSG_hd", + "SKYSH_hd", + "SKYSM_hd", + "SKYSPL_hd", + "SKYST_hd", + "SKYSTE_hd", + "SKYTH_hd", + "SNHD_hd", + "SONY_hd", + "SP-GE_hd", + "SPO-A_hd", + "SPO-D_hd", + "SPORT_hd", + "SPTVW_hd", + "STTV_hd", + "SUPER_hd", + "SWR_hd", + "TAG24_hd", + "TELE5_hd", + "TLC_hd", + "TMAX_hd", + "TNT-C_hd", + "TNT-F_hd", + "TNT-S_hd", + "TOGGO_hd", + "TRACE_hd", + "TRAVELXP_hd", + "TV2_hd", + "TV5_hd", + "TVB_hd", + "TVM_hd", + "UHD1_hd", + "UNIVE_hd", + "VH1_hd", + "VOX_hd", + "VOXUP_hd", + "WDR_hd", + "WDWTV_hd", + "WELT_hd", + "ZDF_hd", + "ZINFO_hd" +] diff --git a/channels/tvspielfilm_channel_list_default.json b/channels/tvspielfilm_channel_list_default.json new file mode 100755 index 0000000..6af23f3 --- /dev/null +++ b/channels/tvspielfilm_channel_list_default.json @@ -0,0 +1 @@ +["ARD_hd", "ZDF_hd", "RTL_hd", "SAT1_hd", "PRO7_hd", "K1_hd", "RTL2_hd", "VOX_hd", "TELE5_hd", "3SAT_hd", "ARTE_hd", "2NEO_hd", "FES_hd", "RTL-N_hd", "DMAX_hd", "SIXX_hd", "SAT1G_hd", "PRO7M_hd"] diff --git a/channels/tvspielfilm_channel_list_sky.json b/channels/tvspielfilm_channel_list_sky.json new file mode 100644 index 0000000..6343500 --- /dev/null +++ b/channels/tvspielfilm_channel_list_sky.json @@ -0,0 +1,19 @@ +[ + "SKY-A_hd", + "SKY-CR_hd", + "SKY-D_hd", + "SKY-F_hd", + "SKY-K_hd", + "SKY-N_hd", + "SKY-NA_hd", + "SKY1_hd", + "SKYAT_hd", + "SKYF1_hd", + "SKYRP_hd", + "SKYSG_hd", + "SKYSH_hd", + "SKYSM_hd", + "SKYSPL_hd", + "SKYST_hd", + "SKYSTE_hd" +] diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..531f723 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,15 @@ + + +

TVMagazineCockpit Installation

+ To install the TVMagazineCockpit plugin execute the following commands in a telnet console on your dreambox: + + The installation script will also install a feed source that enables a convenient upgrade to the latest version with the following commands or automatically as part of a DreamOS upgrade: + + + diff --git a/docs/tvmagazinecockpit.sh b/docs/tvmagazinecockpit.sh new file mode 100755 index 0000000..b512d54 --- /dev/null +++ b/docs/tvmagazinecockpit.sh @@ -0,0 +1,8 @@ +#!/bin/sh +rm -f /etc/apt/sources.list.d/cockpit.list +apt-get update +apt-get install -y apt-transport-https +echo deb [trusted=yes] https://apt.fury.io/dream-alpha ./ > /etc/apt/sources.list.d/cockpit.list +apt-get update +apt-get install -y enigma2-plugin-extensions-tvmagazinecockpit +systemctl restart enigma2 diff --git a/logos/123TV.png b/logos/123TV.png new file mode 100755 index 0000000..ef4670a Binary files /dev/null and b/logos/123TV.png differ diff --git a/logos/13TH.png b/logos/13TH.png new file mode 100755 index 0000000..fd21201 Binary files /dev/null and b/logos/13TH.png differ diff --git a/logos/2NEO.png b/logos/2NEO.png new file mode 100755 index 0000000..804122a Binary files /dev/null and b/logos/2NEO.png differ diff --git a/logos/3PLUS.png b/logos/3PLUS.png new file mode 100755 index 0000000..1f93dcb Binary files /dev/null and b/logos/3PLUS.png differ diff --git a/logos/3SAT.png b/logos/3SAT.png new file mode 100755 index 0000000..d0141c5 Binary files /dev/null and b/logos/3SAT.png differ diff --git a/logos/ADULT.png b/logos/ADULT.png new file mode 100755 index 0000000..5b1366b Binary files /dev/null and b/logos/ADULT.png differ diff --git a/logos/AETV.png b/logos/AETV.png new file mode 100755 index 0000000..e7bf93f Binary files /dev/null and b/logos/AETV.png differ diff --git a/logos/ALJAZ.png b/logos/ALJAZ.png new file mode 100755 index 0000000..3233945 Binary files /dev/null and b/logos/ALJAZ.png differ diff --git a/logos/ALPHA.png b/logos/ALPHA.png new file mode 100755 index 0000000..2f722b5 Binary files /dev/null and b/logos/ALPHA.png differ diff --git a/logos/AMS.png b/logos/AMS.png new file mode 100755 index 0000000..023ff71 Binary files /dev/null and b/logos/AMS.png differ diff --git a/logos/ANIXE.png b/logos/ANIXE.png new file mode 100755 index 0000000..70c56d1 Binary files /dev/null and b/logos/ANIXE.png differ diff --git a/logos/APLAN.png b/logos/APLAN.png new file mode 100755 index 0000000..da460cb Binary files /dev/null and b/logos/APLAN.png differ diff --git a/logos/ARD.png b/logos/ARD.png new file mode 100755 index 0000000..29549ed Binary files /dev/null and b/logos/ARD.png differ diff --git a/logos/ARTE.png b/logos/ARTE.png new file mode 100755 index 0000000..9e93807 Binary files /dev/null and b/logos/ARTE.png differ diff --git a/logos/ARTS.png b/logos/ARTS.png new file mode 100755 index 0000000..316b9a6 Binary files /dev/null and b/logos/ARTS.png differ diff --git a/logos/ATV-A.png b/logos/ATV-A.png new file mode 100755 index 0000000..9301a40 Binary files /dev/null and b/logos/ATV-A.png differ diff --git a/logos/ATV.png b/logos/ATV.png new file mode 100755 index 0000000..c8f0d54 Binary files /dev/null and b/logos/ATV.png differ diff --git a/logos/ATV2.png b/logos/ATV2.png new file mode 100755 index 0000000..f8e4ead Binary files /dev/null and b/logos/ATV2.png differ diff --git a/logos/AXN.png b/logos/AXN.png new file mode 100755 index 0000000..cea4ee2 Binary files /dev/null and b/logos/AXN.png differ diff --git a/logos/BBC-E.png b/logos/BBC-E.png new file mode 100755 index 0000000..d735773 Binary files /dev/null and b/logos/BBC-E.png differ diff --git a/logos/BBC-N.png b/logos/BBC-N.png new file mode 100755 index 0000000..03398a5 Binary files /dev/null and b/logos/BBC-N.png differ diff --git a/logos/BBC.png b/logos/BBC.png new file mode 100755 index 0000000..c43766e Binary files /dev/null and b/logos/BBC.png differ diff --git a/logos/BBC1.png b/logos/BBC1.png new file mode 100755 index 0000000..8141bd8 Binary files /dev/null and b/logos/BBC1.png differ diff --git a/logos/BBC2.png b/logos/BBC2.png new file mode 100755 index 0000000..3533ead Binary files /dev/null and b/logos/BBC2.png differ diff --git a/logos/BBC4.png b/logos/BBC4.png new file mode 100755 index 0000000..15ea3f5 Binary files /dev/null and b/logos/BBC4.png differ diff --git a/logos/BE1.png b/logos/BE1.png new file mode 100755 index 0000000..acefbd2 Binary files /dev/null and b/logos/BE1.png differ diff --git a/logos/BERG.png b/logos/BERG.png new file mode 100755 index 0000000..2650972 Binary files /dev/null and b/logos/BERG.png differ diff --git a/logos/BIBEL.png b/logos/BIBEL.png new file mode 100755 index 0000000..97b68ab Binary files /dev/null and b/logos/BIBEL.png differ diff --git a/logos/BILD.png b/logos/BILD.png new file mode 100755 index 0000000..bcdd364 Binary files /dev/null and b/logos/BILD.png differ diff --git a/logos/BLIZZ.png b/logos/BLIZZ.png new file mode 100755 index 0000000..2f81a31 Binary files /dev/null and b/logos/BLIZZ.png differ diff --git a/logos/BLM.png b/logos/BLM.png new file mode 100755 index 0000000..740ba73 Binary files /dev/null and b/logos/BLM.png differ diff --git a/logos/BLUM.png b/logos/BLUM.png new file mode 100755 index 0000000..d053983 Binary files /dev/null and b/logos/BLUM.png differ diff --git a/logos/BLUM2.png b/logos/BLUM2.png new file mode 100755 index 0000000..236af41 Binary files /dev/null and b/logos/BLUM2.png differ diff --git a/logos/BLUM3.png b/logos/BLUM3.png new file mode 100755 index 0000000..39b9d2d Binary files /dev/null and b/logos/BLUM3.png differ diff --git a/logos/BOOM.png b/logos/BOOM.png new file mode 100755 index 0000000..e31c4a5 Binary files /dev/null and b/logos/BOOM.png differ diff --git a/logos/BR-N.png b/logos/BR-N.png new file mode 100755 index 0000000..930f52a Binary files /dev/null and b/logos/BR-N.png differ diff --git a/logos/BR-S.png b/logos/BR-S.png new file mode 100755 index 0000000..26b67f2 Binary files /dev/null and b/logos/BR-S.png differ diff --git a/logos/BR.png b/logos/BR.png new file mode 100755 index 0000000..9333601 Binary files /dev/null and b/logos/BR.png differ diff --git a/logos/BULI.png b/logos/BULI.png new file mode 100755 index 0000000..5aacf07 Binary files /dev/null and b/logos/BULI.png differ diff --git a/logos/BUTV.png b/logos/BUTV.png new file mode 100755 index 0000000..325893e Binary files /dev/null and b/logos/BUTV.png differ diff --git a/logos/C-NET.png b/logos/C-NET.png new file mode 100755 index 0000000..c007094 Binary files /dev/null and b/logos/C-NET.png differ diff --git a/logos/C5.png b/logos/C5.png new file mode 100755 index 0000000..232cae9 Binary files /dev/null and b/logos/C5.png differ diff --git a/logos/CC.png b/logos/CC.png new file mode 100755 index 0000000..b085f6d Binary files /dev/null and b/logos/CC.png differ diff --git a/logos/CENTE.png b/logos/CENTE.png new file mode 100755 index 0000000..1b19d13 Binary files /dev/null and b/logos/CENTE.png differ diff --git a/logos/CH21.png b/logos/CH21.png new file mode 100755 index 0000000..66e75f4 Binary files /dev/null and b/logos/CH21.png differ diff --git a/logos/CIN.png b/logos/CIN.png new file mode 100755 index 0000000..bd47175 Binary files /dev/null and b/logos/CIN.png differ diff --git a/logos/CIN1.png b/logos/CIN1.png new file mode 100755 index 0000000..e73990f Binary files /dev/null and b/logos/CIN1.png differ diff --git a/logos/CIN24.png b/logos/CIN24.png new file mode 100755 index 0000000..696196f Binary files /dev/null and b/logos/CIN24.png differ diff --git a/logos/CLASS.png b/logos/CLASS.png new file mode 100755 index 0000000..ec06c0e Binary files /dev/null and b/logos/CLASS.png differ diff --git a/logos/CNBC.png b/logos/CNBC.png new file mode 100755 index 0000000..38bedc0 Binary files /dev/null and b/logos/CNBC.png differ diff --git a/logos/CNN-M.png b/logos/CNN-M.png new file mode 100755 index 0000000..073d387 Binary files /dev/null and b/logos/CNN-M.png differ diff --git a/logos/CNN-T.png b/logos/CNN-T.png new file mode 100755 index 0000000..bc9ddfe Binary files /dev/null and b/logos/CNN-T.png differ diff --git a/logos/CNN.png b/logos/CNN.png new file mode 100755 index 0000000..b9088e0 Binary files /dev/null and b/logos/CNN.png differ diff --git a/logos/CPLUS.png b/logos/CPLUS.png new file mode 100755 index 0000000..d8b6960 Binary files /dev/null and b/logos/CPLUS.png differ diff --git a/logos/CPLUSC.png b/logos/CPLUSC.png new file mode 100755 index 0000000..c4c65ad Binary files /dev/null and b/logos/CPLUSC.png differ diff --git a/logos/CPLUSD.png b/logos/CPLUSD.png new file mode 100755 index 0000000..497bfac Binary files /dev/null and b/logos/CPLUSD.png differ diff --git a/logos/CPLUSS.png b/logos/CPLUSS.png new file mode 100755 index 0000000..38d2ac5 Binary files /dev/null and b/logos/CPLUSS.png differ diff --git a/logos/CRIN.png b/logos/CRIN.png new file mode 100755 index 0000000..89c3b12 Binary files /dev/null and b/logos/CRIN.png differ diff --git a/logos/DATV.png b/logos/DATV.png new file mode 100755 index 0000000..be5f186 Binary files /dev/null and b/logos/DATV.png differ diff --git a/logos/DAZN.png b/logos/DAZN.png new file mode 100755 index 0000000..c7d2878 Binary files /dev/null and b/logos/DAZN.png differ diff --git a/logos/DCM.png b/logos/DCM.png new file mode 100755 index 0000000..6fb03fe Binary files /dev/null and b/logos/DCM.png differ diff --git a/logos/DISNE.png b/logos/DISNE.png new file mode 100755 index 0000000..a5ceb9e Binary files /dev/null and b/logos/DISNE.png differ diff --git a/logos/DJUN.png b/logos/DJUN.png new file mode 100755 index 0000000..6c817a6 Binary files /dev/null and b/logos/DJUN.png differ diff --git a/logos/DMAX.png b/logos/DMAX.png new file mode 100755 index 0000000..6074946 Binary files /dev/null and b/logos/DMAX.png differ diff --git a/logos/DMC.png b/logos/DMC.png new file mode 100755 index 0000000..3c541fa Binary files /dev/null and b/logos/DMC.png differ diff --git a/logos/DMF.png b/logos/DMF.png new file mode 100755 index 0000000..416158d Binary files /dev/null and b/logos/DMF.png differ diff --git a/logos/DR1.png b/logos/DR1.png new file mode 100755 index 0000000..6e89089 Binary files /dev/null and b/logos/DR1.png differ diff --git a/logos/DR2.png b/logos/DR2.png new file mode 100755 index 0000000..ecf62f1 Binary files /dev/null and b/logos/DR2.png differ diff --git a/logos/DRTV.png b/logos/DRTV.png new file mode 100755 index 0000000..ed95fb0 Binary files /dev/null and b/logos/DRTV.png differ diff --git a/logos/DWF.png b/logos/DWF.png new file mode 100755 index 0000000..bd3ba4a Binary files /dev/null and b/logos/DWF.png differ diff --git a/logos/DWTV.png b/logos/DWTV.png new file mode 100755 index 0000000..bfc39ce Binary files /dev/null and b/logos/DWTV.png differ diff --git a/logos/DXD.png b/logos/DXD.png new file mode 100755 index 0000000..eb90a5e Binary files /dev/null and b/logos/DXD.png differ diff --git a/logos/E!.png b/logos/E!.png new file mode 100755 index 0000000..e974527 Binary files /dev/null and b/logos/E!.png differ diff --git a/logos/ENGB.png b/logos/ENGB.png new file mode 100755 index 0000000..702e399 Binary files /dev/null and b/logos/ENGB.png differ diff --git a/logos/EOTV.png b/logos/EOTV.png new file mode 100755 index 0000000..d5b4049 Binary files /dev/null and b/logos/EOTV.png differ diff --git a/logos/ES1.png b/logos/ES1.png new file mode 100755 index 0000000..e3a5d7a Binary files /dev/null and b/logos/ES1.png differ diff --git a/logos/EURO-D.png b/logos/EURO-D.png new file mode 100755 index 0000000..5179592 Binary files /dev/null and b/logos/EURO-D.png differ diff --git a/logos/EURO-S.png b/logos/EURO-S.png new file mode 100755 index 0000000..2468c88 Binary files /dev/null and b/logos/EURO-S.png differ diff --git a/logos/EURO.png b/logos/EURO.png new file mode 100755 index 0000000..46af26f Binary files /dev/null and b/logos/EURO.png differ diff --git a/logos/EURO2.png b/logos/EURO2.png new file mode 100755 index 0000000..7ca1b8f Binary files /dev/null and b/logos/EURO2.png differ diff --git a/logos/EURON.png b/logos/EURON.png new file mode 100755 index 0000000..40ed6df Binary files /dev/null and b/logos/EURON.png differ diff --git a/logos/EX-SP.png b/logos/EX-SP.png new file mode 100755 index 0000000..e9a5018 Binary files /dev/null and b/logos/EX-SP.png differ diff --git a/logos/FAMTV.png b/logos/FAMTV.png new file mode 100755 index 0000000..e17aa9f Binary files /dev/null and b/logos/FAMTV.png differ diff --git a/logos/FATV.png b/logos/FATV.png new file mode 100755 index 0000000..9347625 Binary files /dev/null and b/logos/FATV.png differ diff --git a/logos/FES.png b/logos/FES.png new file mode 100755 index 0000000..480d70d Binary files /dev/null and b/logos/FES.png differ diff --git a/logos/FFTV.png b/logos/FFTV.png new file mode 100755 index 0000000..2b8362a Binary files /dev/null and b/logos/FFTV.png differ diff --git a/logos/FLN.png b/logos/FLN.png new file mode 100755 index 0000000..9c79a8e Binary files /dev/null and b/logos/FLN.png differ diff --git a/logos/FOOD.png b/logos/FOOD.png new file mode 100755 index 0000000..d292a1a Binary files /dev/null and b/logos/FOOD.png differ diff --git a/logos/FOX.png b/logos/FOX.png new file mode 100755 index 0000000..5c5c091 Binary files /dev/null and b/logos/FOX.png differ diff --git a/logos/FR24E.png b/logos/FR24E.png new file mode 100755 index 0000000..58d94a5 Binary files /dev/null and b/logos/FR24E.png differ diff --git a/logos/FR24F.png b/logos/FR24F.png new file mode 100755 index 0000000..2d0f970 Binary files /dev/null and b/logos/FR24F.png differ diff --git a/logos/FRA2.png b/logos/FRA2.png new file mode 100755 index 0000000..06e2bf3 Binary files /dev/null and b/logos/FRA2.png differ diff --git a/logos/FRA3.png b/logos/FRA3.png new file mode 100755 index 0000000..b55c44f Binary files /dev/null and b/logos/FRA3.png differ diff --git a/logos/FRA4.png b/logos/FRA4.png new file mode 100755 index 0000000..0b1a97b Binary files /dev/null and b/logos/FRA4.png differ diff --git a/logos/FRA5.png b/logos/FRA5.png new file mode 100755 index 0000000..b305486 Binary files /dev/null and b/logos/FRA5.png differ diff --git a/logos/FRAO.png b/logos/FRAO.png new file mode 100755 index 0000000..f298aa8 Binary files /dev/null and b/logos/FRAO.png differ diff --git a/logos/FREESHOP.png b/logos/FREESHOP.png new file mode 100755 index 0000000..f865006 Binary files /dev/null and b/logos/FREESHOP.png differ diff --git a/logos/GEO.png b/logos/GEO.png new file mode 100755 index 0000000..05315ff Binary files /dev/null and b/logos/GEO.png differ diff --git a/logos/GOLD.png b/logos/GOLD.png new file mode 100755 index 0000000..20bf154 Binary files /dev/null and b/logos/GOLD.png differ diff --git a/logos/GUSTO.png b/logos/GUSTO.png new file mode 100755 index 0000000..97572ab Binary files /dev/null and b/logos/GUSTO.png differ diff --git a/logos/HDDIS.png b/logos/HDDIS.png new file mode 100755 index 0000000..384bcc1 Binary files /dev/null and b/logos/HDDIS.png differ diff --git a/logos/HDSPO.png b/logos/HDSPO.png new file mode 100755 index 0000000..b45f853 Binary files /dev/null and b/logos/HDSPO.png differ diff --git a/logos/HEALTH.png b/logos/HEALTH.png new file mode 100755 index 0000000..8148632 Binary files /dev/null and b/logos/HEALTH.png differ diff --git a/logos/HEIMA.png b/logos/HEIMA.png new file mode 100755 index 0000000..5642c74 Binary files /dev/null and b/logos/HEIMA.png differ diff --git a/logos/HGTV.png b/logos/HGTV.png new file mode 100755 index 0000000..e409e4d Binary files /dev/null and b/logos/HGTV.png differ diff --git a/logos/HH1.png b/logos/HH1.png new file mode 100755 index 0000000..3c203e5 Binary files /dev/null and b/logos/HH1.png differ diff --git a/logos/HISHD.png b/logos/HISHD.png new file mode 100755 index 0000000..9c1ac24 Binary files /dev/null and b/logos/HISHD.png differ diff --git a/logos/HR.png b/logos/HR.png new file mode 100755 index 0000000..68eb371 Binary files /dev/null and b/logos/HR.png differ diff --git a/logos/HSE.png b/logos/HSE.png new file mode 100755 index 0000000..4fa7fcd Binary files /dev/null and b/logos/HSE.png differ diff --git a/logos/JUKE.png b/logos/JUKE.png new file mode 100755 index 0000000..4f79e21 Binary files /dev/null and b/logos/JUKE.png differ diff --git a/logos/JUNIO.png b/logos/JUNIO.png new file mode 100755 index 0000000..7a2e17d Binary files /dev/null and b/logos/JUNIO.png differ diff --git a/logos/K1.png b/logos/K1.png new file mode 100755 index 0000000..b4248da Binary files /dev/null and b/logos/K1.png differ diff --git a/logos/K1CLA.png b/logos/K1CLA.png new file mode 100755 index 0000000..454e7c5 Binary files /dev/null and b/logos/K1CLA.png differ diff --git a/logos/K1DOKU.png b/logos/K1DOKU.png new file mode 100755 index 0000000..3488127 Binary files /dev/null and b/logos/K1DOKU.png differ diff --git a/logos/KIKA.png b/logos/KIKA.png new file mode 100755 index 0000000..e42e652 Binary files /dev/null and b/logos/KIKA.png differ diff --git a/logos/KINOW.png b/logos/KINOW.png new file mode 100755 index 0000000..d01cca9 Binary files /dev/null and b/logos/KINOW.png differ diff --git a/logos/KTV.png b/logos/KTV.png new file mode 100755 index 0000000..a6b43f2 Binary files /dev/null and b/logos/KTV.png differ diff --git a/logos/LAUNE.png b/logos/LAUNE.png new file mode 100755 index 0000000..a06b1a3 Binary files /dev/null and b/logos/LAUNE.png differ diff --git a/logos/LEITV.png b/logos/LEITV.png new file mode 100755 index 0000000..d702683 Binary files /dev/null and b/logos/LEITV.png differ diff --git a/logos/LUSTP.png b/logos/LUSTP.png new file mode 100755 index 0000000..569add6 Binary files /dev/null and b/logos/LUSTP.png differ diff --git a/logos/MAPO.png b/logos/MAPO.png new file mode 100755 index 0000000..2955211 Binary files /dev/null and b/logos/MAPO.png differ diff --git a/logos/MASPO.png b/logos/MASPO.png new file mode 100755 index 0000000..3f6e449 Binary files /dev/null and b/logos/MASPO.png differ diff --git a/logos/MDR-SN.png b/logos/MDR-SN.png new file mode 100755 index 0000000..ca09bec Binary files /dev/null and b/logos/MDR-SN.png differ diff --git a/logos/MDR-ST.png b/logos/MDR-ST.png new file mode 100755 index 0000000..44b02cd Binary files /dev/null and b/logos/MDR-ST.png differ diff --git a/logos/MDR-TH.png b/logos/MDR-TH.png new file mode 100755 index 0000000..8552603 Binary files /dev/null and b/logos/MDR-TH.png differ diff --git a/logos/MDR.png b/logos/MDR.png new file mode 100755 index 0000000..5e2bbb0 Binary files /dev/null and b/logos/MDR.png differ diff --git a/logos/MELODIETV.png b/logos/MELODIETV.png new file mode 100755 index 0000000..55e74dc Binary files /dev/null and b/logos/MELODIETV.png differ diff --git a/logos/MEZZO.png b/logos/MEZZO.png new file mode 100755 index 0000000..1caf4a9 Binary files /dev/null and b/logos/MEZZO.png differ diff --git a/logos/MFTV1.png b/logos/MFTV1.png new file mode 100755 index 0000000..553568c --- /dev/null +++ b/logos/MFTV1.png @@ -0,0 +1,2 @@ + +AccessDeniedAccess DeniedMD9S2GW7F0CSKRHFMvMdp5u4+fIGFFZDW9IsW+cA82tZawH91tm7FAuzcK4gBP0kIpBaFFs3738CZu64wbK1f6c3r7o= \ No newline at end of file diff --git a/logos/MOTOR.png b/logos/MOTOR.png new file mode 100755 index 0000000..bd88732 Binary files /dev/null and b/logos/MOTOR.png differ diff --git a/logos/MOVTV.png b/logos/MOVTV.png new file mode 100755 index 0000000..f00e913 Binary files /dev/null and b/logos/MOVTV.png differ diff --git a/logos/MTV-B.png b/logos/MTV-B.png new file mode 100755 index 0000000..848e585 Binary files /dev/null and b/logos/MTV-B.png differ diff --git a/logos/MTV-D.png b/logos/MTV-D.png new file mode 100755 index 0000000..e68b243 Binary files /dev/null and b/logos/MTV-D.png differ diff --git a/logos/MTV-H.png b/logos/MTV-H.png new file mode 100755 index 0000000..867a128 Binary files /dev/null and b/logos/MTV-H.png differ diff --git a/logos/MTV-L.png b/logos/MTV-L.png new file mode 100755 index 0000000..056cc5f Binary files /dev/null and b/logos/MTV-L.png differ diff --git a/logos/MTV.png b/logos/MTV.png new file mode 100755 index 0000000..e775686 Binary files /dev/null and b/logos/MTV.png differ diff --git a/logos/MUE2.png b/logos/MUE2.png new file mode 100755 index 0000000..cfd3b99 Binary files /dev/null and b/logos/MUE2.png differ diff --git a/logos/Makefile.am b/logos/Makefile.am new file mode 100644 index 0000000..e51c92b --- /dev/null +++ b/logos/Makefile.am @@ -0,0 +1,2 @@ +installdir = $(libdir)/enigma2/python/Plugins/Extensions/TVMagazineCockpit/logos +install_DATA = *.png diff --git a/logos/N-GHD.png b/logos/N-GHD.png new file mode 100755 index 0000000..3d0f2c4 Binary files /dev/null and b/logos/N-GHD.png differ diff --git a/logos/N-GW.png b/logos/N-GW.png new file mode 100755 index 0000000..9c807dd Binary files /dev/null and b/logos/N-GW.png differ diff --git a/logos/N24DOKU.png b/logos/N24DOKU.png new file mode 100755 index 0000000..3c93706 Binary files /dev/null and b/logos/N24DOKU.png differ diff --git a/logos/N3.png b/logos/N3.png new file mode 100755 index 0000000..72017e5 Binary files /dev/null and b/logos/N3.png differ diff --git a/logos/NAUCH.png b/logos/NAUCH.png new file mode 100755 index 0000000..7ef8d1f Binary files /dev/null and b/logos/NAUCH.png differ diff --git a/logos/NDR-HH.png b/logos/NDR-HH.png new file mode 100755 index 0000000..f8c8f60 Binary files /dev/null and b/logos/NDR-HH.png differ diff --git a/logos/NDR-MV.png b/logos/NDR-MV.png new file mode 100755 index 0000000..24f7ad6 Binary files /dev/null and b/logos/NDR-MV.png differ diff --git a/logos/NDR-NI.png b/logos/NDR-NI.png new file mode 100755 index 0000000..59019ef Binary files /dev/null and b/logos/NDR-NI.png differ diff --git a/logos/NDR-SH.png b/logos/NDR-SH.png new file mode 100755 index 0000000..00a4a95 Binary files /dev/null and b/logos/NDR-SH.png differ diff --git a/logos/NDR.png b/logos/NDR.png new file mode 100755 index 0000000..b1f4669 Binary files /dev/null and b/logos/NDR.png differ diff --git a/logos/NHK.png b/logos/NHK.png new file mode 100755 index 0000000..4b16ded Binary files /dev/null and b/logos/NHK.png differ diff --git a/logos/NICK.png b/logos/NICK.png new file mode 100755 index 0000000..386cafa Binary files /dev/null and b/logos/NICK.png differ diff --git a/logos/NICKJ.png b/logos/NICKJ.png new file mode 100755 index 0000000..1efe1e6 Binary files /dev/null and b/logos/NICKJ.png differ diff --git a/logos/NICKT.png b/logos/NICKT.png new file mode 100755 index 0000000..acef210 Binary files /dev/null and b/logos/NICKT.png differ diff --git a/logos/NL1.png b/logos/NL1.png new file mode 100755 index 0000000..4506086 Binary files /dev/null and b/logos/NL1.png differ diff --git a/logos/NL2.png b/logos/NL2.png new file mode 100755 index 0000000..84087a2 Binary files /dev/null and b/logos/NL2.png differ diff --git a/logos/NL3.png b/logos/NL3.png new file mode 100755 index 0000000..c35b7a5 Binary files /dev/null and b/logos/NL3.png differ diff --git a/logos/NOWUS.png b/logos/NOWUS.png new file mode 100755 index 0000000..16b3f08 Binary files /dev/null and b/logos/NOWUS.png differ diff --git a/logos/NTV.png b/logos/NTV.png new file mode 100755 index 0000000..ce9a786 Binary files /dev/null and b/logos/NTV.png differ diff --git a/logos/OE24TV.png b/logos/OE24TV.png new file mode 100755 index 0000000..ac7a5f4 Binary files /dev/null and b/logos/OE24TV.png differ diff --git a/logos/ORF1.png b/logos/ORF1.png new file mode 100755 index 0000000..0bbd870 Binary files /dev/null and b/logos/ORF1.png differ diff --git a/logos/ORF2.png b/logos/ORF2.png new file mode 100755 index 0000000..3426caf Binary files /dev/null and b/logos/ORF2.png differ diff --git a/logos/ORF3.png b/logos/ORF3.png new file mode 100755 index 0000000..3ec1688 Binary files /dev/null and b/logos/ORF3.png differ diff --git a/logos/ORFSP.png b/logos/ORFSP.png new file mode 100755 index 0000000..186509f Binary files /dev/null and b/logos/ORFSP.png differ diff --git a/logos/PASS.png b/logos/PASS.png new file mode 100755 index 0000000..33bcc05 Binary files /dev/null and b/logos/PASS.png differ diff --git a/logos/PBOY.png b/logos/PBOY.png new file mode 100755 index 0000000..05dc5e8 Binary files /dev/null and b/logos/PBOY.png differ diff --git a/logos/PHOEN.png b/logos/PHOEN.png new file mode 100755 index 0000000..af619d3 Binary files /dev/null and b/logos/PHOEN.png differ diff --git a/logos/PLANE.png b/logos/PLANE.png new file mode 100755 index 0000000..9d96e76 Binary files /dev/null and b/logos/PLANE.png differ diff --git a/logos/PRO7.png b/logos/PRO7.png new file mode 100755 index 0000000..44ce381 Binary files /dev/null and b/logos/PRO7.png differ diff --git a/logos/PRO7F.png b/logos/PRO7F.png new file mode 100755 index 0000000..6cf3125 Binary files /dev/null and b/logos/PRO7F.png differ diff --git a/logos/PRO7M.png b/logos/PRO7M.png new file mode 100755 index 0000000..3fee44b Binary files /dev/null and b/logos/PRO7M.png differ diff --git a/logos/PULS4.png b/logos/PULS4.png new file mode 100755 index 0000000..fedcadf Binary files /dev/null and b/logos/PULS4.png differ diff --git a/logos/PULS8.png b/logos/PULS8.png new file mode 100755 index 0000000..10995fc Binary files /dev/null and b/logos/PULS8.png differ diff --git a/logos/QVC.png b/logos/QVC.png new file mode 100755 index 0000000..95cee8f Binary files /dev/null and b/logos/QVC.png differ diff --git a/logos/QVCBS.png b/logos/QVCBS.png new file mode 100755 index 0000000..f27af48 Binary files /dev/null and b/logos/QVCBS.png differ diff --git a/logos/QVCP.png b/logos/QVCP.png new file mode 100755 index 0000000..58ab77f Binary files /dev/null and b/logos/QVCP.png differ diff --git a/logos/RB-TV.png b/logos/RB-TV.png new file mode 100755 index 0000000..10563e1 Binary files /dev/null and b/logos/RB-TV.png differ diff --git a/logos/RBB-B.png b/logos/RBB-B.png new file mode 100755 index 0000000..a2c6749 Binary files /dev/null and b/logos/RBB-B.png differ diff --git a/logos/RBB-BB.png b/logos/RBB-BB.png new file mode 100755 index 0000000..141444d Binary files /dev/null and b/logos/RBB-BB.png differ diff --git a/logos/RBB.png b/logos/RBB.png new file mode 100755 index 0000000..796312f Binary files /dev/null and b/logos/RBB.png differ diff --git a/logos/RBTV.png b/logos/RBTV.png new file mode 100755 index 0000000..d55b343 Binary files /dev/null and b/logos/RBTV.png differ diff --git a/logos/RCK.png b/logos/RCK.png new file mode 100755 index 0000000..9599a2b Binary files /dev/null and b/logos/RCK.png differ diff --git a/logos/REGBS.png b/logos/REGBS.png new file mode 100755 index 0000000..98c32ec Binary files /dev/null and b/logos/REGBS.png differ diff --git a/logos/REGIO.png b/logos/REGIO.png new file mode 100755 index 0000000..d92adbc Binary files /dev/null and b/logos/REGIO.png differ diff --git a/logos/RIC.png b/logos/RIC.png new file mode 100755 index 0000000..6dc963b Binary files /dev/null and b/logos/RIC.png differ diff --git a/logos/RMTV.png b/logos/RMTV.png new file mode 100755 index 0000000..672c92a Binary files /dev/null and b/logos/RMTV.png differ diff --git a/logos/RNF.png b/logos/RNF.png new file mode 100755 index 0000000..300a7f3 Binary files /dev/null and b/logos/RNF.png differ diff --git a/logos/ROM.png b/logos/ROM.png new file mode 100755 index 0000000..c98ad92 Binary files /dev/null and b/logos/ROM.png differ diff --git a/logos/RTL-C.png b/logos/RTL-C.png new file mode 100755 index 0000000..926fb2c Binary files /dev/null and b/logos/RTL-C.png differ diff --git a/logos/RTL-L.png b/logos/RTL-L.png new file mode 100755 index 0000000..a4d8f8f Binary files /dev/null and b/logos/RTL-L.png differ diff --git a/logos/RTL-N.png b/logos/RTL-N.png new file mode 100755 index 0000000..2b8ebc1 Binary files /dev/null and b/logos/RTL-N.png differ diff --git a/logos/RTL.png b/logos/RTL.png new file mode 100755 index 0000000..93b68f9 Binary files /dev/null and b/logos/RTL.png differ diff --git a/logos/RTL2.png b/logos/RTL2.png new file mode 100755 index 0000000..00f2e7e Binary files /dev/null and b/logos/RTL2.png differ diff --git a/logos/RTLPL.png b/logos/RTLPL.png new file mode 100755 index 0000000..859fdde Binary files /dev/null and b/logos/RTLPL.png differ diff --git a/logos/S1PLU.png b/logos/S1PLU.png new file mode 100755 index 0000000..48c23d4 Binary files /dev/null and b/logos/S1PLU.png differ diff --git a/logos/SACH.png b/logos/SACH.png new file mode 100755 index 0000000..92cab92 Binary files /dev/null and b/logos/SACH.png differ diff --git a/logos/SAT1.png b/logos/SAT1.png new file mode 100755 index 0000000..911fb01 Binary files /dev/null and b/logos/SAT1.png differ diff --git a/logos/SAT1E.png b/logos/SAT1E.png new file mode 100755 index 0000000..3de1e1a Binary files /dev/null and b/logos/SAT1E.png differ diff --git a/logos/SAT1G.png b/logos/SAT1G.png new file mode 100755 index 0000000..64dc5c5 Binary files /dev/null and b/logos/SAT1G.png differ diff --git a/logos/SCIFI.png b/logos/SCIFI.png new file mode 100755 index 0000000..87a4162 Binary files /dev/null and b/logos/SCIFI.png differ diff --git a/logos/SERVU.png b/logos/SERVU.png new file mode 100755 index 0000000..9337c52 Binary files /dev/null and b/logos/SERVU.png differ diff --git a/logos/SERVUSA.png b/logos/SERVUSA.png new file mode 100755 index 0000000..e7f875f --- /dev/null +++ b/logos/SERVUSA.png @@ -0,0 +1,2 @@ + +AccessDeniedAccess Denied2AD6SA2Y8GZD7N5FYrHbYtEc7tKYovPqAqbZuKrCDzSlj0Cjan9aPbMIExv16Re5lcEE1dGyUJD6NiVCDrufjEW4+pc= \ No newline at end of file diff --git a/logos/SF1.png b/logos/SF1.png new file mode 100755 index 0000000..65c2f4e Binary files /dev/null and b/logos/SF1.png differ diff --git a/logos/SF2.png b/logos/SF2.png new file mode 100755 index 0000000..2d20959 Binary files /dev/null and b/logos/SF2.png differ diff --git a/logos/SHD2.png b/logos/SHD2.png new file mode 100755 index 0000000..6cd3f58 Binary files /dev/null and b/logos/SHD2.png differ diff --git a/logos/SHOT.png b/logos/SHOT.png new file mode 100755 index 0000000..1890503 Binary files /dev/null and b/logos/SHOT.png differ diff --git a/logos/SILVE.png b/logos/SILVE.png new file mode 100755 index 0000000..d9ed099 Binary files /dev/null and b/logos/SILVE.png differ diff --git a/logos/SIXX.png b/logos/SIXX.png new file mode 100755 index 0000000..b98ce4d Binary files /dev/null and b/logos/SIXX.png differ diff --git a/logos/SKLAR.png b/logos/SKLAR.png new file mode 100755 index 0000000..bd276d3 Binary files /dev/null and b/logos/SKLAR.png differ diff --git a/logos/SKY-A.png b/logos/SKY-A.png new file mode 100755 index 0000000..4c0c04a Binary files /dev/null and b/logos/SKY-A.png differ diff --git a/logos/SKY-C.png b/logos/SKY-C.png new file mode 100755 index 0000000..f71f316 Binary files /dev/null and b/logos/SKY-C.png differ diff --git a/logos/SKY-CO.png b/logos/SKY-CO.png new file mode 100755 index 0000000..7270ab7 Binary files /dev/null and b/logos/SKY-CO.png differ diff --git a/logos/SKY-CR.png b/logos/SKY-CR.png new file mode 100755 index 0000000..1479e91 Binary files /dev/null and b/logos/SKY-CR.png differ diff --git a/logos/SKY-D.png b/logos/SKY-D.png new file mode 100755 index 0000000..de4d991 Binary files /dev/null and b/logos/SKY-D.png differ diff --git a/logos/SKY-E.png b/logos/SKY-E.png new file mode 100755 index 0000000..9f2b8f5 Binary files /dev/null and b/logos/SKY-E.png differ diff --git a/logos/SKY-F.png b/logos/SKY-F.png new file mode 100755 index 0000000..fc75dc8 Binary files /dev/null and b/logos/SKY-F.png differ diff --git a/logos/SKY-H.png b/logos/SKY-H.png new file mode 100755 index 0000000..ac706da Binary files /dev/null and b/logos/SKY-H.png differ diff --git a/logos/SKY-K.png b/logos/SKY-K.png new file mode 100755 index 0000000..98b7c00 Binary files /dev/null and b/logos/SKY-K.png differ diff --git a/logos/SKY-N.png b/logos/SKY-N.png new file mode 100755 index 0000000..84eca8b Binary files /dev/null and b/logos/SKY-N.png differ diff --git a/logos/SKY-NA.png b/logos/SKY-NA.png new file mode 100755 index 0000000..afe620a Binary files /dev/null and b/logos/SKY-NA.png differ diff --git a/logos/SKY-S.png b/logos/SKY-S.png new file mode 100755 index 0000000..ddfd779 Binary files /dev/null and b/logos/SKY-S.png differ diff --git a/logos/SKY1.png b/logos/SKY1.png new file mode 100755 index 0000000..d180745 Binary files /dev/null and b/logos/SKY1.png differ diff --git a/logos/SKYAT.png b/logos/SKYAT.png new file mode 100755 index 0000000..e94eb08 Binary files /dev/null and b/logos/SKYAT.png differ diff --git a/logos/SKYCS.png b/logos/SKYCS.png new file mode 100755 index 0000000..22313b5 Binary files /dev/null and b/logos/SKYCS.png differ diff --git a/logos/SKYF1.png b/logos/SKYF1.png new file mode 100755 index 0000000..a0cd453 Binary files /dev/null and b/logos/SKYF1.png differ diff --git a/logos/SKYRP.png b/logos/SKYRP.png new file mode 100755 index 0000000..239e75c --- /dev/null +++ b/logos/SKYRP.png @@ -0,0 +1,2 @@ + +AccessDeniedAccess Denied5Q9BCX5H8P1SRGATw1fjaHF5dMDNnCafHSwzBJtpb34QamfB5jWaE3r1WZIqwXUKtxGhLxkeDidsxrEJsLRxG+OKFjU= \ No newline at end of file diff --git a/logos/SKYSG.png b/logos/SKYSG.png new file mode 100755 index 0000000..804226d --- /dev/null +++ b/logos/SKYSG.png @@ -0,0 +1,2 @@ + +AccessDeniedAccess DeniedXPZEQC0Z34WQQGTG2VJ9t2a9I1pF/+hFtVHSgo6yg7VIXRrBWPnoCvTnppzQ7CpjWHiHsp7gMUMk1/4bPhxzHqJpKWA= \ No newline at end of file diff --git a/logos/SKYSH.png b/logos/SKYSH.png new file mode 100755 index 0000000..129a645 --- /dev/null +++ b/logos/SKYSH.png @@ -0,0 +1,2 @@ + +AccessDeniedAccess DeniedXPZ8646BK33PWJPAZsqlcQ3a2E2l7ECmT1X5orIZl9mEOG7OO2xE7pdGkIMGBeTHL1QTuRJN1c0l3vpW6sMNpaRUfVc= \ No newline at end of file diff --git a/logos/SKYSM.png b/logos/SKYSM.png new file mode 100755 index 0000000..4233880 --- /dev/null +++ b/logos/SKYSM.png @@ -0,0 +1,2 @@ + +AccessDeniedAccess DeniedXPZ0DYAKV39GWQVMeRaialFxGREqG3NV+DuW5TguPM0wZuby3DRrWfhJIz77VXDWhqUpJ4EZGRwwB2hiQJU4TV/4sgQ= \ No newline at end of file diff --git a/logos/SKYSPL.png b/logos/SKYSPL.png new file mode 100755 index 0000000..aa04b21 --- /dev/null +++ b/logos/SKYSPL.png @@ -0,0 +1,2 @@ + +AccessDeniedAccess Denied2ADBN44SGEPHQTFHIASXRgi5QNOVx7q8LD5+4gRptIqhIsZiRPfXhuDnv1vT5O3wjclzgdMX0lZuFhuAFtAZUZQng8A= \ No newline at end of file diff --git a/logos/SKYST.png b/logos/SKYST.png new file mode 100755 index 0000000..c5a9522 --- /dev/null +++ b/logos/SKYST.png @@ -0,0 +1,2 @@ + +AccessDeniedAccess DeniedXPZ1XZ8V3B8VSHCXK/rfEB2BNXyVJmDGmu9Udkd8E6gJ7hx7NU9iKQ7vf6qeMKyNrv8HCIcm9ZQ0f7a5G0UfiQQ0qtg= \ No newline at end of file diff --git a/logos/SKYSTE.png b/logos/SKYSTE.png new file mode 100755 index 0000000..b7c2cb1 --- /dev/null +++ b/logos/SKYSTE.png @@ -0,0 +1,2 @@ + +AccessDeniedAccess Denied5Q91Q6H6MX30PKZA40c6onhFAM4K0GWoRPP9O8L8NKI/InApv3pzvWCTRvCT2PwHJqqNVurHSS7dcVoQMifOEvju92w= \ No newline at end of file diff --git a/logos/SKYTH.png b/logos/SKYTH.png new file mode 100755 index 0000000..ce7e53b Binary files /dev/null and b/logos/SKYTH.png differ diff --git a/logos/SNHD.png b/logos/SNHD.png new file mode 100755 index 0000000..f395497 Binary files /dev/null and b/logos/SNHD.png differ diff --git a/logos/SONY.png b/logos/SONY.png new file mode 100755 index 0000000..2dc829e Binary files /dev/null and b/logos/SONY.png differ diff --git a/logos/SP-GE.png b/logos/SP-GE.png new file mode 100755 index 0000000..51dc8ce Binary files /dev/null and b/logos/SP-GE.png differ diff --git a/logos/SP1US.png b/logos/SP1US.png new file mode 100755 index 0000000..4603f34 Binary files /dev/null and b/logos/SP1US.png differ diff --git a/logos/SPO-A.png b/logos/SPO-A.png new file mode 100755 index 0000000..7367ee3 Binary files /dev/null and b/logos/SPO-A.png differ diff --git a/logos/SPO-D.png b/logos/SPO-D.png new file mode 100755 index 0000000..09d13e3 Binary files /dev/null and b/logos/SPO-D.png differ diff --git a/logos/SPORT.png b/logos/SPORT.png new file mode 100755 index 0000000..eef4c05 Binary files /dev/null and b/logos/SPORT.png differ diff --git a/logos/SPTVW.png b/logos/SPTVW.png new file mode 100755 index 0000000..e55a962 Binary files /dev/null and b/logos/SPTVW.png differ diff --git a/logos/SPUHD.png b/logos/SPUHD.png new file mode 100755 index 0000000..32a344e Binary files /dev/null and b/logos/SPUHD.png differ diff --git a/logos/SR.png b/logos/SR.png new file mode 100755 index 0000000..b7a1848 Binary files /dev/null and b/logos/SR.png differ diff --git a/logos/STTV.png b/logos/STTV.png new file mode 100755 index 0000000..c2705b8 Binary files /dev/null and b/logos/STTV.png differ diff --git a/logos/SUPER.png b/logos/SUPER.png new file mode 100755 index 0000000..aa9d85f Binary files /dev/null and b/logos/SUPER.png differ diff --git a/logos/SWR.png b/logos/SWR.png new file mode 100755 index 0000000..d5afec3 Binary files /dev/null and b/logos/SWR.png differ diff --git a/logos/SWRBW.png b/logos/SWRBW.png new file mode 100755 index 0000000..55b8465 Binary files /dev/null and b/logos/SWRBW.png differ diff --git a/logos/SWRRP.png b/logos/SWRRP.png new file mode 100755 index 0000000..ce098a5 Binary files /dev/null and b/logos/SWRRP.png differ diff --git a/logos/TAG24.png b/logos/TAG24.png new file mode 100755 index 0000000..3f0429a Binary files /dev/null and b/logos/TAG24.png differ diff --git a/logos/TELE5.png b/logos/TELE5.png new file mode 100755 index 0000000..8693586 Binary files /dev/null and b/logos/TELE5.png differ diff --git a/logos/TLC.png b/logos/TLC.png new file mode 100755 index 0000000..ede7b68 Binary files /dev/null and b/logos/TLC.png differ diff --git a/logos/TMAX.png b/logos/TMAX.png new file mode 100755 index 0000000..a213fcf Binary files /dev/null and b/logos/TMAX.png differ diff --git a/logos/TNT-C.png b/logos/TNT-C.png new file mode 100755 index 0000000..79fd648 Binary files /dev/null and b/logos/TNT-C.png differ diff --git a/logos/TNT-F.png b/logos/TNT-F.png new file mode 100755 index 0000000..e1b0e90 Binary files /dev/null and b/logos/TNT-F.png differ diff --git a/logos/TNT-S.png b/logos/TNT-S.png new file mode 100755 index 0000000..c2324f3 Binary files /dev/null and b/logos/TNT-S.png differ diff --git a/logos/TOGGO.png b/logos/TOGGO.png new file mode 100755 index 0000000..31a199e Binary files /dev/null and b/logos/TOGGO.png differ diff --git a/logos/TRACE.png b/logos/TRACE.png new file mode 100755 index 0000000..83d3cc3 Binary files /dev/null and b/logos/TRACE.png differ diff --git a/logos/TRAVELXP.png b/logos/TRAVELXP.png new file mode 100755 index 0000000..8d30fe4 Binary files /dev/null and b/logos/TRAVELXP.png differ diff --git a/logos/TRCH.png b/logos/TRCH.png new file mode 100755 index 0000000..8255df7 Binary files /dev/null and b/logos/TRCH.png differ diff --git a/logos/TV2.png b/logos/TV2.png new file mode 100755 index 0000000..4b473bb Binary files /dev/null and b/logos/TV2.png differ diff --git a/logos/TV5.png b/logos/TV5.png new file mode 100755 index 0000000..606c82e Binary files /dev/null and b/logos/TV5.png differ diff --git a/logos/TVB.png b/logos/TVB.png new file mode 100755 index 0000000..0dbff08 Binary files /dev/null and b/logos/TVB.png differ diff --git a/logos/TVM.png b/logos/TVM.png new file mode 100755 index 0000000..d42d0ae Binary files /dev/null and b/logos/TVM.png differ diff --git a/logos/UHD1.png b/logos/UHD1.png new file mode 100755 index 0000000..d5277b9 Binary files /dev/null and b/logos/UHD1.png differ diff --git a/logos/UNIVE.png b/logos/UNIVE.png new file mode 100755 index 0000000..c8737a4 Binary files /dev/null and b/logos/UNIVE.png differ diff --git a/logos/VH1.png b/logos/VH1.png new file mode 100755 index 0000000..5a8d79a Binary files /dev/null and b/logos/VH1.png differ diff --git a/logos/VIVA.png b/logos/VIVA.png new file mode 100755 index 0000000..0cdd587 Binary files /dev/null and b/logos/VIVA.png differ diff --git a/logos/VOX.png b/logos/VOX.png new file mode 100755 index 0000000..532458b Binary files /dev/null and b/logos/VOX.png differ diff --git a/logos/VOXUP.png b/logos/VOXUP.png new file mode 100755 index 0000000..ccae75c Binary files /dev/null and b/logos/VOXUP.png differ diff --git a/logos/WDR-AC.png b/logos/WDR-AC.png new file mode 100755 index 0000000..16e6485 Binary files /dev/null and b/logos/WDR-AC.png differ diff --git a/logos/WDR-BI.png b/logos/WDR-BI.png new file mode 100755 index 0000000..adf9045 Binary files /dev/null and b/logos/WDR-BI.png differ diff --git a/logos/WDR-BN.png b/logos/WDR-BN.png new file mode 100755 index 0000000..ff259e6 Binary files /dev/null and b/logos/WDR-BN.png differ diff --git a/logos/WDR-D.png b/logos/WDR-D.png new file mode 100755 index 0000000..0c5476d Binary files /dev/null and b/logos/WDR-D.png differ diff --git a/logos/WDR-DO.png b/logos/WDR-DO.png new file mode 100755 index 0000000..0c4f236 Binary files /dev/null and b/logos/WDR-DO.png differ diff --git a/logos/WDR-DU.png b/logos/WDR-DU.png new file mode 100755 index 0000000..d535217 Binary files /dev/null and b/logos/WDR-DU.png differ diff --git a/logos/WDR-E.png b/logos/WDR-E.png new file mode 100755 index 0000000..d18d665 Binary files /dev/null and b/logos/WDR-E.png differ diff --git a/logos/WDR-K.png b/logos/WDR-K.png new file mode 100755 index 0000000..d1496a5 Binary files /dev/null and b/logos/WDR-K.png differ diff --git a/logos/WDR-MS.png b/logos/WDR-MS.png new file mode 100755 index 0000000..27abb08 Binary files /dev/null and b/logos/WDR-MS.png differ diff --git a/logos/WDR-SI.png b/logos/WDR-SI.png new file mode 100755 index 0000000..4fa858b Binary files /dev/null and b/logos/WDR-SI.png differ diff --git a/logos/WDR-W.png b/logos/WDR-W.png new file mode 100755 index 0000000..b3f580d Binary files /dev/null and b/logos/WDR-W.png differ diff --git a/logos/WDR.png b/logos/WDR.png new file mode 100755 index 0000000..87e267f Binary files /dev/null and b/logos/WDR.png differ diff --git a/logos/WDWTV.png b/logos/WDWTV.png new file mode 100755 index 0000000..38204b4 Binary files /dev/null and b/logos/WDWTV.png differ diff --git a/logos/WELT.png b/logos/WELT.png new file mode 100755 index 0000000..91e0b3b Binary files /dev/null and b/logos/WELT.png differ diff --git a/logos/ZDF.png b/logos/ZDF.png new file mode 100755 index 0000000..fe56aa9 Binary files /dev/null and b/logos/ZDF.png differ diff --git a/logos/ZEE-1.png b/logos/ZEE-1.png new file mode 100755 index 0000000..2246019 Binary files /dev/null and b/logos/ZEE-1.png differ diff --git a/logos/ZINFO.png b/logos/ZINFO.png new file mode 100755 index 0000000..c356a62 Binary files /dev/null and b/logos/ZINFO.png differ diff --git a/po/Makefile.am b/po/Makefile.am new file mode 100644 index 0000000..9c7baa2 --- /dev/null +++ b/po/Makefile.am @@ -0,0 +1,61 @@ +# +# to use this for the localisation of other plugins, +# just change the DOMAIN to the name of the Plugin. +# It is assumed, that the domain ist the same as +# the directory name of the plugin. +# + +DOMAIN = TVMagazineCockpit +installdir = $(libdir)/enigma2/python/Plugins/Extensions/$(DOMAIN) +#GETTEXT=./pygettext.py +GETTEXT=xgettext + +#MSGFMT = ./msgfmt.py +MSGFMT = msgfmt + +LANGS := de +LANGPO := $(foreach LANG, $(LANGS),$(LANG).po) +LANGMO := $(foreach LANG, $(LANGS),$(LANG).mo) + +default: $(DOMAIN).pot $(LANGPO) merge $(LANGMO) + for lang in $(LANGS); do \ + mkdir -p $$lang/LC_MESSAGES; \ + cp $$lang.mo $$lang/LC_MESSAGES/$(DOMAIN).mo; \ + cp $$lang.po $$lang/LC_MESSAGES/$$lang.po; \ + done + +merge: + for lang in $(LANGS); do \ + msgmerge --no-location -s -N -U $$lang.po $(DOMAIN).pot; \ + done + + +# the TRANSLATORS: allows putting translation comments before the to-be-translated line. +$(DOMAIN).pot: + $(GETTEXT) -L python --add-comments="TRANSLATORS:" -d $(DOMAIN) -s -o $(DOMAIN).pot ../*.py + + ../xml2po.py ../ >> $(DOMAIN).pot + + msguniq -o $(DOMAIN)uniq.pot $(DOMAIN).pot + + +.PHONY: $(DOMAIN).pot + + +%.mo: %.po + $(MSGFMT) -o $@ $< + +%.po: + msginit -l $@ -o $@ -i $(DOMAIN).pot --no-translator + +CLEANFILES = $(foreach LANG, $(LANGS),$(LANG).mo) + +clean-local: + $(RM) -r $(LANGS) + +install-data-am: default + for lang in $(LANGS); do \ + mkdir -p $(DESTDIR)$(installdir)/locale/$$lang/LC_MESSAGES; \ + cp $$lang.mo $(DESTDIR)$(installdir)/locale/$$lang/LC_MESSAGES/$(DOMAIN).mo; \ + cp $$lang.po $(DESTDIR)$(installdir)/locale/$$lang/LC_MESSAGES/$$lang.po; \ + done diff --git a/po/TVMagazineCockpit.pot b/po/TVMagazineCockpit.pot new file mode 100644 index 0000000..2750521 --- /dev/null +++ b/po/TVMagazineCockpit.pot @@ -0,0 +1,240 @@ +msgid "" +msgstr "" +"Project-Id-Version: \n" +"POT-Creation-Date: 2024-07-09 18:46+0200\n" +"PO-Revision-Date: 2024-07-09 18:48+0200\n" +"Last-Translator: dream-alpha\n" +"Language-Team: \n" +"Language: de_DE\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 3.4.4\n" +"X-Poedit-Basepath: ../src\n" +"X-Poedit-SearchPath-0: .\n" + +msgid "Exit" +msgstr "" + +msgid "TV Bouquets" +msgstr "" + +msgid "Bouquets" +msgstr "" + +msgid "Service Reference" +msgstr "" + +msgid "Favorites" +msgstr "" + +msgid "not found" +msgstr "" + +msgid "Channel Management" +msgstr "" + +msgid "Press OK for channel list" +msgstr "" + +msgid "Save" +msgstr "" + +msgid "name difference" +msgstr "" + +msgid "Bouquet" +msgstr "" + +msgid "Press OK to enable/disable move function or Menu for more options" +msgstr "" + +msgid "Select" +msgstr "" + +msgid "Delete channel" +msgstr "" + +msgid "Delete all channels" +msgstr "" + +msgid "Zap" +msgstr "" + +msgid "Add channel" +msgstr "" + +msgid "Add all channels" +msgstr "" + +msgid "Channels (TV)" +msgstr "" + +msgid "Move mode enabled" +msgstr "" + +msgid "TV Bouquet Channels" +msgstr "" + +msgid "Press OK to add channel, or Menu for more options" +msgstr "" + +msgid "Default" +msgstr "" + +msgid "Sky" +msgstr "" + +msgid "All" +msgstr "" + +msgid "COCKPIT" +msgstr "" + +msgid "Default bouquet" +msgstr "" + +msgid "Select the default bouquet." +msgstr "" + +msgid "Picon directory" +msgstr "" + +msgid "Select the directory the picons are stored in." +msgstr "" + +msgid "Use picons" +msgstr "" + +msgid "Should channel picons be used instead of channel logos?" +msgstr "" + +msgid "DEBUG" +msgstr "" + +msgid "Log level" +msgstr "" + +msgid "Select the debug log level." +msgstr "" + +msgid "default" +msgstr "" + +msgid "favorites" +msgstr "" + +msgid "sky" +msgstr "" + +msgid "all" +msgstr "" + +msgid "Error during download" +msgstr "" + +msgid "Event Details" +msgstr "" + +msgid "min" +msgstr "" + +msgid "Add Timer" +msgstr "" + +msgid "Menu" +msgstr "" + +msgid "Input" +msgstr "" + +msgid "Bouquet Selection" +msgstr "" + +msgid "Bouquet Setup" +msgstr "" + +msgid "Settings" +msgstr "" + +msgid "About" +msgstr "" + +msgid "More" +msgstr "" + +msgid "20:15" +msgstr "" + +msgid "22:00" +msgstr "" + +msgid "Now" +msgstr "" + +msgid "column view" +msgstr "" + +msgid "Loading..." +msgstr "" + +msgid "Page" +msgstr "" + +msgid "Services" +msgstr "" + +msgid "Browse TV Magazine" +msgstr "" + +msgid "TVMagazineCockpit" +msgstr "" + +msgid "TVMagazine Event Infos" +msgstr "" + +msgid "TVMagazineCockpit Event Infos" +msgstr "" + +msgid "Plugin" +msgstr "" + +msgid "Version" +msgstr "" + +msgid "Copyright" +msgstr "" + +msgid "License" +msgstr "" + +msgid "Cancel" +msgstr "" + +msgid "Defaults" +msgstr "" + +msgid "Setup" +msgstr "" + +msgid "Really close without saving settings?" +msgstr "" + +msgid "Loading default settings will overwrite all settings, really load them?" +msgstr "" + +msgid "Some changes require a GUI restart" +msgstr "" + +msgid "Restart GUI now?" +msgstr "" + +msgid "Bookmarks" +msgstr "" + +msgid "Select directory" +msgstr "" + +msgid "Path does not exist" +msgstr "" diff --git a/po/de.po b/po/de.po new file mode 100644 index 0000000..c9e9ccf --- /dev/null +++ b/po/de.po @@ -0,0 +1,247 @@ +msgid "" +msgstr "" +"Project-Id-Version: \n" +"POT-Creation-Date: 2024-07-09 18:46+0200\n" +"PO-Revision-Date: 2024-07-09 18:48+0200\n" +"Last-Translator: dream-alpha\n" +"Language-Team: \n" +"Language: de_DE\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 3.4.4\n" +"X-Poedit-Basepath: ../src\n" +"X-Poedit-SearchPath-0: .\n" + +msgid "Exit" +msgstr "Beenden" + +msgid "TV Bouquets" +msgstr "TV Bouquets" + +msgid "Bouquets" +msgstr "Bouquets" + +msgid "Service Reference" +msgstr "Kanal Referenz" + +msgid "Favorites" +msgstr "Favoriten" + +msgid "not found" +msgstr "nicht gefunden" + +msgid "Channel Management" +msgstr "Kanalverwaltung" + +msgid "Press OK for channel list" +msgstr "Drücke OK zur Anzeige der Kanalliste" + +msgid "Save" +msgstr "Speichern" + +msgid "name difference" +msgstr "Namensunterschied" + +msgid "Bouquet" +msgstr "Bouquet" + +msgid "Press OK to enable/disable move function or Menu for more options" +msgstr "" +"Drücke OK zum Aktivieren/Deaktivieren der Verschiebefunktion oder Menü für " +"weitere Funkionen" + +msgid "Select" +msgstr "Auswahl" + +msgid "Delete channel" +msgstr "Kanal löschen" + +msgid "Delete all channels" +msgstr "Alle Kanäle löschen" + +msgid "Zap" +msgstr "Umschalten" + +msgid "Add channel" +msgstr "Kanal hinzufügen" + +msgid "Add all channels" +msgstr "Alle Kanäle hinzufügen" + +msgid "Channels (TV)" +msgstr "Kanäle (TV)" + +msgid "Move mode enabled" +msgstr "Verschiebemodus" + +msgid "TV Bouquet Channels" +msgstr "TV Bouquet Kanäle" + +msgid "Press OK to add channel, or Menu for more options" +msgstr "" +"Drücke OK um den Kanal zum Bouquet hinzuzufügen oder Menü für weitere " +"Funktionen" + +msgid "Default" +msgstr "Standard" + +msgid "Sky" +msgstr "SKY" + +msgid "All" +msgstr "Alle" + +msgid "COCKPIT" +msgstr "COCKPIT" + +msgid "Default bouquet" +msgstr "Standard Bouquet" + +msgid "Select the default bouquet." +msgstr "Auswahl des Standard Bouquets" + +msgid "Picon directory" +msgstr "Picon Verzeichnis" + +msgid "Select the directory the picons are stored in." +msgstr "Auswahl des Picon Verzeichnisses" + +msgid "Use picons" +msgstr "Verwende Picons" + +msgid "Should channel picons be used instead of channel logos?" +msgstr "Sollen Picons statt Logos verwendet werden?" + +msgid "DEBUG" +msgstr "DEBUG" + +msgid "Log level" +msgstr "Logstufe" + +msgid "Select the debug log level." +msgstr "Auswahl der Logstufe" + +msgid "default" +msgstr "Standard" + +msgid "favorites" +msgstr "Favoriten" + +msgid "sky" +msgstr "SKY" + +msgid "all" +msgstr "Alle" + +msgid "Error during download" +msgstr "Fehler beim Download" + +msgid "Event Details" +msgstr "Sendungsdetails" + +msgid "min" +msgstr "Min" + +msgid "Add Timer" +msgstr "Timer hinzufügen" + +msgid "Menu" +msgstr "Menü" + +msgid "Input" +msgstr "Eingabe" + +msgid "Bouquet Selection" +msgstr "Bouquetauswahl" + +msgid "Bouquet Setup" +msgstr "Bouquetverwaltung" + +msgid "Settings" +msgstr "Einstellungen" + +msgid "About" +msgstr "Über" + +msgid "More" +msgstr "Mehr" + +msgid "20:15" +msgstr "20:15" + +msgid "22:00" +msgstr "22:00" + +msgid "Now" +msgstr "Jetzt" + +msgid "column view" +msgstr "Spaltenansicht" + +msgid "Loading..." +msgstr "Lade..." + +msgid "Page" +msgstr "Seite" + +msgid "Services" +msgstr "Kanäle" + +msgid "Browse TV Magazine" +msgstr "TV Magazin duchblättern" + +msgid "TVMagazineCockpit" +msgstr "TVMagazinCockpit" + +msgid "TVMagazine Event Infos" +msgstr "TV Magazine Sendungsinfos" + +msgid "TVMagazineCockpit Event Infos" +msgstr "TV Magazin Sendungsinfos" + +msgid "Plugin" +msgstr "Plugin" + +msgid "Version" +msgstr "Version" + +msgid "Copyright" +msgstr "Copyright" + +msgid "License" +msgstr "Lizenz" + +msgid "Cancel" +msgstr "Abbruch" + +msgid "Defaults" +msgstr "Standard" + +msgid "Setup" +msgstr "Einstellungen" + +msgid "Really close without saving settings?" +msgstr "Fortfahren ohne Speichern der Einstellungen?" + +msgid "Loading default settings will overwrite all settings, really load them?" +msgstr "" +"Das Laden der Standardeinstellungen überschreibt alle aktuellen " +"Einstellungen.\n" +"Sollen die Standardeinstellungen wirklich geladen werden?" + +msgid "Some changes require a GUI restart" +msgstr "Einige Änderungen erfordern einen Neustart der GUI" + +msgid "Restart GUI now?" +msgstr "Soll die GUI jetzt neu gestartet werden?" + +msgid "Bookmarks" +msgstr "Lesezeichen" + +msgid "Select directory" +msgstr "Verzeichnis-Auswahl" + +msgid "Path does not exist" +msgstr "Verzeichnis existiert nicht" diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..968fd5c --- /dev/null +++ b/setup.cfg @@ -0,0 +1,9 @@ +[flake8] +ignore = W191, W503, E117, E203, E242, E501 + +[pycodestyle] +count = False +ignore = W191, W503, E117, E203, E242 + +max-line-length = 320 +statistics = True diff --git a/src/About.py b/src/About.py new file mode 100644 index 0000000..32a751d --- /dev/null +++ b/src/About.py @@ -0,0 +1,35 @@ +#!/usr/bin/python +# coding=utf-8 +# +# Copyright (C) 2018-2024 by dream-alpha +# +# In case of reuse of this source code please do not remove this copyright. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# For more information on the GNU General Public License see: +# . + + +from Screens.MessageBox import MessageBox +from .Version import PLUGIN, VERSION, COPYRIGHT, LICENSE +from .__init__ import _ + + +def about(session): + session.open( + MessageBox, + _("Plugin") + ": " + PLUGIN + "\n\n" + + _("Version") + ": " + VERSION + "\n\n" + + _("Copyright") + ": " + COPYRIGHT + "\n\n" + + _("License") + ": " + LICENSE, + MessageBox.TYPE_INFO + ) diff --git a/src/ChannelManagement.py b/src/ChannelManagement.py new file mode 100755 index 0000000..12fd847 --- /dev/null +++ b/src/ChannelManagement.py @@ -0,0 +1,299 @@ +# !/usr/bin/python +# coding=utf-8 +# +# Copyright (C) 2018-2024 by dream-alpha +# +# In case of reuse of this source code please do not remove this copyright. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# For more information on the GNU General Public License see: +# . + + +import re +from APIs.ServiceData import getTVBouquets, getServiceList +from Screens.Screen import Screen +from Screens.ChoiceBox import ChoiceBox +# from Screens.MessageBox import MessageBox +from Screens.ChannelSelection import service_types_tv +from Screens.SimpleSummary import SimpleSummary +from Components.ActionMap import ActionMap +from Components.Label import Label +from Components.Sources.StaticText import StaticText +from ServiceReference import ServiceReference +from Tools.Directories import resolveFilename, SCOPE_CONFIG +from .__init__ import _ +from .MyList import MyList +from .Debug import logger +from .ChannelUtils import write_channel_list, getChannel +from .Constants import TVS +from .ZapUtils import Zap_Service + + +class ChannelManagement(Screen): + def __init__(self, session, bouquet, channel_list, channel_dict): + logger.info("...") + self.bouquet = bouquet + self.channel_list = channel_list + self.channel_list_org = channel_list[:] + logger.debug("channel_list: %s", self.channel_list) + self.channel_dict = channel_dict + Screen.__init__(self, session) + self.skinName = "ChannelManagement" + self["actions"] = ActionMap( + ["TVC_Actions"], + { + "ok": self.key_ok, + "cancel": self.key_red, + "red": self.key_red, + "green": self.key_green, + "yellow": self.key_yellow, + "blue": self.key_blue, + # "info": self.showInfo, + "menu": self.showMenu, + # "menulong": self.showMenuLong + } + ) + self["actionsmove"] = ActionMap( + ["TVC_Actions"], + { + "up": self.keyUp, + "down": self.keyDown, + "left": self.noop, + "right": self.noop + } + ) + self["actionsmove"].setEnabled(False) + + self["key_red"] = StaticText(_("Exit")) + self["key_green"] = StaticText() + self["key_yellow"] = StaticText(_("TV Bouquets")) + self["key_blue"] = StaticText(_("Bouquets")) + + self["list"] = MyList() + self["list"].style = "default" + self.mytitlestr = ("mytitle1", "mytitle2", "mytitle3", "mytitle4", "mytitle5") + self["mytitle1"] = Label("TV Spielfilm Name") + self["mytitle2"] = Label("TV Spielfilm ID") + self["mytitle3"] = Label("Enigma Name") + self["mytitle4"] = Label(_("Service Reference")) + self["mytitle5"] = Label(_("Favorites")) + for myx in self.mytitlestr: + self[myx].hide() + self["message"] = Label() + self.listtype = "" + self.bouquet_list = [] + self.key_blue() + + def createBouquetList(self, channel_list, channel_dict): + result = [] + for channel_name in channel_list: + channel_id = channel_dict[channel_name]["id"] + value = channel_dict[channel_name] + if value: + enameval = "" + ename = ServiceReference(value["service"]).getServiceName() + if not ename: + enameval = _("not found") + elif value["ename"] != ename: + enameval = ename + result.append([value["tname"], channel_id, value["ename"], value["service"], enameval, channel_name]) + else: + result.append(["n/a", channel_id, "n/a", "n/a", ""]) + return result + + def noop(self): + logger.info("...") + + def keyUp(self): + logger.info("...") + if self.listtype in "blue": + currindex = self["list"].getIndex() + self["list"].moveSelection("moveUp") + self["list"].list.insert(self["list"].getIndex(), self["list"].list.pop(currindex)) + + def keyDown(self): + logger.info("...") + if self.listtype in "blue": + currindex = self["list"].getIndex() + self["list"].moveSelection("moveDown") + self["list"].list.insert(self["list"].getIndex(), self["list"].list.pop(currindex)) + + def key_red(self): + logger.info("...") + self.close(self.channel_list_org) + + def key_green(self): + logger.info("...") + if self.listtype == "blue": + channel_list = [] + bouquet_channel_list = self["list"].getList() + for list_element in bouquet_channel_list: + channel_list.append(list_element[5]) + write_channel_list(self.bouquet, channel_list) + logger.debug("channel_list: %s", channel_list) + self.close(channel_list) + + def key_yellow(self): + + def channels_file_name(bouquet): + return resolveFilename(SCOPE_CONFIG, "tvspielfilm_%s_channels.json" % bouquet) + + logger.info("...") + self.listtype = "yellow" + self.setTitle(self["key_yellow"].text) + self["key_green"].text = "" + self["actionsmove"].setEnabled(False) + tvbouquets = getTVBouquets() + mylist = [] + allname = self.cleanname("Alle Sender (Enigma)") + filenameall = channels_file_name(allname) + mylist.append(["Alle Sender (Enigma)", "", service_types_tv, allname, filenameall, "eall"]) + for bouquet in tvbouquets: + name = self.cleanname(bouquet[1]) + filename = channels_file_name(name) + + mylist.append([bouquet[1], "", bouquet[0], name, filename, "bouq"]) + for myx in self.mytitlestr: + self[myx].hide() + self["list"].style = "default" + self["list"].setList(mylist) + title = "%s %s - %s: %s" % (TVS, _("Channel Management"), _("TV Bouquets"), self["list"].count()) + self.setTitle(title) + self["message"].setText(_("Press OK for channel list")) + + def key_blue(self): + logger.info("...") + self["actionsmove"].setEnabled(False) + self.listtype = "blue" + self.setTitle(self["key_blue"].text) + self["key_green"].text = _("Save") + for myx in self.mytitlestr: + self[myx].show() + self["mytitle5"].text = _("name difference") + self["list"].style = "channel_bouquet" + self.bouquet_list = self.createBouquetList(self.channel_list, self.channel_dict) + self["list"].updateList(self.bouquet_list) + + title = "%s %s - %s: %s" % (TVS, _("Channel Management"), _("Bouquet"), self.bouquet) + self.setTitle(title) + self["message"].setText(_("Press OK to enable/disable move function or Menu for more options")) + + def showMenu(self): + logger.info("...") + self["actionsmove"].setEnabled(False) + selection = 0 + options = [] + mytitle = _("Select") + curr = self["list"].getCurrent() + if self.listtype == "blue": + if curr: + options.append((_("Delete channel"), "delcurr")) + if self.bouquet_list: + options.append((_("Delete all channels"), "delall")) + options.append((_("Zap"), "zap")) + mytitle = _("Bouquet") + elif self.listtype == "yellow2": + if curr: + options.append((_("Add channel"), "addcurr")) + options.append((_("Add all channels"), "addall")) + mytitle = _("Channels (TV)") + if options: + self.session.openWithCallback( + self.menuCallback, + ChoiceBox, + title=mytitle, + list=options, + selection=selection + ) + + def menuCallback(self, answer): + logger.info("...") + answer = answer and answer[1] + curr = self["list"].getCurrent() + if curr: + if answer == "delcurr": + self.channel_list.remove(curr[5]) + self["list"].deleteEntry() + self.key_blue() + elif answer == "delall": + self.channel_list = [] + self.key_blue() + elif answer == "addcurr": + if self.addTVChannel(curr): + self.key_blue() + elif answer == "addall": + self.channel_list = [] + for row in self["list"].getList(): + self.addTVChannel(row) + logger.debug("addall: channel_list: %s", self.channel_list) + self.key_blue() + elif answer == "zap": + Zap_Service(curr[3]) + + def addTVChannel(self, curr): + name = curr[0] + service = curr[1] + channel_name = getChannel(service, self.channel_dict) + if channel_name: + self.channel_list.append(channel_name) + else: + logger.error("service not found: %s: %s", name, service) + return True + + def key_ok(self): + logger.info("...") + curr = self["list"].getCurrent() + if self.listtype == "yellow": + if curr: + self.showBouquetChannels(curr) + elif self.listtype == "yellow2": + self.addTVChannel(curr) + elif self.listtype == "blue": + if curr: + if self["actionsmove"].enabled is False: + self["actionsmove"].setEnabled(True) + title = "%s %s - %s: %s - %s" % (TVS, _("Channel Management"), _("Bouquet"), self.bouquet, _("Move mode enabled")) + else: + self["actionsmove"].setEnabled(False) + title = "%s %s - %s: %s" % (TVS, _("Channel Management"), _("Bouquet"), self.bouquet) + self.setTitle(title) + + def showBouquetChannels(self, curr): + logger.info("...") + if curr: + servicetypes = curr[2] + " ORDER BY name" + service_list = getServiceList(servicetypes) + logger.debug("service_list: %s", service_list) + if service_list: + mylist = [] + for service, ename in service_list: + if "::" not in service: + mylist.append((ename, service, "")) + self.listtype = "yellow2" + self["actionsmove"].setEnabled(False) + for myx in self.mytitlestr: + self[myx].hide() + self["list"].style = "default" + self["list"].setList(mylist) + title = "%s %s - %s: %s" % (TVS, _("Channel Management"), _("TV Bouquet Channels"), self["list"].count()) + self.setTitle(title) + self["message"].setText(_("Press OK to add channel, or Menu for more options")) + + def cleanname(self, msg): + logger.info("...") + p = re.compile("[^a-zA-Z0-9]") + return p.sub("_", msg).replace(" ", "") + + def createSummary(self): + logger.info("...") + return SimpleSummary diff --git a/src/ChannelUtils.py b/src/ChannelUtils.py new file mode 100755 index 0000000..0a4d444 --- /dev/null +++ b/src/ChannelUtils.py @@ -0,0 +1,98 @@ +# !/usr/bin/python +# coding=utf-8 +# +# Copyright (C) 2018-2024 by dream-alpha +# +# In case of reuse of this source code please do not remove this copyright. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# For more information on the GNU General Public License see: +# . + + +import os +import json +from six import text_type +from Tools.Directories import resolveFilename, SCOPE_CONFIG, pathExists +from .ConfigInit import plugindir +from .Debug import logger + + +def convert_unicode_to_str(input_data): + if isinstance(input_data, dict): + return {convert_unicode_to_str(key): convert_unicode_to_str(value) for key, value in input_data.iteritems()} + if isinstance(input_data, list): + return [convert_unicode_to_str(element) for element in input_data] + if isinstance(input_data, text_type): + return input_data.encode("utf-8") + return input_data + + +def read_channel_list(bouquet="default"): + logger.info("bouquet: %s", bouquet) + filename = "" + channel_list = [] + channel_list_filename = "tvspielfilm_channel_list_%s.json" % bouquet + path = os.path.join(resolveFilename(SCOPE_CONFIG), channel_list_filename) + if pathExists(path): + filename = path + else: + path = os.path.join(plugindir, channel_list_filename) + if pathExists(path): + filename = path + logger.debug("filename: %s", filename) + if filename: + with open(filename) as data_file: + channel_list = convert_unicode_to_str(json.load(data_file)) + logger.debug("channel_list: %s", channel_list) + return channel_list + + +def write_channel_list(bouquet, channel_list): + logger.info("bouquet: %s", bouquet) + channel_list_filename = "tvspielfilm_channel_list_%s.json" % bouquet + path = os.path.join(resolveFilename(SCOPE_CONFIG), channel_list_filename) + with open(path, "w") as afile: + json.dump(channel_list, afile, indent=2) + + +def read_channel_dict(): + logger.info("...") + filename = "" + channel_dict = {} + channel_dict_filename = "tvspielfilm_channel_dict_default.json" + path = os.path.join(resolveFilename(SCOPE_CONFIG), channel_dict_filename) + if pathExists(path): + filename = path + else: + path = os.path.join(plugindir, channel_dict_filename) + if pathExists(path): + filename = path + logger.debug("filename: %s", filename) + if filename: + with open(filename) as data_file: + channel_dict = convert_unicode_to_str(json.load(data_file)) + logger.debug("channel_dict: %s", channel_dict) + return channel_dict + + +def getChannel(service, channel_dict): + logger.info("service: %s", service) + for channel_name, channel in channel_dict.iteritems(): + # logger.debug("channel_name: %s, channel: %s", channel_name, channel) + if channel["service"] == service: + logger.debug("found: %s", channel_name) + break + else: + channel_name = "" + logger.debug("channel_name: %s", channel_name) + return channel_name diff --git a/src/ConfigInit.py b/src/ConfigInit.py new file mode 100755 index 0000000..5606a4a --- /dev/null +++ b/src/ConfigInit.py @@ -0,0 +1,45 @@ +# !/usr/bin/python +# coding=utf-8 +# +# Copyright (C) 2018-2024 by dream-alpha +# +# In case of reuse of this source code please do not remove this copyright. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# For more information on the GNU General Public License see: +# . + +from Components.config import config, ConfigSelection, ConfigYesNo, ConfigSubsection, ConfigNothing, NoSave +from Tools.Directories import resolveFilename, SCOPE_PLUGINS +from .Debug import logger, log_levels, initLogging +from .__init__ import _ + + +plugindir = resolveFilename(SCOPE_PLUGINS, "Extensions/TVMagazineCockpit/") +bouquet_choices = [ + ("default", _("Default")), + ("favorites", _("Favorites")), + ("sky", _("Sky")), + ("all", _("All")), +] + + +class ConfigInit(): + + def __init__(self): + logger.info("...") + config.plugins.tvmagazinecockpit = ConfigSubsection() + config.plugins.tvmagazinecockpit.fake_entry = NoSave(ConfigNothing()) + config.plugins.tvmagazinecockpit.debug_log_level = ConfigSelection(default="DEBUG", choices=list(log_levels.keys())) + config.plugins.tvmagazinecockpit.use_picons = ConfigYesNo(default=True) + config.plugins.tvmagazinecockpit.bouquet = ConfigSelection(default="default", choices=bouquet_choices) + initLogging() diff --git a/src/ConfigScreen.py b/src/ConfigScreen.py new file mode 100644 index 0000000..6946613 --- /dev/null +++ b/src/ConfigScreen.py @@ -0,0 +1,295 @@ +#!/usr/bin/python +# coding=utf-8 +# +# Copyright (C) 2018-2024 by dream-alpha +# +# In case of reuse of this source code please do not remove this copyright. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# For more information on the GNU General Public License see: +# . + + +import os +from Components.ConfigList import ConfigListScreen +from Components.config import config, configfile, getConfigListEntry, ConfigText, ConfigPassword +from Components.Button import Button +from Components.Sources.StaticText import StaticText +from Components.ActionMap import ActionMap +from Screens.Screen import Screen +from Screens.LocationBox import LocationBox +from Screens.MessageBox import MessageBox +from Screens.VirtualKeyBoard import VirtualKeyBoard +from Screens.Standby import TryQuitMainloop +from enigma import eTimer, ePoint +from .__init__ import _ +from .Version import PLUGIN +from .Debug import logger, log_levels, setLogLevel +from .SkinUtils import getSkinName +from .ConfigScreenInit import ConfigScreenInit + + +class ConfigScreen(ConfigScreenInit, ConfigListScreen, Screen): + + def __init__(self, session, config_plugins_plugin): + self.config_plugins_plugin = config_plugins_plugin + Screen.__init__(self, session) + self.skinName = getSkinName("ConfigScreen") + ConfigScreenInit.__init__(self, session) + + self["actions"] = ActionMap( + ["ColorActions", "SetupActions"], + { + "cancel": self.keyCancel, + "red": self.keyCancel, + "save": self.keySaveNew, + "yellow": self.loadDefaultSettings, + "next_section": self.bouquetPlus, + "previous_section": self.bouquetMinus, + }, + -2 # higher priority + ) + + self["VirtualKB"] = ActionMap( + ["VirtualKeyboardActions"], + { + "showVirtualKeyboard": self.keyText, + }, + -2 # higher priority + ) + + self["VirtualKB"].setEnabled(False) + + self["key_red"] = Button(_("Cancel")) + self["key_green"] = Button(_("Save")) + self["key_yellow"] = Button(_("Defaults")) + self["key_blue"] = Button() + self["help"] = StaticText() + + self.list = [] + ConfigListScreen.__init__(self, self.list, session=self.session, on_change=self.changedEntry) + self.needs_restart = False + + self.reload_timer = eTimer() + self.reload_timer_conn = self.reload_timer.timeout.connect(self.createConfig) + + self["config"].selectionChanged = self.selectionChanged + self["config"].onSelectionChanged.append(self.updateHelp) + # self["config"].onSelectionChanged.append(self.handleInputHelpers) + + self.setTitle(PLUGIN + " " + _("Setup")) + self.createConfig() + + def selectionChanged(self): + current = self["config"].getCurrent() + if current and len(current) > 1: + if self["config"].current != current: + if self["config"].current: + self["config"].current[1].onDeselect(self.session) + if current: + current[1].onSelect(self.session) + self["config"].current = current + for x in self["config"].onSelectionChanged: + if x: + x() + + def handleInputHelpers(self): + self["VirtualKB"].setEnabled(False) + if self["config"].getCurrent(): + if isinstance(self['config'].getCurrent()[1], (ConfigPassword, ConfigText)): + self["VirtualKB"].setEnabled(True) + if hasattr(self, "HelpWindow"): + if self["config"].getCurrent()[1].help_window.instance: + helpwindowpos = self["HelpWindow"].getPosition() + self["config"].getCurrent()[1].help_window.instance.move(ePoint(helpwindowpos[0], helpwindowpos[1])) + + def keyText(self): + self.session.openWithCallback(self.VirtualKeyBoardCallback, VirtualKeyBoard, title=self["config"].getCurrent()[0], text=self["config"].getCurrent()[1].getValue()) + + def VirtualKeyBoardCallback(self, callback=None): + if callback: + self["config"].getCurrent()[1].setValue(callback) + self["config"].invalidate(self["config"].getCurrent()) + + def cancelConfirm(self, answer): + if answer: + for x in self["config"].list: + if len(x) > 1: + x[1].cancel() + self.close() + + def keyCancel(self): + if self["config"].isChanged(): + self.session.openWithCallback(self.cancelConfirm, MessageBox, _("Really close without saving settings?")) + else: + self.close() + + def bouquetPlus(self): + self["config"].jumpToPreviousSection() + + def bouquetMinus(self): + self["config"].jumpToNextSection() + + def createConfig(self): + logger.debug("len(self.config_list): %s", len(self.config_list)) + self.list = [] + for i, conf in enumerate(self.config_list): + # 0 entry text + # 1 variable + # 2 validation + # 3 pressed ok + # 4 setup level + # 5 parent entries + # 6 help text + # config item must be valid for current usage setup level + if config.usage.setup_level.index >= conf[4]: + # parent entries must be true + for parent in conf[5]: + if parent < 0: + if not self.config_list[i + parent][1].value: + break + elif parent > 0: + if self.config_list[i - parent][1].value: + break + else: + # loop fell through without a break + if conf[0] == self.section: + if len(self.list) > 1: + self.list.append(getConfigListEntry("", self.config_plugins_plugin.fake_entry, None, None, 0, [], "")) + if conf[1] == "": + self.list.append(getConfigListEntry("",)) + else: + self.list.append(getConfigListEntry(conf[1],)) + else: + self.list.append(getConfigListEntry(conf[0], conf[1], conf[2], conf[3], conf[4], conf[5], conf[6])) + self["config"].setList(self.list) + + def loadDefaultSettings(self): + self.session.openWithCallback( + self.loadDefaultSettingsCallback, + MessageBox, + _("Loading default settings will overwrite all settings, really load them?"), + MessageBox.TYPE_YESNO + ) + + def loadDefaultSettingsCallback(self, answer): + if answer: + for conf in self.config_list: + if conf[0] != self.section: + conf[1].value = conf[1].default + self.createConfig() + + def changedEntry(self, _addNotifier=None): + if self.reload_timer.isActive(): + self.reload_timer.stop() + self.reload_timer.start(50, True) + + def updateHelp(self): + cur = self["config"].getCurrent() + self["help"].text = (cur[6] if cur else '') + + def dirSelected(self, adir): + if adir: + adir = os.path.normpath(adir) + if self["config"].getCurrent()[2]: + if self["config"].getCurrent()[2](adir): + self["config"].getCurrent()[1].value = adir + + def keyOK(self): + logger.debug("...") + current = self["config"].getCurrent() + if current and current[3]: + current[3](current[1]) + + def reloadConfig(self): + logger.debug("...") + ConfigScreenInit.__init__(self, self.session) + self.changedEntry() + + def keySaveNew(self): + logger.debug("...") + save_value = True + for i, conf in enumerate(self.config_list): + # logger.debug("i: %s, conf[0]: %s", i, conf[0]) + if conf[0] != self.section: + if conf[1].isChanged(): + # logger.debug("i: %s, conf[0]: %s isChanged", i, conf[0]) + if conf[2]: + # execute value changed function + # logger.debug("execute value changed function") + if not conf[2](conf[1]): + logger.error("value function error: %s", conf[0]) + save_value = False + # Check parent entries + for parent in conf[5]: + # logger.debug("parent: %s, conf[5]: %s", str(parent), str(conf[5])) + if self.config_list[i + parent][2]: + # execute parent value changed function + # logger.debug("execute parent value changed function") + if not self.config_list[i + parent][2](self.config_list[i + parent][1]): + logger.error("parent value function error: %s", self.config_list[i + parent][2]) + if save_value: + logger.debug("saving: %s", conf[0]) + conf[1].save() + configfile.save() + if not save_value: + self.createConfig() + else: + if self.needs_restart: + self.restartGUI() + else: + self.close(True) + + def restartGUI(self): + self.session.openWithCallback(self.restartGUIConfirmed, MessageBox, _("Some changes require a GUI restart") + "\n" + _("Restart GUI now?"), MessageBox.TYPE_YESNO) + + def restartGUIConfirmed(self, answer): + if answer: + self.session.open(TryQuitMainloop, 3) + else: + self.close(True) + + def setLogLevel(self, element): + logger.debug("element: %s", element.value) + setLogLevel(log_levels[element.value]) + return True + + def needsRestart(self, _element=None): + logger.info("...") + self.needs_restart = True + return True + + def openLocationBox(self, element): + if element: + path = os.path.normpath(element.value) + self.session.openWithCallback( + self.dirSelected, + LocationBox, + windowTitle=_("Bookmarks"), + text=_("Select directory"), + currDir=path + "/", + bookmarks=self.config_plugins_plugin.bookmarks, + autoAdd=False, + editDir=True, + inhibitDirs=["/bin", "/boot", "/dev", "/etc", "/lib", "/proc", "/sbin", "/sys", "/var"], + minFree=None + ) + + def validatePath(self, element): + if isinstance(element, str): + adir = os.path.normpath(element) + else: + adir = os.path.normpath(element.value) + valid = os.path.exists(adir) + if not valid: + self.session.open(MessageBox, _("Path does not exist") + ": " + adir, MessageBox.TYPE_ERROR) + return valid diff --git a/src/ConfigScreenInit.py b/src/ConfigScreenInit.py new file mode 100644 index 0000000..4729c7a --- /dev/null +++ b/src/ConfigScreenInit.py @@ -0,0 +1,69 @@ +#!/usr/bin/python +# coding=utf-8 +# +# Copyright (C) 2018-2024 by dream-alpha +# +# In case of reuse of this source code please do not remove this copyright. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# For more information on the GNU General Public License see: +# . + + +from Components.config import config +from .Debug import logger +from .__init__ import _ + + +class ConfigScreenInit(): + def __init__(self, session): + self.session = session + self.section = 400 * "¯" + + # config list entry + # , config element + # , , function called on save + # , , , function called if user has pressed OK + # , , , , usage setup level from E2 + # , , , , 0: simple+ + # , , , , 1: intermediate+ + # , , , , 2: expert+ + # , , , , , depends on relative parent entries + # , , , , , parent config value < 0 = true + # , , , , , parent config value > 0 = false + # , , , , , , context sensitive help text + # , , , , , , + # 0 , 1 , 2 , 3 , 4 , 5 , 6 + self.config_list = [ + (self.section , _("COCKPIT") , None , None , 0 , [] , ""), + (_("Default bouquet") , config.plugins.tvmagazinecockpit.bouquet , None , None , 0 , [] , _("Select the default bouquet.")), + (_("Picon directory") , config.usage.configselection_piconspath , self.validatePath , None , 0 , [] , _("Select the directory the picons are stored in.")), + (_("Use picons") , config.plugins.tvmagazinecockpit.use_picons , None , None , 0 , [] , _("Should channel picons be used instead of channel logos?")), + (self.section , _("DEBUG") , None , None , 2 , [] , ""), + (_("Log level") , config.plugins.piconcockpit.debug_log_level , self.setLogLevel , None , 2 , [] , _("Select the debug log level.")), + ] + + @staticmethod + def save(_conf): + logger.debug("...") + + def openLocationBox(self, element): + logger.debug("element: %s", element.value) + return True + + def setLogLevel(self, element): + logger.debug("element: %s", element.value) + return True + + def validatePath(self, element): + logger.debug("element: %s", element.value) + return True diff --git a/src/Constants.py b/src/Constants.py new file mode 100644 index 0000000..4fd4cf1 --- /dev/null +++ b/src/Constants.py @@ -0,0 +1,71 @@ +# !/usr/bin/python +# coding=utf-8 +# +# Copyright (C) 2018-2024 by dream-alpha +# +# In case of reuse of this source code please do not remove this copyright. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# For more information on the GNU General Public License see: +# . + + +from __init__ import _ + +TMP_DIR = "tmp/TVC" +TVS = "TV Spielfilm" +BOUQUETS = {"default": _("default"), "favorites": _("favorites"), "sky": _("sky"), "all": _("all")} + +EVENT_IDX_TIME_START = 0 +EVENT_IDX_VIDEOS = 1 +EVENT_IDX_IS_NEW = 2 +EVENT_IDX_TEXT = 3 +EVENT_IDX_GENRE = 4 +EVENT_IDX_YEAR = 5 +EVENT_IDX_IMAGES = 6 +EVENT_IDX_CURRENT_TOPICS = 7 +EVENT_IDX_ID = 8 +EVENT_IDX_TITLE = 9 +EVENT_IDX_EPISODE_TITLE = 10 +EVENT_IDX_SUBLINE = 11 +EVENT_IDX_TIME_END = 12 +EVENT_IDX_REPEAT = 13 +EVENT_IDX_BROADCASTER_ID = 14 +EVENT_IDX_BROADCASTER_NAME = 15 +EVENT_IDX_IS_TIP_OF_THE_DAY = 16 +EVENT_IDX_IS_TOP_TIP = 17 +EVENT_IDX_ANCHOR_MAN = 18 +EVENT_IDX_THUMB_ID_NUMERIC = 19 +EVENT_LENGTH = 20 + +EVENT_KEYS = [ + "timestart", + "videos", + "isNew", + "text", + "genre", + "year", + "images", + "currentTopics", + "id", + "title", + "episodeTitle", + "subline", + "timeend", + "repeatHint", + "broadcasterId", + "broadcasterName", + "isTipOfTheDay", + "isTopTip", + "anchorMan", + "thumbIdNumeric" +] diff --git a/src/Debug.py b/src/Debug.py new file mode 100644 index 0000000..fbcfb9e --- /dev/null +++ b/src/Debug.py @@ -0,0 +1,53 @@ +#!/usr/bin/python +# coding=utf-8 +# +# Copyright (C) 2018-2024 by dream-alpha +# +# In case of reuse of this source code please do not remove this copyright. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# For more information on the GNU General Public License see: +# . + + +import sys +import logging +from Components.config import config, ConfigSubsection, ConfigDirectory, ConfigSelection # noqa: F401, pylint: disable=W0611 +from .Version import ID, PLUGIN + + +logger = None +streamer = None +format_string = (ID + ": " + "%(levelname)s: %(filename)s: %(funcName)s: %(message)s") +log_levels = {"ERROR": logging.ERROR, "INFO": logging.INFO, "DEBUG": logging.DEBUG} +plugin = PLUGIN.lower() +exec("config.plugins." + plugin + " = ConfigSubsection()") # noqa: F401, pylint: disable=W0122 +exec("config.plugins." + plugin + ".debug_log_level = ConfigSelection(default='INFO', choices=log_levels.keys())") # noqa: F401, pylint: disable=W0122 + + +def initLogging(): + global logger + global streamer + if not logger: + logger = logging.getLogger(ID) + formatter = logging.Formatter(format_string) + streamer = logging.StreamHandler(sys.stdout) + streamer.setFormatter(formatter) + logger.addHandler(streamer) + logger.propagate = False + setLogLevel(log_levels[eval("config.plugins." + plugin + ".debug_log_level").value]) + + +def setLogLevel(level): + logger.setLevel(level) + streamer.setLevel(level) + logger.info("level: %s", level) diff --git a/src/Downloader.py b/src/Downloader.py new file mode 100755 index 0000000..8c5be49 --- /dev/null +++ b/src/Downloader.py @@ -0,0 +1,407 @@ +# !/usr/bin/python +# coding=utf-8 +# +# Copyright (C) 2018-2024 by dream-alpha +# +# In case of reuse of this source code please do not remove this copyright. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# For more information on the GNU General Public License see: +# . + +# pylint: disable=W1113, W0212, W0221, W0222 + + +import json +from cookielib import CookieJar +from twisted.internet import reactor +from twisted.web.http_headers import Headers +from twisted.internet.task import deferLater +from twisted.web.client import Agent, RedirectAgent, _GzipProtocol, CookieAgent, BrowserLikePolicyForHTTPS, HTTPConnectionPool, _requireSSL, PartialDownloadError +from twisted.internet.protocol import Protocol +from twisted.internet.defer import Deferred, DeferredSemaphore, succeed +from twisted.web.iweb import IBodyProducer +from twisted.internet.ssl import ClientContextFactory as ssl_ClientContextFactory, CertificateOptions, AcceptableCiphers +from twisted.internet._sslverify import ClientTLSOptions, verifyHostname, VerificationError +from twisted.web._newclient import ResponseDone, ResponseFailed, PotentialDataLoss +from twisted.python.failure import Failure +from twisted.internet.error import CertificateError +from twisted.web import http +from zope.interface import implementer +from OpenSSL import SSL as _SSL +from API import session as mysession +from .__init__ import _ +from .Debug import logger + + +_headers = Headers({"User-Agent": ["Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36"]}) +_headers.addRawHeader("content-type", "text/html; charset=UTF-8") +_headers.addRawHeader("Accept-Language", "de, de-DE;q=0.9, en;q=0.8, en-GB;q=0.7, en-US;q=0.6") +_headers.addRawHeader("Accept-Charset", "utf-8, iso-8859-1;q=0.5") +_headers.addRawHeader("Accept", "text/html, application/xhtml+xml, application/xml;q=0.9, image/webp, */*;q=0.8") +_headers.addRawHeader("Cache-Control", "public, max-age=86400, max-stale=86400") +_headers.addRawHeader("Sec-CH-UA", 'Google Chrome";v="107", "Chromium";v="107", "Not=A?Brand";v="24') +_headers.addRawHeader("SEC-CH-UA-FULL-VERSION", "107.0.5304.88") +_headers.addRawHeader("Sec-CH-UA-Mobile", "?0") +_headers.addRawHeader("Sec-CH-UA-Platform", "Windows") +_headers.addRawHeader("Sec-CH-UA-Platform-Version", "10.0.0") +_headers.addRawHeader("Sec-CH-UA-Model", "") +_headers.addRawHeader("SEC-CH-UA-ARCH", "x86") +_headers.addRawHeader("Sec-CH-UA-Bitness", "64") +_headers.addRawHeader("DNT", "1") +_headers.addRawHeader("Connection", "keep-alive") +headers_gzip = _headers.copy() +headers_gzip.addRawHeader("Accept-Encoding", "gzip, deflate") +headersplain = _headers.copy() +headersplain.setRawHeaders("content-type", ["text/plain; charset=UTF-8"]) +headers_ts = Headers({"User-Agent": ["GStreamer souphttpsrc libsoup/2.52.2"]}) +headers_ts.setRawHeaders("content-type", ["application/x-mpegURL"]) +headers_dash = _headers.copy() +headers_dash.setRawHeaders("content-type", ["application/dash+xml"]) +_headers_jpeg = _headers.copy() +_headers_jpeg.setRawHeaders("content-type", ["image/jpeg"]) +_headers_svg = _headers.copy() +_headers_svg.setRawHeaders("content-type", ["image/svg+xml"]) +_headers_json = _headers.copy() +_headers_json.setRawHeaders("content-type", ["application/json; charset=utf-8"]) + + +_downloads = dict() +_downloads["state"] = True + + +def MyCallLater(ltime, iscallable, *args, **kwargs): + logger.info("...") + return reactor.callLater(ltime, iscallable, *args, **kwargs) + + +class CallLater: + def __init__(self, result, iscallable, *args, **kwargs): + logger.info("...") + reactor.callLater(0, iscallable, result, *args, **kwargs) + + def __del__(self): + logger.info("...") + + +class MyDeferredSemaphore: + def __init__(self, tokens=1): + logger.info("...") + self.ds = DeferredSemaphore(tokens=tokens) + self._deferreds = [] + self.work = dict() + _downloads["state"] = True + + def run(self, *args, **kwargs): + logger.info("...") + return self.ds.run(*args, **kwargs) + + def rundeferLater(self, ltime=0.0, *args, **kwargs): + logger.info("...") + return deferLater(reactor, ltime, self.ds.run, *args, **kwargs) + + def start(self, *args, **kwargs): + logger.info("...") + return self.rundeferLater(0.0, *args, **kwargs) + + def deferCanceler(self, _cancel=True): + logger.info("...") + for items in self.ds.waiting: + items.cancel() + + def settokens(self, tokens=10): + logger.info("...") + self.ds.tokens = tokens + self.ds.limit = tokens + + def finished(self): + logger.info("...") + return self.ds.tokens >= self.ds.limit + + def __del__(self): + logger.info("...") + self.deferCanceler() + self.work.clear() + + +class _MyClientTLSOptions(ClientTLSOptions): + def _identityVerifyingInfoCallback(self, connection, where, _ret): + logger.info("...") + if where & _SSL.SSL_CB_HANDSHAKE_START: + connection.set_tlsext_host_name(self._hostnameBytes) + elif where & _SSL.SSL_CB_HANDSHAKE_DONE: + try: + verifyHostname(connection, self._hostnameASCII) + except (CertificateError, VerificationError) as e: + logger.debug("Remote certificate is not valid for hostname %s; %s", self._hostnameASCII, e) + except ValueError as e: + logger.debug("Ignoring error while verifying certificate from host %s (exception: %s)", self._hostnameASCII, repr(e)) + + +try: + MyClientTLSOptions = ClientTLSOptions +except Exception: + MyClientTLSOptions = _MyClientTLSOptions + + +class ClientContextFactory(ssl_ClientContextFactory): + def __init__(self): + logger.info("...") + self.method = _SSL.SSLv23_METHOD + + def getContext(self, hostname=None, _port=None): + logger.info("...") + ctx = self._contextFactory(self.method) + ctx.set_options(_SSL.OP_SINGLE_DH_USE | _SSL.OP_NO_SSLv2 | _SSL.OP_NO_SSLv3 | _SSL.OP_ALL) + ctx.set_session_cache_mode(_SSL.SESS_CACHE_BOTH) + if hostname: + MyClientTLSOptions(hostname, ctx) + return ctx + + +defaultCiphers = AcceptableCiphers.fromOpenSSLCipherString( + "TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:" + "TLS13-AES-128-GCM-SHA256:" + "ECDH+AESGCM:ECDH+CHACHA20:DH+AESGCM:DH+CHACHA20:ECDH+AES256:DH+AES256:" + "ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:" + "!aNULL:!MD5:!DSS") + + +class ClientContextFactory__(BrowserLikePolicyForHTTPS): + + def _getCertificateOptions(self, _hostname, _port): + logger.info("...") + return CertificateOptions(verify=False, method=_SSL.SSLv23_METHOD, fixBrokenPeers=True, acceptableCiphers=defaultCiphers, ) + + @_requireSSL + def getContext(self, hostname=None, port=None): + logger.info("...") + return self._getCertificateOptions(hostname, port).getContext() + + @_requireSSL + def creatorForNetloc(self, hostname, port): + logger.info("...") + return MyClientTLSOptions(hostname.decode("ascii"), self.getContext(hostname, port)) + + +class MyRedirectAgent(RedirectAgent): + _redirectResponses = [http.MOVED_PERMANENTLY, http.FOUND] + _seeOtherResponses = [http.SEE_OTHER] + + +class mydownloadWithProgress: + def __init__(self, url, fileOrName, headers=None, *args, **kwargs): + logger.info("...") + self.factory = getPagenew(url=url, fileOrName=fileOrName, headers=headers, *args, **kwargs) + + def start(self): + logger.info("...") + return self.factory.deferred + + def stop(self): + logger.info("...") + self.factory.deferred.cancel() + + def addProgress(self, progress_callback): + logger.info("...") + self.factory.progress_callback = progress_callback + + +def MydownloadPage(url, file=None, method="GET", headers=_headers, postdata=None, contextFactory=ClientContextFactory(), *args, **kwargs): + logger.info("...") + return getPagenew(url, file, method, headers, postdata, contextFactory, *args, **kwargs).deferred + + +def MygetPage(url, fileOrName=None, method="GET", headers=_headers, postdata=None, contextFactory=ClientContextFactory(), *args, **kwargs): + logger.info("...") + return getPagenew(url, fileOrName, method, headers, postdata, contextFactory, *args, **kwargs).deferred + + +@implementer(IBodyProducer) +class StringProducer(object): + def __init__(self, body): + logger.info("...") + self.body = body + self.length = len(body) + + def startProducing(self, consumer): + logger.info("...") + consumer.write(self.body) + return succeed(None) + + def pauseProducing(self): + logger.info("...") + + def stopProducing(self): + logger.info("...") + + +class ReadBodyProtocol(Protocol): + def __init__(self, status, message, deferred): + logger.info("...") + self.deferred = deferred + self.status = status + self.message = message + self.dataBuffer = [] + + def dataReceived(self, data): + logger.info("...") + self.dataBuffer.append(data) + + def connectionLost(self, reason): + logger.info("...") + if reason.check(ResponseDone): + self.deferred.callback(b"".join(self.dataBuffer)) + elif reason.check(PotentialDataLoss): + self.deferred.errback(PartialDownloadError(self.status, self.message, b"".join(self.dataBuffer))) + else: + self.deferred.errback(reason) + + +class ReadBodyURI(Protocol): + def __init__(self, deferred, response): + logger.info("...") + self.deferred = deferred + self._response = response + self.dataBuffer = [] + + def dataReceived(self, data): + logger.info("...") + self.dataBuffer.append(data) + + def connectionLost(self, reason): + logger.info("...") + if reason.check(ResponseDone): + self.deferred.callback((b"".join(self.dataBuffer), self._response.request.absoluteURI)) + elif reason.check(PotentialDataLoss): + self.deferred.errback(PartialDownloadError(self._response.code, self._response.phrase, b"".join(self.dataBuffer))) + else: + self.deferred.errback(reason) + + +class ReadBody(Protocol): + def __init__(self, finished, response, fileOrName, progress_callback): + logger.info("...") + self.finished = finished + self._response = response + self.currentbytes = 0.0 + self.progress_callback = progress_callback + self.datafile = None + if isinstance(fileOrName, str): + self.datafile = open(fileOrName, "wb") + else: + self.datafile = fileOrName + + def dataReceived(self, data): + logger.info("...") + try: + if self.finished.called: + return + if self.datafile: + self.datafile.write(data) + self.currentbytes += len(data) + if self._response.length and self.progress_callback: + self.progress_callback(self.currentbytes, self._response.length) + except IOError: + self.finished.errback(Failure()) + + def connectionLost(self, reason): + logger.info("...") + if self.datafile: + try: + self.datafile.close() + except Exception: + self.finished.errback(Failure()) + + if reason.check(ResponseDone): + self.finished.callback(None) + elif reason.check(PotentialDataLoss): + self.finished.errback(Failure()) + else: + self.finished.errback(reason) + + +class getPagenew(object): + progress_callback = None + + def __init__(self, url, fileOrName=None, method="GET", headers=None, postdata=None, contextFactory=ClientContextFactory(), location=None, timeout=10.0, cookies=None, *args, **kwargs): + logger.info("...") + body = None + if postdata: + body = StringProducer(postdata) + pool = HTTPConnectionPool(reactor, persistent=True) + pool.maxPersistentPerHost = 10 + pool.cachedConnectionTimeout = 600 + pool.retryAutomatically = True + pool._factory.noisy = False + + agent = MyRedirectAgent(Agent(reactor, contextFactory=contextFactory, connectTimeout=timeout, bindAddress=None, pool=pool)) + cookieJar = None + if cookies: + cookieJar = CookieJar() + agent = CookieAgent(agent, cookieJar) + + self.deferred = agent.request(method=method, uri=url, headers=headers, bodyProducer=body) + self.deferred.addCallback(self.calresponse, fileOrName, location, cookieJar, *args, **kwargs) + + def calresponse(self, response, fileOrName, location, cookieJar, *args, **kwargs): + def _cancel(_): + logger.info("...") + try: + response._transport._producer.abortConnection() + except Exception: + pass + + logger.info("...") + finished = Deferred(canceller=_cancel) + if "CallbackResponse" in kwargs: + kwargs["CallbackResponse"](self, response, fileOrName, location, cookieJar, *args, **kwargs) + if response.code not in (200, 301, 302, 303): + raise ResponseFailed("{0} {1}".format(response.code, response.phrase), response) + gzipdecoder = "gzip" in response.headers.getRawHeaders("Content-Encoding", "none") + + if not location and gzipdecoder: + response.deliverBody(_GzipProtocol(ReadBodyProtocol(response.code, response.phrase, finished), response)) + elif fileOrName: + response.deliverBody(ReadBody(finished, response, fileOrName, self.progress_callback)) + elif location: + if gzipdecoder: + response.deliverBody(_GzipProtocol(ReadBodyURI(finished, response), response)) + else: + response.deliverBody(ReadBodyURI(finished, response)) + else: + response.deliverBody(ReadBodyProtocol(response.code, response.phrase, finished)) + return finished + + def calerr(self, _err): + logger.info("...") + + +def writerawheaders(response, *_args, **_kwargs): + logger.info("...") + with open("/tmp/rawheaders.json", "w") as fp: + json.dump(list(response.headers.getAllRawHeaders()), fp, encoding="utf-8", indent=2, sort_keys=True) + + +def http_failed(failure_instance=None, *_args, **kwargs): + logger.info("...") + error_message = str(failure_instance.getErrorMessage()) + if not error_message: + error_message = str(failure_instance) + text = _(kwargs.get("title", "Error")) + "\n" + text += _("Error during download") + "\n\n" + error_message + "\n" + logger.error("error_message: %s", error_message) + try: + if mysession: + mysession.toastManager.showToast(text, int(kwargs.get("duration", 20))) + except Exception as e: + logger.error("exception: %s", e) diff --git a/src/EventDetails.py b/src/EventDetails.py new file mode 100755 index 0000000..eff2415 --- /dev/null +++ b/src/EventDetails.py @@ -0,0 +1,153 @@ +# !/usr/bin/python +# coding=utf-8 +# +# Copyright (C) 2018-2024 by dream-alpha +# +# In case of reuse of this source code please do not remove this copyright. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# For more information on the GNU General Public License see: +# . + + +import os +from time import strftime, localtime +from Screens.Screen import Screen +from Components.ActionMap import ActionMap +from Components.Label import Label +from Components.Pixmap import Pixmap +from Components.ScrollLabel import ScrollLabel +from Components.AVSwitch import AVSwitch +from Tools.Directories import pathExists +from Tools.LoadPixmap import LoadPixmap +from Downloader import headers_gzip, MydownloadPage, MyDeferredSemaphore, http_failed +from enigma import eServiceReference, ePicLoad +from StreamPlayer import StreamPlayer +from .Debug import logger +from .Constants import TMP_DIR, TVS, EVENT_IDX_SUBLINE, EVENT_IDX_EPISODE_TITLE, EVENT_IDX_YEAR, EVENT_IDX_VIDEOS, EVENT_IDX_IMAGES, EVENT_IDX_TITLE, EVENT_IDX_TIME_START, EVENT_IDX_TIME_END, EVENT_IDX_TEXT +from .PictureUtils import getPicon, getVideo, getEventPicUrl +from .__init__ import _ + + +class EventDetails(Screen): + def __init__(self, session, channel, list_event): + logger.info("...") + self.list_event = list_event + self.channel = channel + Screen.__init__(self, session) + self.skinName = "EventDetails" + self["description"] = ScrollLabel() + self["actions"] = ActionMap( + ["TVC_Actions"], + { + "ok": self.key_ok, + "cancel": self.close, + "up": self["description"].pageUp, + "left": self["description"].pageUp, + "down": self["description"].pageDown, + "right": self["description"].pageDown + } + ) + self["programpix"] = Pixmap() + self["videopix"] = Pixmap() + self["channelpix"] = Pixmap() + self["daumenpix"] = Pixmap() + + self["title"] = Label() + self["episodetitle"] = Label() + self["timeduration"] = Label() + + self.picload = ePicLoad() + self.picload_conn = self.picload.PictureData.connect(self.__finish_decode) + self.deferreds = [] + self.download = MyDeferredSemaphore(tokens=12) + + self.onClose.append(self.__onClose__) + self.onLayoutFinish.append(self.createsetup) + + def createsetup(self): + logger.info("...") + logger.debug("list_event: %s", self.list_event) + self.setTitle("%s - %s" % (TVS, _("Event Details"))) + year = self.list_event[EVENT_IDX_YEAR] + # genre = self.list_event[EVENT_IDX_GENRE] + title = self.list_event[EVENT_IDX_TITLE] + if year: + title += " (%s)" % year + self["title"].setText(title) + episodetitle = self.list_event[EVENT_IDX_EPISODE_TITLE] + subline = self.list_event[EVENT_IDX_SUBLINE] + self["episodetitle"].setText(episodetitle if episodetitle else subline) + start = strftime("%H:%M", localtime(int(self.list_event[EVENT_IDX_TIME_START]))) + duration = (int(self.list_event[EVENT_IDX_TIME_END]) - int(self.list_event[EVENT_IDX_TIME_START])) / 60 + self["timeduration"].setText("%s, %s %s" % (start, duration, _("min"))) + self["channelpix"].setPixmap(getPicon(self.channel["id"], self.channel["service"])) + self["description"].setText(self.list_event[EVENT_IDX_TEXT]) + + url = getEventPicUrl(self.list_event[EVENT_IDX_IMAGES]) + if url: + afile = os.path.join(TMP_DIR, "programpix%s" % url[-4:]) + self.download.run(MydownloadPage, url, afile, headers=headers_gzip).addCallback(self.result_back_pic, self["programpix"], afile).addErrback(http_failed) + + self.video_title, url, self.video_url = getVideo(self.list_event[EVENT_IDX_VIDEOS]) + if url: + afile = os.path.join(TMP_DIR, "videopix%s" % url[-4:]) + self.download.run(MydownloadPage, url, afile, headers=headers_gzip).addCallback(self.result_back_pic2, self["videopix"], afile).addErrback(http_failed) + + def result_back_pic(self, result, pixmap, afile): + logger.info("result: %s", result) + logger.info("afile: %s", afile) + pixmap.instance.setPixmap(LoadPixmap(afile)) + + def result_back_pic2(self, result, pixmap, afile): + logger.info("result: %s", result) + logger.info("afile: %s", afile) + self.loadscalePixmap(pixmap, afile) + + def loadscalePixmap(self, pixmap, afile=""): + logger.info("afile: %s, pixmap: %s", afile, pixmap) + if pathExists(afile): + # pixmap.instance.setPixmap(gPixmapPtr()) + scale = AVSwitch().getFramebufferScale() + size = pixmap.instance.size() + self.picload.setPara( + (size.width(), size.height(), scale[0], scale[1], False, 1, "#00000000") + ) + self.picload.startDecode(afile) + + def __finish_decode(self, _picInfo): + logger.info("...") + ptr = self.picload.getData() + if ptr is not None: + self["videopix"].instance.setPixmap(ptr) + + def deferCanceler(self): + logger.info("...") + for items in self.deferreds: + if items.paused >= 0: + items.pause() + if not items.called: + items.cancel() + self.deferreds.remove(items) + + def key_ok(self): + logger.info("...") + if self.video_url and self.video_url.endswith(("mp4")): + sref = eServiceReference(eServiceReference.idGST, 0, self.video_url) + sref.setName(self.video_title) + self.session.open(StreamPlayer, sref) + + def __onClose__(self): + logger.info("...") + del self.picload_conn + del self.picload + self.deferCanceler() diff --git a/src/EventList.py b/src/EventList.py new file mode 100644 index 0000000..4813efe --- /dev/null +++ b/src/EventList.py @@ -0,0 +1,95 @@ +# !/usr/bin/python +# coding=utf-8 +# +# Copyright (C) 2018-2024 by dream-alpha +# +# In case of reuse of this source code please do not remove this copyright. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# For more information on the GNU General Public License see: +# . + + +from Components.HTMLComponent import HTMLComponent +from Components.TemplatedMultiContentComponent import TemplatedMultiContentComponent +from enigma import eListbox +from .SkinUtils import getSkinPath +from .FileUtils import readFile +from .Debug import logger + + +class EventList(HTMLComponent, TemplatedMultiContentComponent, object): + + COMPONENT_ID = "" + default_template = "" + + def __init__(self, alist=None, component_id="", default_template_name=""): + logger.info("...") + self.skinAttributes = [] + EventList.default_template = readFile(getSkinPath(default_template_name)) + EventList.COMPONENT_ID = component_id + TemplatedMultiContentComponent.__init__(self) + self.list = alist if alist else [] + + def getCurrent(self): + logger.info("...") + return self.l.getCurrentSelection() + + GUI_WIDGET = eListbox + + def postWidgetCreate(self, instance): + logger.info("...") + instance.setContent(self.l) + + def preWidgetRemove(self, instance): + logger.info("...") + instance.setContent(None) + + def moveToIndex(self, index): + logger.info("...") + self.instance.moveSelectionTo(index) + + def getCurrentIndex(self): + logger.info("...") + return self.instance.getCurrentIndex() + + def moveUp(self): + logger.info("...") + if self.instance is not None: + self.instance.moveSelection(self.instance.moveUp) + + def moveDown(self): + logger.info("...") + if self.instance is not None: + self.instance.moveSelection(self.instance.moveDown) + + def moveLeft(self): + logger.info("...") + if self.instance is not None: + self.instance.moveSelection(self.instance.moveLeft) + + def moveRight(self): + logger.info("...") + if self.instance is not None: + self.instance.moveSelection(self.instance.moveRight) + + def invalidate(self): + logger.info("...") + self.l.invalidate() + + def entryRemoved(self, index): + logger.info("...") + self.l.entryRemoved(index) + + def setSelectionEnable(self, selectionEnabled=True): + logger.info("...") + self.instance.setSelectionEnable(selectionEnabled) diff --git a/src/FileUtils.py b/src/FileUtils.py new file mode 100644 index 0000000..71cdf07 --- /dev/null +++ b/src/FileUtils.py @@ -0,0 +1,88 @@ +#!/usr/bin/python +# coding=utf-8 +# +# Copyright (C) 2018-2024 by dream-alpha +# +# In case of reuse of this source code please do not remove this copyright. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# For more information on the GNU General Public License see: +# . + + +import os +from pipes import quote +import glob +from .Debug import logger + + +def stripCutNumber(path): + filename, ext = os.path.splitext(path) + if len(filename) > 3: + if filename[-4] == "_" and filename[-3:].isdigit(): + filename = filename[:-4] + path = filename + ext + return path + + +def readFile(path): + data = "" + try: + with open(path, "r") as f: + data = f.read() + except Exception as e: + logger.info("path: %s, exception: %s", path, e) + return data + + +def writeFile(path, data): + try: + with open(path, "w") as f: + f.write(data) + except Exception as e: + logger.error("path: %s, exception: %s", path, e) + + +def deleteFile(path): + os.popen("rm %s" % quote(path)).read() + + +def deleteFiles(path, clear=False): + for afile in glob.glob(path): + if clear: + writeFile(afile, "") + deleteFile(afile) + + +def touchFile(path): + os.popen("touch %s" % quote(path)).read() + + +def copyFile(src_path, dest_path): + os.popen("cp %s %s" % (quote(src_path), quote(dest_path))).read() + + +def renameFile(src_path, dest_path): + os.popen("mv %s %s" % (quote(src_path), quote(dest_path))).read() + + +def createDirectory(path): + os.popen("mkdir -p %s" % quote(path)).read() + + +def createSymlink(src, dst): + logger.info("link: src: %s > %s", src, dst) + os.symlink(src, dst) + + +def deleteDirectory(path): + os.popen("rm -rf %s" % quote(path)).read() diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..65b79ed --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,4 @@ +installdir = $(libdir)/enigma2/python/Plugins/Extensions/TVMagazineCockpit +SUBDIRS = skin +install_PYTHON = *.py +install_DATA = *.png *.xml diff --git a/src/Menu.py b/src/Menu.py new file mode 100755 index 0000000..bb0b645 --- /dev/null +++ b/src/Menu.py @@ -0,0 +1,102 @@ +# !/usr/bin/python +# coding=utf-8 +# +# Copyright (C) 2018-2024 by dream-alpha +# +# In case of reuse of this source code please do not remove this copyright. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# For more information on the GNU General Public License see: +# . + + +from Components.config import config +from Components.UsageConfig import preferredTimerPath +from RecordTimer import RecordTimerEntry +from Screens.TimerEdit import TimerSanityConflict +from Screens.TimerEntry import TimerEntry +from Screens.ChoiceBox import ChoiceBox +from enigma import eServiceReference +from ServiceReference import ServiceReference +from .__init__ import _ +from .Debug import logger +from .Version import PLUGIN +from .ZapUtils import Zap_Service +from .Constants import EVENT_IDX_TIME_START, EVENT_IDX_TIME_END, EVENT_IDX_TITLE, EVENT_IDX_GENRE +from .PluginUtils import getPlugin, WHERE_MEDIATHEK_SEARCH, WHERE_TMDB_MOVIELIST +from .ServiceUtils import getService + + +class Menu(): + def __init__(self): + logger.info("...") + self.mediathek_plugin = getPlugin(WHERE_MEDIATHEK_SEARCH) + self.tmdb_plugin = getPlugin(WHERE_TMDB_MOVIELIST) + + def openMenu(self, service, event): + logger.info("service: %s", service) + logger.info("event: %s", event) + self.service = service + self.event = event + alist = [ + ("%s" % _("Zap"), "zap"), + ("%s" % _("Add Timer"), "timer"), + ] + if self.mediathek_plugin: + alist.append(("%s" % self.mediathek_plugin.description, "mediathek_search")) + if self.tmdb_plugin: + alist.append(("%s" % self.tmdb_plugin.description, "tmdb_search")) + + self.session.openWithCallback( + self.openMenuCallback, + ChoiceBox, + title=PLUGIN, + list=alist, + windowTitle=_("Menu"), + allow_cancel=True, + titlebartext=_("Input") + ) + + def openMenuCallback(self, answer=None): + logger.info("...") + if answer: + action = answer[1] + if action == "zap": + Zap_Service(self.service) + self.close() + elif action == "timer": + serviceref = ServiceReference(eServiceReference(self.service)) + begin = int(self.event[EVENT_IDX_TIME_START]) - config.recording.margin_before.value * 60 + end = int(self.event[EVENT_IDX_TIME_END]) + config.recording.margin_after.value * 60 + eventdata = (begin, end, self.event[EVENT_IDX_TITLE], self.event[EVENT_IDX_GENRE], None) + newEntry = RecordTimerEntry(serviceref, checkOldTimers=True, dirname=preferredTimerPath(), *eventdata) + self.session.openWithCallback(self.finishedAdd, TimerEntry, newEntry) + elif action == "mediathek_search": + self.mediathek_plugin(self.session, self.event[EVENT_IDX_TITLE]) + elif action == "tmdb_search": + service = getService("", self.event[EVENT_IDX_TITLE]) + self.tmdb_plugin(self.session, service) + + def finishedAdd(self, answer): + logger.info("...") + if answer[0]: + entry = answer[1] + simulTimerList = self.session.nav.RecordTimer.record(entry) + if simulTimerList is not None: + for x in simulTimerList: + if x.setAutoincreaseEnd(entry): + self.session.nav.RecordTimer.timeChanged(x) + simulTimerList = self.session.nav.RecordTimer.record(entry) + if simulTimerList is not None: + self.session.openWithCallback(self.finishedAdd, TimerSanityConflict, simulTimerList) + else: + logger.debug("Timeredit aborted") diff --git a/src/More.py b/src/More.py new file mode 100755 index 0000000..564ecf0 --- /dev/null +++ b/src/More.py @@ -0,0 +1,105 @@ +# !/usr/bin/python +# coding=utf-8 +# +# Copyright (C) 2018-2024 by dream-alpha +# +# In case of reuse of this source code please do not remove this copyright. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# For more information on the GNU General Public License see: +# . + + +from Screens.ChoiceBox import ChoiceBox +from Components.config import config +from .__init__ import _ +from .Debug import logger +from .ConfigScreen import ConfigScreen +from .ChannelManagement import ChannelManagement +from .ConfigInit import bouquet_choices +from .About import about +from .Version import PLUGIN + + +class More(): + def __init__(self): + logger.info("...") + + def openMore(self, bouquet, channel_list, channel_dict): + logger.info("...") + self.bouquet = bouquet + self.channel_list = channel_list + self.channel_dict = channel_dict + alist = [ + ("%s" % _("Bouquet Selection"), "bouquetselection"), + ("%s" % _("Bouquet Setup"), "channel"), + ("%s" % _("Settings"), "settings"), + ("%s" % _("About"), "about"), + ] + + self.session.openWithCallback( + self.openMoreCallback, + ChoiceBox, + title=PLUGIN, + list=alist, + windowTitle=_("More"), + allow_cancel=True, + titlebartext=_("Input") + ) + + def openMoreCallback(self, answer=None): + logger.info("...") + if answer: + screen = answer[1] + if screen == "channel": + self.session.openWithCallback( + self.openChannelManagementCallback, + ChannelManagement, + self.bouquet, + self.channel_list, + self.channel_dict, + ) + elif screen == "settings": + self.session.openWithCallback( + self.openConfigScreenCallback, + ConfigScreen, + config.plugins.tvmagazinecockpit + ) + elif screen == "bouquetselection": + alist = [(value[1], value[0]) for value in bouquet_choices] + self.session.openWithCallback( + self.openBouquetSelectionCallback, + ChoiceBox, + title="Bouquet Selection", + list=alist, + windowTitle=_("Bouquet Selection"), + allow_cancel=True, + titlebartext=_("Input") + ) + elif screen == "about": + about(self.session) + + def openConfigScreenCallback(self, _result=None): + logger.info("...") + self.reload() + + def openChannelManagementCallback(self, channel_list): + logger.info("...") + self.channel_list = channel_list + self.reload() + + def openBouquetSelectionCallback(self, bouquet): + logger.info("bouquet: %s", bouquet) + if bouquet: + config.plugins.tvmagazinecockpit.bouquet.value = bouquet[1] + config.plugins.tvmagazinecockpit.bouquet.save() + self.close("programcolumns") diff --git a/src/MyList.py b/src/MyList.py new file mode 100644 index 0000000..0b02bca --- /dev/null +++ b/src/MyList.py @@ -0,0 +1,64 @@ +# !/usr/bin/python +# coding=utf-8 +# +# Copyright (C) 2018-2024 by dream-alpha +# +# In case of reuse of this source code please do not remove this copyright. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# For more information on the GNU General Public License see: +# . + + +from Components.Sources.List import List +from .Debug import logger + + +class MyList(List): + def __init__(self, alist=None, enableWrapAround=False, item_height=25, fonts=None, buildfunc=None): + logger.info("...") + if alist is None: + alist = [] + if fonts is None: + fonts = [] + List.__init__(self, list=alist, enableWrapAround=enableWrapAround, item_height=item_height, fonts=fonts, buildfunc=buildfunc) + + def extendList(self, alist): + logger.info("...") + self.list.extend(alist) + self.changed((self.CHANGED_ALL, )) + + def sort(self, key=0): + logger.info("...") + self.list.sort(key=key) + self.changed((self.CHANGED_ALL, )) + + def deleteEntry(self): + logger.info("...") + index = self.master.getIndex() + del self.list[index] + self.setList(self.list) + self.master.setIndex(index) + self.entry_changed(index) + + def clearList(self): + logger.info("...") + if self.list: + del self.list[:] + self.changed((self.CHANGED_CLEAR, )) + + def modifyEntryVal(self, index, data, indexval): + self.list[index][indexval] = data + self.entry_changed(index) + + def getList(self): + return self.list[:] diff --git a/src/PictureUtils.py b/src/PictureUtils.py new file mode 100644 index 0000000..e7f82c2 --- /dev/null +++ b/src/PictureUtils.py @@ -0,0 +1,60 @@ +# !/usr/bin/python +# coding=utf-8 +# +# Copyright (C) 2018-2024 by dream-alpha +# +# In case of reuse of this source code please do not remove this copyright. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# For more information on the GNU General Public License see: +# . + + +from Components.config import config +from Tools.LoadPixmap import LoadPixmap +from .ConfigInit import plugindir +from .Debug import logger + + +def getPicon(channel_id, service=""): + logger.info("channel_id: %s, service: %s", channel_id, service) + pixmap_ptr = None + if service and config.plugins.tvmagazinecockpit.use_picons.value: + picons_dir = config.usage.configselection_piconspath.value + pixmap_ptr = LoadPixmap("%s/%s.png" % (picons_dir, service[:-1].replace(":", "_"))) + if not pixmap_ptr: + pixmap_ptr = LoadPixmap("%slogos/%s.png" % (plugindir, channel_id)) + return pixmap_ptr + + +def getVideo(videos): + logger.debug("videos: %s", videos) + title = video_url = still_image_url = "" + if len(videos) > 0: + video_list = videos[0].get("video", "") + video = video_list[0] + logger.debug("video: %s", video) + title = videos[0].get("title", "") + still_image_url = videos[0].get("stillImage", "") + video_url = video.get("url", "") + logger.debug("title: %s, still_image_url: %s, video_url: %s", title, still_image_url, video_url) + return title, still_image_url, video_url + + +def getEventPicUrl(images): + logger.debug("images: %s", images) + url = "" + if len(images) > 0: + image = images[0] + url = image.get("size4", "") + logger.debug("programpix url: %s", url) + return url diff --git a/src/PluginUtils.py b/src/PluginUtils.py new file mode 100644 index 0000000..0cbc972 --- /dev/null +++ b/src/PluginUtils.py @@ -0,0 +1,37 @@ +#!/usr/bin/python +# coding=utf-8 +# +# Copyright (C) 2018-2024 by dream-alpha +# +# In case of reuse of this source code please do not remove this copyright. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# For more information on the GNU General Public License see: +# . + + +from Components.PluginComponent import plugins + + +WHERE_SEARCH = -99 +WHERE_TMDB_SEARCH = -98 +WHERE_TMDB_MOVIELIST = -97 +WHERE_MEDIATHEK_SEARCH = -96 +WHERE_TVMAGAZINE_SEARCH = -95 + + +def getPlugin(where): + plugin = None + plugins_list = plugins.getPlugins(where=where) + if len(plugins_list) > 0: + plugin = plugins_list[0] + return plugin diff --git a/src/ProgramColumns.py b/src/ProgramColumns.py new file mode 100755 index 0000000..07ee860 --- /dev/null +++ b/src/ProgramColumns.py @@ -0,0 +1,407 @@ +# !/usr/bin/python +# coding=utf-8 +# +# Copyright (C) 2018-2024 by dream-alpha +# +# In case of reuse of this source code please do not remove this copyright. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# For more information on the GNU General Public License see: +# . + + +import os +import time +from datetime import datetime +from time import strftime, localtime +from math import ceil +from enigma import gPixmapPtr +from Screens.Screen import Screen +from Components.ActionMap import ActionMap +from Components.Label import Label +from Components.Pixmap import Pixmap +from Components.Sources.StaticText import StaticText +from Components.config import config +from Tools.LoadPixmap import LoadPixmap +from .Downloader import headers_gzip, MydownloadPage, http_failed, MyDeferredSemaphore +from .EventDetails import EventDetails +from .More import More +from .Menu import Menu +from .__init__ import _ +from .EventList import EventList +from .Debug import logger +from .TVSpielfilmData import TVSpielfilmData +from .Constants import TMP_DIR, TVS, BOUQUETS, EVENT_IDX_YEAR, EVENT_IDX_IMAGES, EVENT_IDX_TITLE, EVENT_IDX_EPISODE_TITLE, EVENT_IDX_SUBLINE, EVENT_IDX_TIME_START, EVENT_IDX_BROADCASTER_NAME +from .PictureUtils import getEventPicUrl, getPicon +from .FileUtils import deleteDirectory +from .ChannelUtils import read_channel_list + + +class ProgramColumns(Screen, More, Menu): + def __init__(self, session, channel_dict): + logger.info("...") + self.bouquet = config.plugins.tvmagazinecockpit.bouquet.value + self.channel_list = read_channel_list(self.bouquet) + self.channel_dict = channel_dict + Screen.__init__(self, session) + self.skinName = "ProgramColumns" + More.__init__(self) + Menu.__init__(self) + self["actions"] = ActionMap( + ["TVC_Actions", "NumberActions"], + { + "0": self.reload, + "ok": self.key_ok, + "cancel": self.close, + "info": self.key_ok, + "up": self.moveUp, + "down": self.moveDown, + "left": self.left, + "right": self.right, + "next": self.key_next, + "back": self.key_back, + "red": self.key_red, + "green": self.key_green, + "yellow": self.key_yellow, + "blue": self.key_blue, + "menu": self.showMenu, + "channelup": self.channelup, + "channeldown": self.channeldown, + } + ) + + self.tvs_data_mgr = TVSpielfilmData(self.showChannel) + self.events = {} + self.cols = 6 + self.list_columns = [[]] * self.cols + self.list_prime = [[]] * self.cols + self.list_indices = [-1] * self.cols + self.listindex = 0 + self.page_index = 0 + self.pages = 0 + + self["searchdate"] = Label() + + for i in range(self.cols): + self["list%s" % i] = EventList(None, "ProgramColumns", "screenpart_program_template.tpl") + self["channel%s" % i] = Label() + self["channelpix%s" % i] = Pixmap() + self["programpix%s" % i] = Pixmap() + self["time%s" % i] = Label() + self["description%s" % i] = Label() + + self.first = True + self.mytimecount = 1 + mytime = int(time.time()) - 24 * 60 * 60 + self.timelist = [] + for _day in range(0, 15): + self.timelist.append([strftime("< %A, %d. %b %Y >", localtime(mytime)), strftime("%Y-%m-%d", localtime(mytime))]) + mytime = mytime + 24 * 60 * 60 + + self["key_red"] = StaticText(_("More") + " ...") + self["key_green"] = StaticText(_("20:15")) + self["key_yellow"] = StaticText(_("22:00")) + self["key_blue"] = StaticText(_("Now")) + + self.download = MyDeferredSemaphore(tokens=100) + self.onClose.append(self.__onClose__) + self.onLayoutFinish.append(self.reload) + + def downloadChannel(self, channel, i): + logger.info("channel: %s", channel) + if self.channel_list: + self.tvs_data_mgr.downloadEvents(channel, self.day, i) + else: + self.showPage() + + def showPage(self): + logger.info("...") + # logger.info("self.events: %s", self.events) + title = "%s %s - %s: %s" % (TVS, _("column view"), BOUQUETS[self.bouquet], _("Loading...")) + self.setTitle(title) + self.clearValues() + start = self.page_index * 6 + stop = min(start + 6, len(self.channel_list)) + self.page_list = self.channel_list[start:stop] + logger.debug("page_list: %s", self.page_list) + + for i, channel_name in enumerate(self.page_list): + channel = self.channel_dict.get(channel_name, None) + if channel: + channel_id = channel["id"] + self["channel%s" % i].setText(channel_id) + # self["description%s" % i].setText(_("no event info avilable")) + if self.day in self.events and channel_id in self.events[self.day]: + logger.debug("data already available") + self.showChannel(self.events, channel, i) + else: + logger.debug("need to download data") + self.downloadChannel(channel, i) + if len(self.page_list) == 0: + title = "%s %s - %s: %s: %s/%s, %s: %s" % (TVS, _("column view"), BOUQUETS[self.bouquet], _("Page"), self.page_index + 1, self.pages, _("Services"), len(self.channel_list)) + self.setTitle(title) + + def showChannel(self, events, channel, i): + + def createListEntry(event): + entry = [] + start_time = strftime("%H:%M", localtime(int(event[EVENT_IDX_TIME_START]))) + entry.append(start_time) + entry.append(event[EVENT_IDX_TITLE]) + sub_title = event[EVENT_IDX_EPISODE_TITLE] + if not sub_title: + sub_title = event[EVENT_IDX_SUBLINE] + entry.append(sub_title) + entry.append(str(event[EVENT_IDX_YEAR])) + entry.append(int(event[EVENT_IDX_TIME_START])) + return entry + + logger.info("i: %s", i) + channel_id = channel["id"] + self.events = events + tmp_list = [] + prime_time = self.getPointInTime("20:15") + prime_diff = prime_time + self.list_prime[i] = None + now_time = self.point_in_time + now_diff = now_time + now_index = 0 + for event_index, event in enumerate(events[self.day][channel_id]): + tmp = createListEntry(event) + event_time = int(event[EVENT_IDX_TIME_START]) + event_diff = abs(prime_time - event_time) + # logger.debug("event_time: %s, event_diff: %s, prime_diff: %s", event_time, event_diff, prime_diff) + if event_diff < prime_diff: + prime_diff = event_diff + self.list_prime[i] = event + # logger.debug("new prime diff: %s", prime_diff) + + event_diff = abs(now_time - event_time) + # logger.debug("event_time: %s, event_diff: %s, now_diff: %s", event_time, event_diff, now_diff) + if event_diff < now_diff: + now_diff = event_diff + now_index = event_index + # logger.debug("new now diff: %s, index: %s", now_diff, now_index) + tmp_list.append(tmp) + + if self.list_prime[i]: + self.showPrimeEvent(self.list_prime[i], i, channel) + + self.list_columns[i] = tmp_list + self.list_indices[i] = now_index + + sub_list = self.list_columns[i][self.list_indices[i] - 1:self.list_indices[i] + 4] + j = len(sub_list) + while j < 5: + sub_list.append(["", "", "", "", 0]) + j += 1 + + self["list%s" % i].l.setList(sub_list) + self["list%s" % i].moveToIndex(1) + if i == 0 and self.first: + self.first = False + self["list0"].setSelectionEnable(True) + title = "%s %s - %s: %s: %s/%s, %s: %s" % (TVS, _("column view"), BOUQUETS[self.bouquet], _("Page"), self.page_index + 1, self.pages, _("Services"), len(self.channel_list)) + self.setTitle(title) + + def showPrimeEvent(self, prime_event, i, channel): + logger.info("...") + channel_id = channel["id"] + self["channel%s" % i].setText(prime_event[EVENT_IDX_BROADCASTER_NAME]) + self["time%s" % i].setText(strftime("%H:%M", localtime(int(prime_event[EVENT_IDX_TIME_START])))) + self["description%s" % i].setText(prime_event[EVENT_IDX_TITLE]) + self["channelpix%s" % i].instance.setPixmap(gPixmapPtr()) + self["channelpix%s" % i].instance.setPixmap(getPicon(channel_id, channel["service"])) + url = getEventPicUrl(prime_event[EVENT_IDX_IMAGES]) + if url: + afile = os.path.join(TMP_DIR, "programpix-%s-%s%s" % (self.day, channel_id, url[-4:])) + if os.path.exists(afile): + self.result_back_pic(None, i, afile) + else: + self.download.run(MydownloadPage, url, afile, headers=headers_gzip).addCallback(self.result_back_pic, i, afile).addErrback(http_failed) + + def result_back_pic(self, result, i, event_pic_file): + logger.info("result: %s", result) + logger.info("i: %s, event_pic_file: %s", i, event_pic_file) + self["programpix%s" % i].instance.setPixmap(LoadPixmap(event_pic_file)) + + def clearValues(self): + logger.info("...") + for i in range(self.cols): + self["channel%s" % i].setText("") + self["time%s" % i].setText("") + self["description%s" % i].setText("") + self["channelpix%s" % i].instance.setPixmap(gPixmapPtr()) + self["list%s" % i].l.setList([]) + self["programpix%s" % i].instance.setPixmap(gPixmapPtr()) + + def left(self): + logger.info("...") + self["list%s" % self.listindex].setSelectionEnable(False) + self.listindex -= 1 + if self.listindex < 0: + self.listindex = self.cols - 1 + self.page_index -= 1 + if self.page_index < 0: + self.page_index = self.pages - 1 + max_listindex = len(self.channel_list) % self.cols - 1 + if max_listindex >= 0: + self.listindex = max_listindex + self.showPage() + self["list%s" % self.listindex].setSelectionEnable(True) + + def right(self): + logger.info("...") + self["list%s" % self.listindex].setSelectionEnable(False) + max_listindex = len(self.channel_list) % self.cols - 1 + self.listindex += 1 + if ( + self.listindex > self.cols - 1 + or (self.page_index == self.pages - 1 and self.listindex > max_listindex) + ): + self.listindex = 0 + self.page_index += 1 + if self.page_index > self.pages - 1: + self.page_index = 0 + self.showPage() + self["list%s" % self.listindex].setSelectionEnable(True) + + def moveUp(self): + logger.info("listindex: %s", self.listindex) + if self.list_indices[self.listindex] > 1: + self.list_indices[self.listindex] -= 1 + index = self.list_indices[self.listindex] + column = self.list_columns[self.listindex] + self.point_in_time = column[index][4] + sub_list = column[index - 1:index + 4] + self["list%s" % self.listindex].setList(sub_list) + self.showPage() + + def moveDown(self): + logger.info("listindex: %s", self.listindex) + logger.debug("index: %s, len(list): %s", self.list_indices[self.listindex], len(self.list_columns[self.listindex])) + if self.list_indices[self.listindex] < len(self.list_columns[self.listindex]) - 1: + self.list_indices[self.listindex] += 1 + index = self.list_indices[self.listindex] + column = self.list_columns[self.listindex] + self.point_in_time = column[index][4] + sub_list = column[index - 1:index + 4] + self["list%s" % self.listindex].setList(sub_list) + self.showPage() + + def channelup(self): + logger.info("...") + self["list%s" % self.listindex].setSelectionEnable(False) + self.page_index += 1 + if self.page_index >= self.pages: + self.page_index = 0 + self.listindex = 0 + self["list%s" % self.listindex].setSelectionEnable(True) + self.showPage() + + def channeldown(self): + logger.info("...") + self["list%s" % self.listindex].setSelectionEnable(False) + self.page_index -= 1 + if self.page_index < 0: + self.page_index = self.pages - 1 + self.listindex = self.cols - 1 if len(self.channel_list) % self.cols == 0 else len(self.channel_list) % self.cols - 1 + else: + self.listindex = self.cols - 1 + self["list%s" % self.listindex].setSelectionEnable(True) + self.showPage() + + def showMore(self): + logger.info("...") + if self.download.finished(): + self.openMore(self.bouquet, self.channel_list, self.channel_dict) + + def showMenu(self): + if self.download.finished(): + channel_name = self.page_list[self.listindex] + channel = self.channel_dict[channel_name] + event = self.events[self.day][channel["id"]][self.list_indices[self.listindex]] + self.openMenu(channel["service"], event) + + def key_next(self): + logger.info("...") + self.mytimecount += 1 + self.reload() + + def key_back(self): + logger.info("...") + self.mytimecount -= 1 + self.reload() + + def key_ok(self): + logger.info("...") + current_selection = self["list%s" % self.listindex].l.getCurrentSelection() + if current_selection: + logger.debug("current_selection: %s", current_selection) + channel_name = self.page_list[self.listindex] + channel_id = self.channel_dict[channel_name]["id"] + self.session.open( + EventDetails, + self.channel_dict[channel_name], + self.events[self.day][channel_id][self.list_indices[self.listindex]], + ) + + def getPointInTime(self, hm): + logger.info("hm: %s", hm) + logger.info("mytimecount: %s", self.mytimecount) + ymd = self.timelist[self.mytimecount][1].split("-") + hm = hm.split(":") + point_in_time = int(datetime(int(ymd[0]), int(ymd[1]), int(ymd[2]), int(hm[0]), int(hm[1]), 0).strftime("%s")) + logger.debug("point_in_time: %s", point_in_time) + return point_in_time + + def key_red(self): + logger.info("...") + self.showMore() + + def key_green(self): + logger.info("...") + self.point_in_time = self.getPointInTime("20:15") + self.showPage() + + def key_yellow(self): + logger.info("...") + self.point_in_time = self.getPointInTime("22:00") + self.showPage() + + def key_blue(self): + logger.info("...") + self.point_in_time = self.getPointInTime(time.strftime("%H:%M")) + self.showPage() + + def reload(self): + logger.info("self.channel_list: %s", self.channel_list) + self["list%s" % self.listindex].setSelectionEnable(False) + self.pages = int(ceil(float(len(self.channel_list)) / self.cols)) + self.listindex = 0 + self.page_index = 0 + self.mytimecount = max(min(len(self.timelist) - 1, self.mytimecount), 0) + self["searchdate"].text = self.timelist[self.mytimecount][0] + self.day = self.timelist[self.mytimecount][1] + self.list_columns = [[]] * self.cols + self.list_prime = [[]] * self.cols + self.list_indices = [-1] * self.cols + self.point_in_time = self.getPointInTime("20:15") + self["list%s" % self.listindex].setSelectionEnable(True) + self.showPage() + + def __onClose__(self): + logger.info("...") + self.download.deferCanceler() + del self.download.ds.waiting[:] + self.download.work.clear() + deleteDirectory(TMP_DIR) diff --git a/src/Search.py b/src/Search.py new file mode 100755 index 0000000..1ec6478 --- /dev/null +++ b/src/Search.py @@ -0,0 +1,31 @@ +# !/usr/bin/python +# coding=utf-8 +# +# Copyright (C) 2018-2024 by dream-alpha +# +# In case of reuse of this source code please do not remove this copyright. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# For more information on the GNU General Public License see: +# . + + +from Screens.Screen import Screen +from .Debug import logger + + +class Search(Screen): + def __init__(self, session, query): + logger.info("query: %s", query) + Screen.__init__(self, session) + + # let"s do it... diff --git a/src/ServiceUtils.py b/src/ServiceUtils.py new file mode 100644 index 0000000..33e056b --- /dev/null +++ b/src/ServiceUtils.py @@ -0,0 +1,64 @@ +#!/usr/bin/python +# coding=utf-8 +# +# Copyright (C) 2018-2024 by dream-alpha +# +# In case of reuse of this source code please do not remove this copyright. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# For more information on the GNU General Public License see: +# . + + +import os +from enigma import eServiceReference + + +SID_DVB = eServiceReference.idDVB # eServiceFactoryDVB::id enum{id = 0x0001}; +SID_DVD = eServiceReference.idDVD # eServiceFactoryDVD::id enum{id = 0x1111}; +SID_M2TS = eServiceReference.idM2TS # eServiceFactoryM2TS::id enum{id = 0x0003}; +SID_GST = eServiceReference.idGST # eServiceFactoryGST::id enum{id = 0x1001}; + + +EXT_TS = [".ts", ".trp"] +EXT_M2TS = [".m2ts"] +EXT_DVD = [".ifo", ".iso", ".img"] +EXT_VIDEO = [".avi", ".divx", ".f4v", ".flv", ".m4v", ".mkv", ".mov", ".mp4", ".mpeg", ".mpg", ".mts", ".vob", ".wmv", ".asf", ".stream", ".webm"] +EXT_BLU = [".bdmv"] + +EXT_PICTURE = [".jpg", ".jpeg", ".png"] +EXT_MUSIC = [".mp3", ".wma"] +EXT_PLAYLIST = [".m3u"] + +ALL_VIDEO = EXT_TS + EXT_M2TS + EXT_DVD + EXT_VIDEO + EXT_BLU +ALL_MEDIA = ALL_VIDEO + EXT_PICTURE + EXT_MUSIC + EXT_PLAYLIST + + +DEFAULT_VIDEO_PID = 0x44 +DEFAULT_AUDIO_PID = 0x45 + + +def getService(path, name=""): + service = None + ext = os.path.splitext(path)[1].lower() + if ext in EXT_TS: + service = eServiceReference(SID_DVB, 0, path) + elif ext in EXT_DVD: + service = eServiceReference(SID_DVD, 0, path) + elif ext in EXT_M2TS: + service = eServiceReference(SID_M2TS, 0, path) + else: + service = eServiceReference(SID_GST, 0, path) + service.setData(0, DEFAULT_VIDEO_PID) + service.setData(1, DEFAULT_AUDIO_PID) + service.setName(name) + return service diff --git a/src/SkinUtils.py b/src/SkinUtils.py new file mode 100644 index 0000000..1228983 --- /dev/null +++ b/src/SkinUtils.py @@ -0,0 +1,96 @@ +#!/usr/bin/python +# coding=utf-8 +# +# Copyright (C) 2018-2024 by dream-alpha +# +# In case of reuse of this source code please do not remove this copyright. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# For more information on the GNU General Public License see: +# . + + +import os +from enigma import getDesktop +from Components.config import config +from Tools.Directories import resolveFilename, SCOPE_PLUGINS +from skin import loadSkin, loadSingleSkinData, dom_skins +from .Debug import logger +from .Version import ID, PLUGIN + + +def getSkinName(skin_name): + return ID + skin_name + + +def getScalingFactor(): + return {"HD": 2.0 / 3.0, "FHD": 1, "WQHD": 4.0 / 3.0}[getResolution()] + + +def getResolution(): + height = getDesktop(0).size().height() + resolution = "SD" + if height > 576: + resolution = "HD" + if height > 720: + resolution = "FHD" + if height > 1080: + resolution = "WQHD" + return resolution + + +def getSkinPath(file_name): + logger.debug(">>> file_name: %s", file_name) + base_skin_dir = "/usr/share/enigma2" + sub_skin_dir = os.path.dirname(config.skin.primary_skin.value) + resolution = getResolution() + logger.debug("resolution: %s, sub_skin_dir: %s", resolution, sub_skin_dir) + if not sub_skin_dir: + sub_skin_dir = "Default-HD" + elif resolution == "FHD": + if sub_skin_dir in ["Shadow-FHD", "Zombi-Shadow-FHD"]: + sub_skin_dir = "Shadow-FHD" + else: + sub_skin_dir = "Default-FHD" + elif resolution == "WQHD": + if sub_skin_dir in ["Shadow-WQHD", "Default-WQHD"]: + sub_skin_dir = "Default-WQHD" + else: + sub_skin_dir = "Other-WQHD" + else: + sub_skin_dir = "Default-HD" + + dirs = [ + os.path.join(resolveFilename(SCOPE_PLUGINS), "Extensions", PLUGIN, "skin", sub_skin_dir), + os.path.join(resolveFilename(SCOPE_PLUGINS), "SystemPlugins", PLUGIN, "skin", sub_skin_dir), + os.path.join(resolveFilename(SCOPE_PLUGINS), "Extensions", PLUGIN, "skin"), + os.path.join(resolveFilename(SCOPE_PLUGINS), "SystemPlugins", PLUGIN, "skin"), + os.path.join(base_skin_dir, sub_skin_dir), + base_skin_dir + ] + logger.debug("dirs: %s", dirs) + + for adir in dirs: + skin_path = os.path.join(adir, file_name) + logger.debug("checking: skin_path: %s", skin_path) + if os.path.exists(skin_path): + break + skin_path = "" + logger.debug("skin_path: %s", skin_path) + return skin_path + + +def loadPluginSkin(skin_file): + logger.info("skin_path: %s", getSkinPath(skin_file)) + loadSkin(getSkinPath(skin_file), "") + path, dom_skin = dom_skins[-1:][0] + loadSingleSkinData(getDesktop(0), dom_skin, path) diff --git a/src/StreamPlayer.py b/src/StreamPlayer.py new file mode 100644 index 0000000..fa78954 --- /dev/null +++ b/src/StreamPlayer.py @@ -0,0 +1,64 @@ +# !/usr/bin/python +# coding=utf-8 +# +# Copyright (C) 2018-2024 by dream-alpha +# +# In case of reuse of this source code please do not remove this copyright. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# For more information on the GNU General Public License see: +# . + + +from Screens.InfoBar import MoviePlayer +from Components.ActionMap import ActionMap +from .Debug import logger + + +class StreamPlayer(MoviePlayer): + def __init__(self, session, service): + logger.info("...") + MoviePlayer.__init__(self, session, service) + self.skinName = "MoviePlayer" + if "CueSheetActions" in self: + del self["CueSheetActions"] + if "MenuActions" in self: + del self["MenuActions"] + if "MovieListActions" in self: + del self["MovieListActions"] + if "TeletextActions" in self: + del self["TeletextActions"] + if "InstantExtensionsActions" in self: + del self["InstantExtensionsActions"] + if "helpActions" in self: + del self["helpActions"] + if "EPGActions" in self: + del self["EPGActions"] + + self["ShowHideActions"] = ActionMap( + ["InfobarShowHideActions"], + { + "toggleShow": self.toggleShow, + "hide": self.leavePlayer, + }, + 1 + ) + + def seekFwd(self): + logger.info("...") + + def seekBack(self): + logger.info("...") + + def handleLeave(self, _how): + logger.info("...") + self.close() diff --git a/src/TVMagazineCockpit.png b/src/TVMagazineCockpit.png new file mode 100755 index 0000000..d981361 Binary files /dev/null and b/src/TVMagazineCockpit.png differ diff --git a/src/TVMagazineCockpit.py b/src/TVMagazineCockpit.py new file mode 100644 index 0000000..d58bf7e --- /dev/null +++ b/src/TVMagazineCockpit.py @@ -0,0 +1,46 @@ +# !/usr/bin/python +# coding=utf-8 +# +# Copyright (C) 2018-2024 by dream-alpha +# +# In case of reuse of this source code please do not remove this copyright. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# For more information on the GNU General Public License see: +# . + + +from .Debug import logger +from .ProgramColumns import ProgramColumns +from .ChannelUtils import read_channel_dict +from .Constants import TMP_DIR +from .FileUtils import createDirectory + + +class TVMagazineCockpit(): + def __init__(self, session, **_kwargs): + logger.info("...") + self.session = session + self.last_screen = None + createDirectory(TMP_DIR) + self.channel_dict = read_channel_dict() + self.showScreenCallback("programcolumns") + + def showScreen(self, screen, *args): + logger.info("screen: %s", screen) + self.session.openWithCallback(self.showScreenCallback, screen, *args) + + def showScreenCallback(self, *args): + return_screen = args[0] if len(args) > 0 else "" + logger.info("return_screen: %s", return_screen) + if return_screen == "programcolumns": + self.showScreen(ProgramColumns, self.channel_dict) diff --git a/src/TVSpielfilmData.py b/src/TVSpielfilmData.py new file mode 100644 index 0000000..d414006 --- /dev/null +++ b/src/TVSpielfilmData.py @@ -0,0 +1,72 @@ +# !/usr/bin/python +# coding=utf-8 +# +# Copyright (C) 2018-2024 by dream-alpha +# +# In case of reuse of this source code please do not remove this copyright. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# For more information on the GNU General Public License see: +# . + + +import json +from .Downloader import headers_gzip, MygetPage, MyDeferredSemaphore +from .Constants import EVENT_KEYS, EVENT_IDX_VIDEOS, EVENT_IDX_IMAGES, EVENT_LENGTH +from .Debug import logger +from .ChannelUtils import convert_unicode_to_str + + +class TVSpielfilmData(): + def __init__(self, callback): + self.callback = callback + self.events = {} + self.download = MyDeferredSemaphore(tokens=32) + + def parseJsonEvents(self, json_events): + logger.info("...") + list_events = [] + for json_event in json_events: + list_event = [""] * EVENT_LENGTH + for index, key in enumerate(EVENT_KEYS): + # logger.debug("json_event: %s", json_event) + # logger.debug("index: %s, key: %s", index, key) + if index in [EVENT_IDX_VIDEOS, EVENT_IDX_IMAGES]: + # logger.debug("json_event: %s", json_event) + list_event[index] = json_event.get(key, []) + else: + list_event[index] = json_event.get(key, "") + list_events.append(list_event) + return list_events + + def downloadEvents(self, channel, day, i): + logger.info("channel: %s, day: %s", channel, day) + channel_id = channel["id"] + del self.download.ds.waiting[:] + url = "https://live.tvspielfilm.de/static/broadcast/list/%s/%s" % (channel_id, day) + logger.debug("url: %s", url) + self.download.run(MygetPage, url, headers=headers_gzip).addCallback(self.result_back, channel, i, day).addErrback(self.download_failed, channel, i, day) + + def result_back(self, result, channel, i, day): + logger.info("channel: %s", channel) + channel_id = channel["id"] + if result: + if day not in self.events: + self.events[day] = {} + events = convert_unicode_to_str(json.loads(result)) + self.events[day][channel_id] = self.parseJsonEvents(events) + self.callback(self.events, channel, i) + + def download_failed(self, failure, channel, i, day): + logger.error("channel: %s, failure: %s", channel, failure) + self.events[day] = {} + self.callback(self.events, channel, i) diff --git a/src/Version.py b/src/Version.py new file mode 100644 index 0000000..145df79 --- /dev/null +++ b/src/Version.py @@ -0,0 +1,26 @@ +# !/usr/bin/python +# coding=utf-8 +# +# Copyright (C) 2018-2024 by dream-alpha +# +# In case of reuse of this source code please do not remove this copyright. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# For more information on the GNU General Public License see: +# . + + +PLUGIN = "TVMagazineCockpit" +ID = "TVC" +VERSION = "1.7.8" +COPYRIGHT = "2018-2024 by dream-alpha" +LICENSE = "This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version." diff --git a/src/ZapUtils.py b/src/ZapUtils.py new file mode 100644 index 0000000..d80dfbc --- /dev/null +++ b/src/ZapUtils.py @@ -0,0 +1,53 @@ +# !/usr/bin/python +# coding=utf-8 +# +# Copyright (C) 2018-2024 by dream-alpha +# +# In case of reuse of this source code please do not remove this copyright. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# For more information on the GNU General Public License see: +# . + + +from Screens.InfoBar import InfoBar +from Screens.ChannelSelection import service_types_tv +from enigma import eServiceCenter, eServiceReference +from .Debug import logger + + +def Zap_Service(strservice): + logger.info("strservice: %s", strservice) + if strservice: + service = eServiceReference(str(strservice)) + if service: + allservice = eServiceReference("%s ORDER BY name" % (service_types_tv)) + serviceHandler = eServiceCenter.getInstance() + bouquet_root = InfoBar.instance.servicelist.bouquet_root + bouquet = bouquet_root + bouquetlist = serviceHandler.list(bouquet_root) + if bouquetlist is not None: + while True: + bouquet = bouquetlist.getNext() + if not bouquet.valid(): + bouquet = allservice + break + currlist = serviceHandler.list(bouquet) + if (currlist is not None) and (strservice in currlist.getContent("S", True)): + break + if InfoBar.instance.servicelist.getRoot() != bouquet: # already in correct bouquet? + InfoBar.instance.servicelist.clearPath() + if bouquet_root != bouquet: + InfoBar.instance.servicelist.enterPath(bouquet_root) + InfoBar.instance.servicelist.enterPath(bouquet) + InfoBar.instance.servicelist.setCurrentSelection(service) # select the service in servicelist + InfoBar.instance.servicelist.zap() diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000..edcc6e0 --- /dev/null +++ b/src/__init__.py @@ -0,0 +1,47 @@ +#!/usr/bin/python +# coding=utf-8 +# +# Copyright (C) 2018-2024 by dream-alpha +# +# In case of reuse of this source code please do not remove this copyright. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# For more information on the GNU General Public License see: +# . + + +import os +import gettext +from Components.Language import language +from Tools.Directories import resolveFilename, SCOPE_PLUGINS +from .Version import PLUGIN +from .Debug import initLogging + + +def initLocale(): + lang = language.getLanguage()[:2] + os.environ["LANGUAGE"] = lang + locale = resolveFilename(SCOPE_PLUGINS, "Extensions/" + PLUGIN + "/locale") + if not os.path.exists(locale): + locale = resolveFilename(SCOPE_PLUGINS, "SystemPlugins/" + PLUGIN + "/locale") + if os.path.exists(locale): + gettext.bindtextdomain(PLUGIN, locale) + + +def _(txt): + translation = gettext.dgettext(PLUGIN, txt) + return translation + + +initLogging() +initLocale() +language.addCallback(initLocale) diff --git a/src/keymap.xml b/src/keymap.xml new file mode 100644 index 0000000..d79ffe0 --- /dev/null +++ b/src/keymap.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/locale/de/LC_MESSAGES/TVMagazineCockpit.mo b/src/locale/de/LC_MESSAGES/TVMagazineCockpit.mo new file mode 100644 index 0000000..200d375 Binary files /dev/null and b/src/locale/de/LC_MESSAGES/TVMagazineCockpit.mo differ diff --git a/src/plugin.png b/src/plugin.png new file mode 100644 index 0000000..1553d8e Binary files /dev/null and b/src/plugin.png differ diff --git a/src/plugin.py b/src/plugin.py new file mode 100644 index 0000000..8d13573 --- /dev/null +++ b/src/plugin.py @@ -0,0 +1,99 @@ +# !/usr/bin/python +# coding=utf-8 +# +# Copyright (C) 2018-2024 by dream-alpha +# +# In case of reuse of this source code please do not remove this copyright. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# For more information on the GNU General Public License see: +# . + + +from Plugins.Plugin import PluginDescriptor +from .ConfigInit import ConfigInit +from .SkinUtils import loadPluginSkin +from .Debug import logger +from .Version import VERSION +from . import _ +from .TVMagazineCockpit import TVMagazineCockpit +# from .PluginUtils import WHERE_TVMAGAZINE_SEARCH +# from .Search import Search + + +# def search(session, query, **__kwargs): +# Search(session, query) + + +# def searchEvent(session, event="", service="", **_kwargs): +# logger.info("...") +# if not service: +# service = session.nav.getCurrentService() +# info = service.info() +# if not event: +# event = info.getEvent(0) # 0 = now, 1 = next +# event_name = event and event.getEventName() or info.getName() or "" +# logger.info("event_name: %s", event_name) +# Search(session, event_name) + + +def main(session, **kwargs): + logger.info("...") + TVMagazineCockpit(session, **kwargs) + + +def autoStart(reason, **kwargs): + if reason == 0: # startup + if "session" in kwargs: + logger.info("+++ Version: %s starts...", VERSION) + loadPluginSkin("skin.xml") + elif reason == 1: # shutdown + logger.info("--- shutdown") + else: + logger.info("reason not handled: %s", reason) + + +def Plugins(**__kwargs): + logger.info("...") + ConfigInit() + return [ + PluginDescriptor( + where=[ + PluginDescriptor.WHERE_AUTOSTART, + PluginDescriptor.WHERE_SESSIONSTART + ], + fnc=autoStart + ), + PluginDescriptor( + name="TVMagazineCockpit", + where=PluginDescriptor.WHERE_PLUGINMENU, + icon="TVMagazineCockpit.png", + description=_("Browse TV Magazine"), + fnc=main + ), + # PluginDescriptor( + # name=_("TVMagazineCockpit"), + # description=_("TVMagazine Event Infos"), + # where=[ + # PluginDescriptor.WHERE_EPG_SELECTION_SINGLE_BLUE, + # PluginDescriptor.WHERE_EVENTINFO, + # PluginDescriptor.WHERE_EVENTVIEW, + # ], + # fnc=searchEvent + # ), + # PluginDescriptor( + # name=_("TVMagazineCockpit"), + # description=_("TVMagazineCockpit Event Infos"), + # where=WHERE_TVMAGAZINE_SEARCH, + # fnc=search + # ), + ] diff --git a/src/skin/Default-FHD/Makefile.am b/src/skin/Default-FHD/Makefile.am new file mode 100644 index 0000000..164b525 --- /dev/null +++ b/src/skin/Default-FHD/Makefile.am @@ -0,0 +1,2 @@ +installdir = $(libdir)/enigma2/python/Plugins/Extensions/TVMagazineCockpit/skin/Default-FHD +install_DATA = skin.xml screenpart_program_template.tpl diff --git a/src/skin/Default-FHD/colors.xmlinc b/src/skin/Default-FHD/colors.xmlinc new file mode 100644 index 0000000..239e7c9 --- /dev/null +++ b/src/skin/Default-FHD/colors.xmlinc @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/skin/Default-FHD/screenpart_program_template.tpl b/src/skin/Default-FHD/screenpart_program_template.tpl new file mode 100644 index 0000000..cdea211 --- /dev/null +++ b/src/skin/Default-FHD/screenpart_program_template.tpl @@ -0,0 +1 @@ +{"template":[MultiContentEntryText(pos=(5,7),size=(55,23),font=1,flags=RT_HALIGN_LEFT,text=0,backcolor=None),MultiContentEntryText(pos=(65,5),size=(245,75),font=0,flags=RT_HALIGN_LEFT|RT_WRAP,text=1,backcolor=None),MultiContentEntryText(pos=(65,87),size=(245,23),font=1,flags=RT_HALIGN_LEFT|RT_WRAP,text=2,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=(65,115),size=(245,23),font=1,flags=RT_HALIGN_LEFT|RT_WRAP,text=3,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=(0,0),size=(320,140),font=1,flags=RT_VALIGN_CENTER,text="",border_width=1,border_color=0x595959),],"itemHeight":140,"selectionEnabled":False,"fonts":[gFont("Regular",23),gFont("Regular",20),gFont("Regular",17)]} \ No newline at end of file diff --git a/src/skin/Default-FHD/skin.xml b/src/skin/Default-FHD/skin.xml new file mode 100644 index 0000000..b67f350 --- /dev/null +++ b/src/skin/Default-FHD/skin.xml @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Format:%A, %d. %B - %H:%M + + + {"templates": {"default":(40,[ MultiContentEntryText(pos=(5,0),size=(1000,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0), MultiContentEntryText(pos=(500,0),size=(500,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1,color=0xa0a0a0), ]), "channel_bouquet":(40,[ MultiContentEntryText(pos=(5,0),size=(350,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0, backcolor=None), MultiContentEntryText(pos=(360,0),size=(350,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1, backcolor=None), MultiContentEntryText(pos=(720,0),size=(350,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=2, backcolor=None), MultiContentEntryText(pos=(1080,0),size=(350,40),font=1,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=3, backcolor=None), MultiContentEntryText(pos=(1440,0),size=(350,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=4, backcolor=None), MultiContentEntryText(pos=(355,0),size=(1,40),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0), MultiContentEntryText(pos=(715,0),size=(1,40),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0), MultiContentEntryText(pos=(1075,0),size=(1,40),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0), MultiContentEntryText(pos=(1435,0),size=(1,40),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0), ]) }, "fonts": [gFont("Regular",25),gFont("Regular",20)], itemHeight":40 } + + + + + + + + + + + + + + + + + + + + + Date + + + Default + + + + + + + diff --git a/src/skin/Default-HD/Makefile.am b/src/skin/Default-HD/Makefile.am new file mode 100644 index 0000000..f366176 --- /dev/null +++ b/src/skin/Default-HD/Makefile.am @@ -0,0 +1,2 @@ +installdir = $(libdir)/enigma2/python/Plugins/Extensions/TVMagazineCockpit/skin/Default-HD +install_DATA = skin.xml screenpart_program_template.tpl diff --git a/src/skin/Default-HD/colors.xmlinc b/src/skin/Default-HD/colors.xmlinc new file mode 100644 index 0000000..239e7c9 --- /dev/null +++ b/src/skin/Default-HD/colors.xmlinc @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/skin/Default-HD/screenpart_program_template.tpl b/src/skin/Default-HD/screenpart_program_template.tpl new file mode 100644 index 0000000..043e9e7 --- /dev/null +++ b/src/skin/Default-HD/screenpart_program_template.tpl @@ -0,0 +1 @@ +{"template":[MultiContentEntryText(pos=(3,5),size=(37,15),font=1,flags=RT_HALIGN_LEFT,text=0,backcolor=None),MultiContentEntryText(pos=(43,3),size=(163,50),font=0,flags=RT_HALIGN_LEFT|RT_WRAP,text=1,backcolor=None),MultiContentEntryText(pos=(43,58),size=(163,15),font=1,flags=RT_HALIGN_LEFT|RT_WRAP,text=2,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=(43,77),size=(163,15),font=1,flags=RT_HALIGN_LEFT|RT_WRAP,text=3,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=(0,0),size=(213,93),font=1,flags=RT_VALIGN_CENTER,text="",border_width=1,border_color=0x595959),],"itemHeight":93,"selectionEnabled":False,"fonts":[gFont("Regular",15),gFont("Regular",13),gFont("Regular",11)]} \ No newline at end of file diff --git a/src/skin/Default-HD/skin.xml b/src/skin/Default-HD/skin.xml new file mode 100644 index 0000000..b86a01b --- /dev/null +++ b/src/skin/Default-HD/skin.xml @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Format:%A, %d. %B - %H:%M + + + {"templates":{"default":(27,[MultiContentEntryText(pos=(3,0),size=(667,27),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0),MultiContentEntryText(pos=(333,0),size=(333,27),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1,color=0xa0a0a0),]),"channel_bouquet":(27,[MultiContentEntryText(pos=(3,0),size=(233,27),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0,backcolor=None),MultiContentEntryText(pos=(240,0),size=(233,27),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1,backcolor=None),MultiContentEntryText(pos=(480,0),size=(233,27),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=2,backcolor=None),MultiContentEntryText(pos=(720,0),size=(233,27),font=1,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=3,backcolor=None),MultiContentEntryText(pos=(960,0),size=(233,27),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=4,backcolor=None),MultiContentEntryText(pos=(237,0),size=(1,27),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),MultiContentEntryText(pos=(477,0),size=(1,27),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),MultiContentEntryText(pos=(717,0),size=(1,27),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),MultiContentEntryText(pos=(957,0),size=(1,27),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),])},"fonts":[gFont("Regular",17),gFont("Regular",13)],itemHeight":40} + + + + + + + + + + + + + + + + + + + + + Date + + + Default + + + + + + + diff --git a/src/skin/Default-WQHD/Makefile.am b/src/skin/Default-WQHD/Makefile.am new file mode 100644 index 0000000..ce9a5fa --- /dev/null +++ b/src/skin/Default-WQHD/Makefile.am @@ -0,0 +1,2 @@ +installdir = $(libdir)/enigma2/python/Plugins/Extensions/TVMagazineCockpit/skin/Default-WQHD +install_DATA = skin.xml screenpart_program_template.tpl diff --git a/src/skin/Default-WQHD/colors.xmlinc b/src/skin/Default-WQHD/colors.xmlinc new file mode 100644 index 0000000..23b5d66 --- /dev/null +++ b/src/skin/Default-WQHD/colors.xmlinc @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/skin/Default-WQHD/screen_ChannelManagement.xmlinc b/src/skin/Default-WQHD/screen_ChannelManagement.xmlinc new file mode 100755 index 0000000..777d680 --- /dev/null +++ b/src/skin/Default-WQHD/screen_ChannelManagement.xmlinc @@ -0,0 +1,16 @@ + + + + + + + + + + + {"templates":{"default":(53,[MultiContentEntryText(pos=(7,0),size=(1333,53),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0),MultiContentEntryText(pos=(667,0),size=(667,53),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1,color=0xa0a0a0),]),"channel_bouquet":(53,[MultiContentEntryText(pos=(7,0),size=(467,53),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0,backcolor=None),MultiContentEntryText(pos=(480,0),size=(467,53),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1,backcolor=None),MultiContentEntryText(pos=(960,0),size=(467,53),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=2,backcolor=None),MultiContentEntryText(pos=(1440,0),size=(467,53),font=1,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=3,backcolor=None),MultiContentEntryText(pos=(1920,0),size=(467,53),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=4,backcolor=None),MultiContentEntryText(pos=(473,0),size=(1,53),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),MultiContentEntryText(pos=(953,0),size=(1,53),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),MultiContentEntryText(pos=(1433,0),size=(1,53),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),MultiContentEntryText(pos=(1913,0),size=(1,53),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),])},"fonts":[gFont("Regular",33),gFont("Regular",27)],"itemHeight":53} + + + + + diff --git a/src/skin/Default-WQHD/screen_ConfigScreen.xmlinc b/src/skin/Default-WQHD/screen_ConfigScreen.xmlinc new file mode 100644 index 0000000..1cbc524 --- /dev/null +++ b/src/skin/Default-WQHD/screen_ConfigScreen.xmlinc @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/skin/Default-WQHD/screen_EventDetails.xmlinc b/src/skin/Default-WQHD/screen_EventDetails.xmlinc new file mode 100755 index 0000000..e877711 --- /dev/null +++ b/src/skin/Default-WQHD/screen_EventDetails.xmlinc @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/skin/Default-WQHD/screen_ProgramColumns.xmlinc b/src/skin/Default-WQHD/screen_ProgramColumns.xmlinc new file mode 100644 index 0000000..a4327b6 --- /dev/null +++ b/src/skin/Default-WQHD/screen_ProgramColumns.xmlinc @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/skin/Default-WQHD/screenpart_ProgramColumnsPrime.xmlinc b/src/skin/Default-WQHD/screenpart_ProgramColumnsPrime.xmlinc new file mode 100644 index 0000000..05acd9c --- /dev/null +++ b/src/skin/Default-WQHD/screenpart_ProgramColumnsPrime.xmlinc @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/skin/Default-WQHD/screenpart_program_template.tpl b/src/skin/Default-WQHD/screenpart_program_template.tpl new file mode 100644 index 0000000..e42ce7e --- /dev/null +++ b/src/skin/Default-WQHD/screenpart_program_template.tpl @@ -0,0 +1 @@ +{"template":[MultiContentEntryText(pos=(7,9),size=(73,31),font=1,flags=RT_HALIGN_LEFT,text=0,backcolor=None),MultiContentEntryText(pos=(87,7),size=(327,100),font=0,flags=RT_HALIGN_LEFT|RT_WRAP,text=1,backcolor=None),MultiContentEntryText(pos=(87,116),size=(327,31),font=1,flags=RT_HALIGN_LEFT|RT_WRAP,text=2,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=(87,153),size=(327,31),font=1,flags=RT_HALIGN_LEFT|RT_WRAP,text=3,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=(0,0),size=(427,187),font=1,flags=RT_VALIGN_CENTER,text="",border_width=1,border_color=0x595959),],"itemHeight":187,"selectionEnabled":False,"fonts":[gFont("Regular",31),gFont("Regular",27),gFont("Regular",23)]} \ No newline at end of file diff --git a/src/skin/Default-WQHD/skin.xml b/src/skin/Default-WQHD/skin.xml new file mode 100644 index 0000000..bab9f29 --- /dev/null +++ b/src/skin/Default-WQHD/skin.xml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {"templates":{"default":(53,[MultiContentEntryText(pos=(7,0),size=(1333,53),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0),MultiContentEntryText(pos=(667,0),size=(667,53),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1,color=0xa0a0a0),]),"channel_bouquet":(53,[MultiContentEntryText(pos=(7,0),size=(467,53),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0,backcolor=None),MultiContentEntryText(pos=(480,0),size=(467,53),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1,backcolor=None),MultiContentEntryText(pos=(960,0),size=(467,53),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=2,backcolor=None),MultiContentEntryText(pos=(1440,0),size=(467,53),font=1,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=3,backcolor=None),MultiContentEntryText(pos=(1920,0),size=(467,53),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=4,backcolor=None),MultiContentEntryText(pos=(473,0),size=(1,53),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),MultiContentEntryText(pos=(953,0),size=(1,53),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),MultiContentEntryText(pos=(1433,0),size=(1,53),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),MultiContentEntryText(pos=(1913,0),size=(1,53),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),])},"fonts":[gFont("Regular",33),gFont("Regular",27)],"itemHeight":53} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/skin/Makefile.am b/src/skin/Makefile.am new file mode 100644 index 0000000..6bbf689 --- /dev/null +++ b/src/skin/Makefile.am @@ -0,0 +1,2 @@ +SUBDIRS = images Default-HD Default-FHD Default-WQHD Other-WQHD Shadow-FHD +install_DATA = skin.xml *.tpl diff --git a/src/skin/Other-WQHD/Makefile.am b/src/skin/Other-WQHD/Makefile.am new file mode 100644 index 0000000..582addd --- /dev/null +++ b/src/skin/Other-WQHD/Makefile.am @@ -0,0 +1,2 @@ +installdir = $(libdir)/enigma2/python/Plugins/Extensions/TVMagazineCockpit/skin/Other-WQHD +install_DATA = skin.xml screenpart_program_template.tpl diff --git a/src/skin/Other-WQHD/colors.xmlinc b/src/skin/Other-WQHD/colors.xmlinc new file mode 100644 index 0000000..88b18fa --- /dev/null +++ b/src/skin/Other-WQHD/colors.xmlinc @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/skin/Other-WQHD/screenpart_program_template.tpl b/src/skin/Other-WQHD/screenpart_program_template.tpl new file mode 100644 index 0000000..e42ce7e --- /dev/null +++ b/src/skin/Other-WQHD/screenpart_program_template.tpl @@ -0,0 +1 @@ +{"template":[MultiContentEntryText(pos=(7,9),size=(73,31),font=1,flags=RT_HALIGN_LEFT,text=0,backcolor=None),MultiContentEntryText(pos=(87,7),size=(327,100),font=0,flags=RT_HALIGN_LEFT|RT_WRAP,text=1,backcolor=None),MultiContentEntryText(pos=(87,116),size=(327,31),font=1,flags=RT_HALIGN_LEFT|RT_WRAP,text=2,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=(87,153),size=(327,31),font=1,flags=RT_HALIGN_LEFT|RT_WRAP,text=3,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=(0,0),size=(427,187),font=1,flags=RT_VALIGN_CENTER,text="",border_width=1,border_color=0x595959),],"itemHeight":187,"selectionEnabled":False,"fonts":[gFont("Regular",31),gFont("Regular",27),gFont("Regular",23)]} \ No newline at end of file diff --git a/src/skin/Other-WQHD/skin.xml b/src/skin/Other-WQHD/skin.xml new file mode 100644 index 0000000..7ec262d --- /dev/null +++ b/src/skin/Other-WQHD/skin.xml @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Format:%A, %d. %B - %H:%M + + + {"templates":{"default":(53,[MultiContentEntryText(pos=(7,0),size=(1333,53),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0),MultiContentEntryText(pos=(667,0),size=(667,53),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1,color=0xa0a0a0),]),"channel_bouquet":(53,[MultiContentEntryText(pos=(7,0),size=(467,53),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0,backcolor=None),MultiContentEntryText(pos=(480,0),size=(467,53),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1,backcolor=None),MultiContentEntryText(pos=(960,0),size=(467,53),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=2,backcolor=None),MultiContentEntryText(pos=(1440,0),size=(467,53),font=1,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=3,backcolor=None),MultiContentEntryText(pos=(1920,0),size=(467,53),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=4,backcolor=None),MultiContentEntryText(pos=(473,0),size=(1,53),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),MultiContentEntryText(pos=(953,0),size=(1,53),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),MultiContentEntryText(pos=(1433,0),size=(1,53),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),MultiContentEntryText(pos=(1913,0),size=(1,53),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),])},"fonts":[gFont("Regular",33),gFont("Regular",27)],itemHeight":40} + + + + + + + + + + + + + + + + + + + + + Date + + + Default + + + + + + + diff --git a/src/skin/Shadow-FHD/Makefile.am b/src/skin/Shadow-FHD/Makefile.am new file mode 100644 index 0000000..9fdb498 --- /dev/null +++ b/src/skin/Shadow-FHD/Makefile.am @@ -0,0 +1,2 @@ +installdir = $(libdir)/enigma2/python/Plugins/Extensions/TVMagazineCockpit/skin/Shadow-FHD +install_DATA = skin.xml screenpart_program_template.tpl diff --git a/src/skin/Shadow-FHD/colors.xmlinc b/src/skin/Shadow-FHD/colors.xmlinc new file mode 100644 index 0000000..218bc31 --- /dev/null +++ b/src/skin/Shadow-FHD/colors.xmlinc @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/skin/Shadow-FHD/screen_ChannelManagement.xmlinc b/src/skin/Shadow-FHD/screen_ChannelManagement.xmlinc new file mode 100755 index 0000000..cdceddf --- /dev/null +++ b/src/skin/Shadow-FHD/screen_ChannelManagement.xmlinc @@ -0,0 +1,37 @@ + + + + + + + + + + + + {"templates": + {"default":(40,[ + MultiContentEntryText(pos=(5,0),size=(1000,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0), + MultiContentEntryText(pos=(500,0),size=(500,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1,color=0xa0a0a0), + ]), + "channel_bouquet":(40,[ + MultiContentEntryText(pos=(5,0),size=(350,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0, backcolor=None), + MultiContentEntryText(pos=(360,0),size=(350,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1, backcolor=None), + MultiContentEntryText(pos=(720,0),size=(350,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=2, backcolor=None), + MultiContentEntryText(pos=(1080,0),size=(350,40),font=1,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=3, backcolor=None), + MultiContentEntryText(pos=(1440,0),size=(350,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=4, backcolor=None), + MultiContentEntryText(pos=(355,0),size=(1,40),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0), + MultiContentEntryText(pos=(715,0),size=(1,40),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0), + MultiContentEntryText(pos=(1075,0),size=(1,40),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0), + MultiContentEntryText(pos=(1435,0),size=(1,40),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0), + ]) + }, + "fonts": [gFont("Regular",25),gFont("Regular",20)], + "itemHeight": 40 + } + + + + + + diff --git a/src/skin/Shadow-FHD/screen_ConfigScreen.xmlinc b/src/skin/Shadow-FHD/screen_ConfigScreen.xmlinc new file mode 100644 index 0000000..9a76096 --- /dev/null +++ b/src/skin/Shadow-FHD/screen_ConfigScreen.xmlinc @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/skin/Shadow-FHD/screen_EventDetails.xmlinc b/src/skin/Shadow-FHD/screen_EventDetails.xmlinc new file mode 100755 index 0000000..ca8574b --- /dev/null +++ b/src/skin/Shadow-FHD/screen_EventDetails.xmlinc @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/skin/Shadow-FHD/screen_ProgramColumns.xmlinc b/src/skin/Shadow-FHD/screen_ProgramColumns.xmlinc new file mode 100644 index 0000000..c001f31 --- /dev/null +++ b/src/skin/Shadow-FHD/screen_ProgramColumns.xmlinc @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/skin/Shadow-FHD/screenpart_ProgramColumnsPrime.xmlinc b/src/skin/Shadow-FHD/screenpart_ProgramColumnsPrime.xmlinc new file mode 100644 index 0000000..27bd2a0 --- /dev/null +++ b/src/skin/Shadow-FHD/screenpart_ProgramColumnsPrime.xmlinc @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/skin/Shadow-FHD/screenpart_program_template.tpl b/src/skin/Shadow-FHD/screenpart_program_template.tpl new file mode 100644 index 0000000..cdea211 --- /dev/null +++ b/src/skin/Shadow-FHD/screenpart_program_template.tpl @@ -0,0 +1 @@ +{"template":[MultiContentEntryText(pos=(5,7),size=(55,23),font=1,flags=RT_HALIGN_LEFT,text=0,backcolor=None),MultiContentEntryText(pos=(65,5),size=(245,75),font=0,flags=RT_HALIGN_LEFT|RT_WRAP,text=1,backcolor=None),MultiContentEntryText(pos=(65,87),size=(245,23),font=1,flags=RT_HALIGN_LEFT|RT_WRAP,text=2,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=(65,115),size=(245,23),font=1,flags=RT_HALIGN_LEFT|RT_WRAP,text=3,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=(0,0),size=(320,140),font=1,flags=RT_VALIGN_CENTER,text="",border_width=1,border_color=0x595959),],"itemHeight":140,"selectionEnabled":False,"fonts":[gFont("Regular",23),gFont("Regular",20),gFont("Regular",17)]} \ No newline at end of file diff --git a/src/skin/Shadow-FHD/skin.xml b/src/skin/Shadow-FHD/skin.xml new file mode 100644 index 0000000..856b9d5 --- /dev/null +++ b/src/skin/Shadow-FHD/skin.xml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {"templates": {"default":(40,[ MultiContentEntryText(pos=(5,0),size=(1000,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0), MultiContentEntryText(pos=(500,0),size=(500,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1,color=0xa0a0a0), ]), "channel_bouquet":(40,[ MultiContentEntryText(pos=(5,0),size=(350,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0, backcolor=None), MultiContentEntryText(pos=(360,0),size=(350,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1, backcolor=None), MultiContentEntryText(pos=(720,0),size=(350,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=2, backcolor=None), MultiContentEntryText(pos=(1080,0),size=(350,40),font=1,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=3, backcolor=None), MultiContentEntryText(pos=(1440,0),size=(350,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=4, backcolor=None), MultiContentEntryText(pos=(355,0),size=(1,40),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0), MultiContentEntryText(pos=(715,0),size=(1,40),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0), MultiContentEntryText(pos=(1075,0),size=(1,40),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0), MultiContentEntryText(pos=(1435,0),size=(1,40),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0), ]) }, "fonts": [gFont("Regular",25),gFont("Regular",20)], "itemHeight": 40 } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/skin/images/Makefile.am b/src/skin/images/Makefile.am new file mode 100644 index 0000000..1ae8610 --- /dev/null +++ b/src/skin/images/Makefile.am @@ -0,0 +1,2 @@ +installdir = $(libdir)/enigma2/python/Plugins/Extensions/TVMagazineCockpit/images +install_DATA = *.png *.svg diff --git a/src/skin/images/default.png b/src/skin/images/default.png new file mode 100755 index 0000000..593fa85 Binary files /dev/null and b/src/skin/images/default.png differ diff --git a/src/skin/images/icon-video.png b/src/skin/images/icon-video.png new file mode 100755 index 0000000..3fcc17c Binary files /dev/null and b/src/skin/images/icon-video.png differ diff --git a/src/skin/images/thumb0.svg b/src/skin/images/thumb0.svg new file mode 100755 index 0000000..3c79685 --- /dev/null +++ b/src/skin/images/thumb0.svg @@ -0,0 +1,114 @@ + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/skin/images/thumb1.svg b/src/skin/images/thumb1.svg new file mode 100755 index 0000000..e4917bc --- /dev/null +++ b/src/skin/images/thumb1.svg @@ -0,0 +1,144 @@ + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/skin/images/thumb2.svg b/src/skin/images/thumb2.svg new file mode 100755 index 0000000..72dbb55 --- /dev/null +++ b/src/skin/images/thumb2.svg @@ -0,0 +1,209 @@ + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/src/skin/screen_ChannelManagement.xmlinc b/src/skin/screen_ChannelManagement.xmlinc new file mode 100755 index 0000000..02a5491 --- /dev/null +++ b/src/skin/screen_ChannelManagement.xmlinc @@ -0,0 +1,45 @@ + + + + + + + + + + + Format:%A, %d. %B - %H:%M + + + + {"templates": + {"default":(40,[ + MultiContentEntryText(pos=(5,0),size=(1000,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0), + MultiContentEntryText(pos=(500,0),size=(500,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1,color=0xa0a0a0), + ]), + "channel_bouquet":(40,[ + MultiContentEntryText(pos=(5,0),size=(350,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0, backcolor=None), + MultiContentEntryText(pos=(360,0),size=(350,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1, backcolor=None), + MultiContentEntryText(pos=(720,0),size=(350,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=2, backcolor=None), + MultiContentEntryText(pos=(1080,0),size=(350,40),font=1,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=3, backcolor=None), + MultiContentEntryText(pos=(1440,0),size=(350,40),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=4, backcolor=None), + MultiContentEntryText(pos=(355,0),size=(1,40),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0), + MultiContentEntryText(pos=(715,0),size=(1,40),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0), + MultiContentEntryText(pos=(1075,0),size=(1,40),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0), + MultiContentEntryText(pos=(1435,0),size=(1,40),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0), + ]) + }, + "fonts": [gFont("Regular",25),gFont("Regular",20)], + itemHeight":40 + } + + + + + + + + + + + diff --git a/src/skin/screen_ConfigScreen.xmlinc b/src/skin/screen_ConfigScreen.xmlinc new file mode 100644 index 0000000..87ec0c7 --- /dev/null +++ b/src/skin/screen_ConfigScreen.xmlinc @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/skin/screen_EventDetails.xmlinc b/src/skin/screen_EventDetails.xmlinc new file mode 100755 index 0000000..ed95dec --- /dev/null +++ b/src/skin/screen_EventDetails.xmlinc @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/skin/screen_ProgramColumns.xmlinc b/src/skin/screen_ProgramColumns.xmlinc new file mode 100755 index 0000000..7fddbad --- /dev/null +++ b/src/skin/screen_ProgramColumns.xmlinc @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/skin/screenpart_1Button_icon.xmlinc b/src/skin/screenpart_1Button_icon.xmlinc new file mode 100644 index 0000000..7fdff5f --- /dev/null +++ b/src/skin/screenpart_1Button_icon.xmlinc @@ -0,0 +1 @@ + diff --git a/src/skin/screenpart_1Button_name.xmlinc b/src/skin/screenpart_1Button_name.xmlinc new file mode 100644 index 0000000..99ded21 --- /dev/null +++ b/src/skin/screenpart_1Button_name.xmlinc @@ -0,0 +1 @@ + diff --git a/src/skin/screenpart_1Button_source.xmlinc b/src/skin/screenpart_1Button_source.xmlinc new file mode 100644 index 0000000..7770d75 --- /dev/null +++ b/src/skin/screenpart_1Button_source.xmlinc @@ -0,0 +1 @@ + diff --git a/src/skin/screenpart_4Buttons_icon.xmlinc b/src/skin/screenpart_4Buttons_icon.xmlinc new file mode 100644 index 0000000..3494407 --- /dev/null +++ b/src/skin/screenpart_4Buttons_icon.xmlinc @@ -0,0 +1,4 @@ + + + + diff --git a/src/skin/screenpart_4Buttons_name.xmlinc b/src/skin/screenpart_4Buttons_name.xmlinc new file mode 100644 index 0000000..478a313 --- /dev/null +++ b/src/skin/screenpart_4Buttons_name.xmlinc @@ -0,0 +1,5 @@ + + + + + diff --git a/src/skin/screenpart_4Buttons_source.xmlinc b/src/skin/screenpart_4Buttons_source.xmlinc new file mode 100644 index 0000000..1ad6074 --- /dev/null +++ b/src/skin/screenpart_4Buttons_source.xmlinc @@ -0,0 +1,5 @@ + + + + + diff --git a/src/skin/screenpart_Background.xmlinc b/src/skin/screenpart_Background.xmlinc new file mode 100644 index 0000000..73bed6f --- /dev/null +++ b/src/skin/screenpart_Background.xmlinc @@ -0,0 +1,3 @@ + + + diff --git a/src/skin/screenpart_ColorButtons.xmlinc b/src/skin/screenpart_ColorButtons.xmlinc new file mode 100644 index 0000000..ed3e06a --- /dev/null +++ b/src/skin/screenpart_ColorButtons.xmlinc @@ -0,0 +1,4 @@ + + + + diff --git a/src/skin/screenpart_ColorButtonsLabels.xmlinc b/src/skin/screenpart_ColorButtonsLabels.xmlinc new file mode 100644 index 0000000..8babe13 --- /dev/null +++ b/src/skin/screenpart_ColorButtonsLabels.xmlinc @@ -0,0 +1,4 @@ + + + + diff --git a/src/skin/screenpart_DateTime.xmlinc b/src/skin/screenpart_DateTime.xmlinc new file mode 100644 index 0000000..b25906a --- /dev/null +++ b/src/skin/screenpart_DateTime.xmlinc @@ -0,0 +1,6 @@ + + Date + + + Default + diff --git a/src/skin/screenpart_EventDetailsPics.xmlinc b/src/skin/screenpart_EventDetailsPics.xmlinc new file mode 100755 index 0000000..fe8a5ee --- /dev/null +++ b/src/skin/screenpart_EventDetailsPics.xmlinc @@ -0,0 +1,2 @@ + + diff --git a/src/skin/screenpart_ProgramColumnsButtons.xmlinc b/src/skin/screenpart_ProgramColumnsButtons.xmlinc new file mode 100755 index 0000000..2c3c109 --- /dev/null +++ b/src/skin/screenpart_ProgramColumnsButtons.xmlinc @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/skin/screenpart_ProgramColumnsLists.xmlinc b/src/skin/screenpart_ProgramColumnsLists.xmlinc new file mode 100755 index 0000000..96dcc58 --- /dev/null +++ b/src/skin/screenpart_ProgramColumnsLists.xmlinc @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/skin/screenpart_ProgramColumnsPrime.xmlinc b/src/skin/screenpart_ProgramColumnsPrime.xmlinc new file mode 100755 index 0000000..307d471 --- /dev/null +++ b/src/skin/screenpart_ProgramColumnsPrime.xmlinc @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/skin/screenpart_TitleOnly.xmlinc b/src/skin/screenpart_TitleOnly.xmlinc new file mode 100644 index 0000000..8360b2d --- /dev/null +++ b/src/skin/screenpart_TitleOnly.xmlinc @@ -0,0 +1 @@ + diff --git a/src/skin/screenpart_program_template.tpl b/src/skin/screenpart_program_template.tpl new file mode 100644 index 0000000..c1f080d --- /dev/null +++ b/src/skin/screenpart_program_template.tpl @@ -0,0 +1,16 @@ +{ + "template": [ + MultiContentEntryText(pos=(5,7),size=(55,23),font=1,flags=RT_HALIGN_LEFT,text=0,backcolor=None), + MultiContentEntryText(pos=(65,5),size=(245,75),font=0,flags=RT_HALIGN_LEFT|RT_WRAP,text=1,backcolor=None), + MultiContentEntryText(pos=(65,87),size=(245,23),font=1,flags=RT_HALIGN_LEFT|RT_WRAP,text=2,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None), + MultiContentEntryText(pos=(65,115),size=(245,23),font=1,flags=RT_HALIGN_LEFT|RT_WRAP,text=3,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None), + MultiContentEntryText(pos=(0,0),size=(320,140),font=1,flags=RT_VALIGN_CENTER,text="",border_width=1,border_color=0x595959), + ], + "itemHeight":140, + "selectionEnabled":False, + "fonts":[ + gFont("Regular",23), + gFont("Regular",20), + gFont("Regular",17) + ] +} diff --git a/src/skin/skin_src.xml b/src/skin/skin_src.xml new file mode 100644 index 0000000..fcc907e --- /dev/null +++ b/src/skin/skin_src.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/tvc1.png b/tvc1.png new file mode 100755 index 0000000..888ca88 Binary files /dev/null and b/tvc1.png differ diff --git a/tvc2.png b/tvc2.png new file mode 100755 index 0000000..5283c76 Binary files /dev/null and b/tvc2.png differ