diff --git a/.pylintrc b/.pylintrc index 6d571a9..fd30fdd 100644 --- a/.pylintrc +++ b/.pylintrc @@ -130,7 +130,7 @@ disable=print-statement, R0201, R0205, C0103, C0114, C0326, C0330, - W0122, W0123, W0201, W0311, W0312, W0603, W0703, W1505, + W0122, W0123, W0201, W0212, W0221, W0311, W0312, W0603, W0614, W0703, W1113, W1505, E0401, E0611, E1101 # Enable the message, report, category or checker with the given id(s). You can diff --git a/CONTROL/control b/CONTROL/control index ac5ab05..0e234ea 100644 --- a/CONTROL/control +++ b/CONTROL/control @@ -1,6 +1,6 @@ Description: MediathekCockpit Maintainer: dream-alpha Package: enigma2-plugin-extensions-mediathekcockpit -Version: 0.1.2 +Version: 0.2.5 Architecture: all Depends: python-requests, enigma2-plugin-skincomponents-extmultilistselection diff --git a/Components/Converter/MvVideoInfo.py b/Components/Converter/MTCVideoInfo.py similarity index 97% rename from Components/Converter/MvVideoInfo.py rename to Components/Converter/MTCVideoInfo.py index 2bff50d..31dbaaf 100644 --- a/Components/Converter/MvVideoInfo.py +++ b/Components/Converter/MTCVideoInfo.py @@ -3,7 +3,7 @@ from enigma import iServiceInformation, iPlayableService -class MvVideoInfo(Converter, object): +class MTCVideoInfo(Converter, object): def __init__(self, atype): Converter.__init__(self, atype) diff --git a/po/de.po b/po/de.po index 4d5a856..8997567 100644 --- a/po/de.po +++ b/po/de.po @@ -1,8 +1,8 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"POT-Creation-Date: 2024-04-16 16:18+0200\n" -"PO-Revision-Date: 2024-04-16 16:26+0200\n" +"POT-Creation-Date: 2024-04-22 13:47+0200\n" +"PO-Revision-Date: 2024-04-22 13:47+0200\n" "Last-Translator: dream-alpha\n" "Language-Team: \n" "Language: de_DE\n" @@ -14,269 +14,158 @@ msgstr "" "X-Poedit-Basepath: ../src\n" "X-Poedit-SearchPath-0: .\n" -msgid "Error during download." -msgstr "Fehler beim Download" - -msgid "Clock" -msgstr "Uhr" - -msgid "Live channels" -msgstr "Live-Kanäle" - -msgid "Channel selection" +msgid "Channel Selection" msgstr "Kanalauswahl" -msgid "All movies" -msgstr "Alle Filme" - -msgid "Search" -msgstr "Suche nach:" - -msgid "Favorites" -msgstr "Favoriten" - -msgid "MediathekCockpit" -msgstr "MediathekCockpit" - -msgid "Download started..." -msgstr "Download wurde gestartet..." - -msgid "Low" -msgstr "Niedrig" - -msgid "Medium" -msgstr "Mittel" - -msgid "Maximum" -msgstr "Maximum" - -msgid "Video" -msgstr "Film" - -msgid "Resolution" -msgstr "Auflösung" - -msgid "Option Selector" -msgstr "Auswahl" +msgid "Live" +msgstr "Live" msgid "Movies" msgstr "Filme" -msgid "No favorites available" -msgstr "Keine Favoriten verfügbar" - -msgid "Search list" -msgstr "Suchliste" - -msgid "No search list available" -msgstr "Keine Suchliste verfügbar" - -msgid "Delete" -msgstr "Löschen" - -msgid "Enter search text" -msgstr "Eingabe des Suchtexts" - -msgid "Easy selection" -msgstr "Einfach-Auswahl" - -msgid "All" -msgstr "Alle" - -msgid "Manual search" -msgstr "Manuelle Suche" +msgid "Search" +msgstr "Suche" -msgid "Search for all entries in the search list" -msgstr "Suche nach allen Einträgen in der Suchliste" +msgid "All channels" +msgstr "Alle Kanäle" -msgid "Edit selected entry" -msgstr "Ausgewählten Eintrag editieren" +msgid "Download failed" +msgstr "Download fehlgeschlagen" -msgid "Remove entry" -msgstr "Auswahl entfernen" +msgid "High" +msgstr "Hoch" -msgid "Add entry" -msgstr "Eintrag hinzufügen" +msgid "Medium" +msgstr "Mittel" -msgid "Search for '%s'" -msgstr "Suche nach %s:" +msgid "Low" +msgstr "Niedrig" -msgid "Manual Search" -msgstr "Manuelle Suche" +msgid "Do nothing" +msgstr "Nichts tun" -msgid "Select" -msgstr "Auswählen" +msgid "Ask user" +msgstr "Benutzer fragen" -msgid "Added '%s'" -msgstr "'%s' hinzugefügt" +msgid "Close" +msgstr "Schliessen" -msgid "Entry already exists" -msgstr "Eintrag existiert bereits" +msgid "Save" +msgstr "Speichern" -msgid "Added:" -msgstr "Hinzugefügt:" +msgid "Abort current download" +msgstr "Laufenden Download abbrechen" -msgid "Directory %s does not exist." -msgstr "Verzeichnis %s existiert nicht." +msgid "Abort all downloads" +msgstr "Alle Downloads abbrechen" -msgid "Name" -msgstr "Name" +msgid "Abort all pending downloads" +msgstr "Alle wartenden Downloads abbrechen" -msgid "Fields:" -msgstr "Felder:" +msgid "Abort" +msgstr "Abbrechen" -msgid "Channel" -msgstr "Kanal" +msgid "Channels" +msgstr "Kanäle" -msgid "Add favorite" -msgstr "Zu Favoriten hinzufügen" +msgid "Default" +msgstr "Standard" -msgid "Remove favorite" -msgstr "Aus Favoriten entfernen" +msgid "options" +msgstr "Optionen" -msgid "movie" -msgstr "Film" +msgid "Live channels" +msgstr "Live-Kanäle" -msgid "Save" -msgstr "Speichern" +msgid "Download Manager" +msgstr "Download Manager" -msgid "Setup" +msgid "Settings" msgstr "Einstellungen" -msgid "Download manager" -msgstr "Download Manager" - -msgid "Default" -msgstr "Standard" +msgid "About" +msgstr "Über" -msgid "options" -msgstr "Optionen" +msgid "Functions" +msgstr "Funktionen" -msgid "Move selected item up" -msgstr "Ausgewählter Eintrag nach oben" +msgid "Menu" +msgstr "Menü" -msgid "Move selected item down" -msgstr "Ausgewähler Eintrag nach unten" - -msgid "Reset" -msgstr "Zurücksetzen" +msgid "Quit" +msgstr "Beenden" -msgid "remove entry" -msgstr "Eintrag entfernen" +msgid "Restart from the beginning" +msgstr "Neustart von Anfang an" -msgid "Please wait... Loading list..." -msgstr "Liste wird geladen..." +msgid "None" +msgstr "Nichts" -msgid "Page:" -msgstr "Seite:" +msgid "Action" +msgstr "Aktion" -msgid "Online" -msgstr "Online" +msgid "Search results" +msgstr "Suchergebnisse" -msgid "Please wait..." -msgstr "Bitten warten..." +msgid "Download" +msgstr "Download" msgid "Next page" msgstr "Nächste Seite" -msgid "Entries" -msgstr "Einträge" - -msgid "Time" -msgstr "Zeit" - -msgid "From" -msgstr "Von" +msgid "Select" +msgstr "Auswählen" -msgid "Date" -msgstr "Datum" +msgid "Broadcast time" +msgstr "Sendezeit" msgid "Duration" msgstr "Dauer" -msgid "Download failed" -msgstr "Download fehlgeschlagen" - -msgid "Close" -msgstr "Schliessen" - -msgid "Current" -msgstr "Aktuellen" - -msgid "Abort" -msgstr "Abbrechen" - -msgid "All open" -msgstr "Alle offene" - -msgid "Search entry" -msgstr "Suche" +msgid "Quality" +msgstr "Auflösung" -msgid "Cancel" -msgstr "Abbrechen" +msgid "Entries" +msgstr "Einträge" -msgid "Topic" -msgstr "Thema" +msgid "Load time" +msgstr "Ladedauer" -msgid "Title" -msgstr "Titel" +msgid "From" +msgstr "Ladezeit" -msgid "Description" -msgstr "Beschreibung" +msgid "Download added" +msgstr "Download hinzugefügt" -msgid "Search for:" -msgstr "Suche nach:" +msgid "Video resolution" +msgstr "Filmauflösung" -msgid "Channels:" -msgstr "Kanäle:" +msgid "Movie directory does not exist" +msgstr "Filmverzeichnis existiert nicht" -msgid "Enter text to search for" +msgid "Enter search text" msgstr "Eingabe des Suchtexts" -msgid "No, do nothing." -msgstr "Nichts tun" +msgid "MediathekCockpit" +msgstr "MediathekCockpit" -msgid "Ask user" -msgstr "Benutzer fragen" +msgid "Setup" +msgstr "Einstellungen" + +msgid "Cancel" +msgstr "Abbrechen" msgid "Entries per page" msgstr "Einträge pro Seite" -msgid "Future" -msgstr "Filme aus der Zukunft anzeigen" - -msgid "Yellow button mapping" -msgstr "Belegung der gelben Taste" - -msgid "Minimum movie" -msgstr "Minimale Film" - -msgid "minutes" -msgstr "Minuten" - -msgid "disabled" -msgstr "deaktiviert" - -msgid "Maximum movie" -msgstr "Maximale Film" +msgid "Show future movies" +msgstr "Zeige zukünftige Filme" -msgid "Behavior when a movie is stopped" +msgid "Behavior when movie stopped" msgstr "Verhalten beim Stoppen des Films" -msgid "Select movie path" -msgstr "Auswahl des Filmpfads" - -msgid "Quit" -msgstr "Beenden" - -msgid "Restart from the beginning" -msgstr "Neustart von Anfang an" - -msgid "None" -msgstr "Nichts" - -msgid "Action" -msgstr "Aktion" +msgid "Movie path" +msgstr "Filmpfad" msgid "Browse Mediathek libraries" msgstr "Mediatheken durchsuchen, Filme abspielen und herunterladen" @@ -286,3 +175,15 @@ msgstr "Mediathek Downloads ..." msgid "MediathekCockpit Search" msgstr "MediathekCockpit Suche" + +msgid "Plugin" +msgstr "Plugin" + +msgid "Version" +msgstr "Version" + +msgid "Copyright" +msgstr "Copyright" + +msgid "License" +msgstr "Lizenz" 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/Channels.py b/src/Channels.py new file mode 100644 index 0000000..3a80679 --- /dev/null +++ b/src/Channels.py @@ -0,0 +1,163 @@ +#!/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 Screens.Screen import Screen +from Screens.MessageBox import MessageBox +from Components.ActionMap import ActionMap +from Components.Label import Label +from Components.Sources.StaticText import StaticText +from Components.Sources.List import List +from .Debug import logger +from .LoadPixmap import loadPixmap +from .Downloader import MyGetPage, headersplain +from .MyDeferredSemaphore import MyDeferredSemaphore +from .__init__ import _ +from .Version import PLUGIN +from .Menu import Menu +from .Constants import plugindir, CHAN_CHANNEL + + +class Channels(Screen): + def attrgetter(self, default=None): + attr = self + + def get_any(_self): + return getattr(Channels, attr, default) + return get_any + + def attrsetter(self): + attr = self + + def set_any(_self, value): + setattr(Channels, attr, value) + return set_any + + curr_index = property(attrgetter('_curr_index', 0), attrsetter('_curr_index')) + + def __init__(self, session, postdata): + logger.info("curr_index: %s", self.curr_index) + self.postdata = postdata + Screen.__init__(self, session) + self.skinName = 'MediathekCockpit' + self.title = PLUGIN + ' - ' + _('Channel Selection') + + self['key_red'] = StaticText(_('Live')) + self['key_green'] = StaticText() + self['key_yellow'] = StaticText(_('Movies')) + self['key_blue'] = StaticText(_('Search')) + + self['description'] = Label('') + self['date'] = Label('') + self['sresult'] = Label('') + + self['list'] = List() + + self['actions'] = ActionMap( + ['MTC_Actions'], + { + 'ok': self.pressOk, + 'cancel': self.pressClose, + 'red': self.pressRed, + # 'green': self.pressGreen, + 'yellow': self.pressYellow, + 'blue': self.pressBlue, + 'menu': self.pressMenu, + # 'info': self.pressInfo + } + ) + self['list'].onSelectionChanged.append(self.__SelectionChanged) + self.onLayoutFinish.append(self.__onLayoutFinish) + self.download = MyDeferredSemaphore(tokens=1) + + def __onLayoutFinish(self): + logger.info("...") + url = 'https://mediathekviewweb.de/api/channels' + self.download.start( + MyGetPage, + url=url, + headers=headersplain + ).addCallback(self.downloadSucceeded).addErrback(self.downloadFailed) + + def downloadSucceeded(self, result): + logger.info("...") + self['list'].style = 'default' + self.list = [] + self.curr_index2 = self.curr_index + if result: + self.list.append((_("All channels"), "", None)) + data = json.loads(result) + # logger.info("data: %s", data) + if not data.get('error', True): + channels = data['channels'] + for channel in channels: + name = channel.encode('utf-8') + ptr = loadPixmap('%slogos/%s.png' % (plugindir, name.replace(' ', '').upper())) + self.list.append((name, '', ptr)) + # logger.info("list: %s", self.list) + self["list"].setList(self.list) + self["list"].setIndex(self.curr_index2) + + def downloadFailed(self, failure, *args): + logger.info("...") + error_message = str(failure.getErrorMessage()) + if not error_message: + error_message = str(failure) + logger.error("%s, %s", error_message, str(args)) + if 'CancelledError' not in error_message: + self.session.open(MessageBox, error_message, MessageBox.TYPE_INFO, timeout=10, title=_('Download failed')) + + def __SelectionChanged(self): + logger.info("...") + self.curr = self['list'].getCurrent() + self.curr_index = self['list'].getIndex() + if self.curr[CHAN_CHANNEL] == _("All channels"): + if "queries" in self.postdata: + del self.postdata['queries'] + else: + self.postdata['queries'] = [] + self.postdata['queries'].append({'fields': ['channel'], 'query': self.curr[CHAN_CHANNEL].encode('utf-8')}) + self.postdata['offset'] = 0 + + def pressOk(self): + self.close("movies") + + def pressRed(self): + self.close("streams") + + def pressGreen(self): + pass + + def pressYellow(self): + self.close("movies") + + def pressBlue(self): + self.close("search") + + def pressMenu(self): + Menu(self.session, self.postdata) + + def pressInfo(self): + pass + + def pressClose(self): + logger.info("...") + self.close("exit") diff --git a/src/ConfigInit.py b/src/ConfigInit.py index 3264a77..f600513 100644 --- a/src/ConfigInit.py +++ b/src/ConfigInit.py @@ -19,8 +19,15 @@ # . -from Components.config import config, ConfigSelection, ConfigSubsection +from Components.config import config, ConfigSelection, ConfigSelectionNumber, ConfigYesNo, ConfigDirectory, ConfigSubsection from .Debug import logger, log_levels +from .__init__ import _ + +from .Constants import LIST_URL_VIDEO_LOW, LIST_URL_VIDEO, LIST_URL_VIDEO_HD + + +VIDEO_RESOLUTIONS = [LIST_URL_VIDEO_HD, LIST_URL_VIDEO, LIST_URL_VIDEO_LOW] +VIDEO_RESOLUTIONS_DICT = {LIST_URL_VIDEO_HD: _("High"), LIST_URL_VIDEO: _("Medium"), LIST_URL_VIDEO_LOW: _("Low")} class ConfigInit(): @@ -29,3 +36,8 @@ def __init__(self): logger.info("...") config.plugins.mediathekcockpit = ConfigSubsection() config.plugins.mediathekcockpit.debug_log_level = ConfigSelection(default="DEBUG", choices=list(log_levels.keys())) + config.plugins.mediathekcockpit.size = ConfigSelectionNumber(min=50, max=1500, stepwidth=50, default=500) + config.plugins.mediathekcockpit.future = ConfigYesNo(default=False) + config.plugins.mediathekcockpit.askstopmovie = ConfigSelection(default='quit', choices=[('quit', _('Do nothing')), ('ask', _('Ask user'))]) + config.plugins.mediathekcockpit.movie_resolution = ConfigSelection(default=str(LIST_URL_VIDEO_HD), choices=[(str(LIST_URL_VIDEO_LOW), _('Low')), (str(LIST_URL_VIDEO), _('Medium')), (str(LIST_URL_VIDEO_HD), _('High'))]) + config.plugins.mediathekcockpit.moviesavedir = ConfigDirectory(default='/media/hdd/movie/') diff --git a/src/ConfigUtils.py b/src/ConfigUtils.py deleted file mode 100644 index 2d5c64b..0000000 --- a/src/ConfigUtils.py +++ /dev/null @@ -1,71 +0,0 @@ -import os -import json -from .Debug import logger -from .Constants import enigma2configdir, listfields - - -configfile = enigma2configdir + 'mv_config.json' - - -def read_mvconfig(): - logger.info("...") - mvconfig = {} - mvconfig['offset'] = 0 - mvconfig['size'] = 500 - mvconfig['future'] = False - mvconfig['askstopmovie'] = 'quit' - mvconfig['channels'] = ['ARD', 'ZDF', 'NDR', 'BR', 'SR', 'SWR', 'SRF', '3Sat', 'HR', 'WDR', 'MDR', 'RBB', 'ARTE.DE', 'ARTE.FR', 'PHOENIX', 'ORF', 'KiKA', 'DW', 'ZDF-tivi', 'SRF.Podcast'] - mvconfig['channelslist'] = [] - mvconfig['livechannels'] = [] - mvconfig['favorites'] = [] - mvconfig['searchquerys'] = [] - mvconfig['searchquerysfields'] = listfields['topic'] - mvconfig['searchstart'] = 'easyselection' - mvconfig['playmovieselect'] = 'url_video_hd' - mvconfig['moviesavedir'] = '/media/hdd/movie/' - mvconfig['postdata'] = {'sortOrder': 'desc', 'sortBy': 'timestamp'} - if os.path.exists(configfile): - with open(configfile) as (data_file): - data = json.load(data_file) - mvconfig['size'] = data.get('size', 500) - mvconfig['future'] = data.get('future', False) - mvconfig['askstopmovie'] = data.get('askstopmovie', 'quit') - mvconfig['searchquerysfields'] = data.get('searchquerysfields', listfields['topic']) - mvconfig['searchstart'] = data.get('searchstart', 'easyselection') - mvconfig['playmovieselect'] = data.get('playmovieselect', 'url_video_hd') - mvconfig['moviesavedir'] = data.get('moviesavedir', '/media/hdd/movie/') - if data.get('duration_min', 0) > 0: - mvconfig['duration_min'] = data['duration_min'] - mvconfig['postdata']['duration_min'] = mvconfig['duration_min'] * 60 - if data.get('duration_max', 0) > 0: - mvconfig['duration_max'] = data['duration_max'] - mvconfig['postdata']['duration_max'] = mvconfig['duration_max'] * 60 - mvconfig['postdata']['size'] = mvconfig['size'] - mvconfig['postdata']['offset'] = 0 - mvconfig['postdata']['future'] = mvconfig['future'] - return mvconfig - - -def write_mvconfig(mvconfig): - logger.info("...") - tmp = {} - if mvconfig['size'] != 500: - tmp['size'] = mvconfig['size'] - if mvconfig['future']: - tmp['future'] = mvconfig['future'] - if mvconfig['askstopmovie'] != 'quit': - tmp['askstopmovie'] = mvconfig['askstopmovie'] - if mvconfig['searchquerysfields'] != listfields['topic']: - tmp['searchquerysfields'] = mvconfig['searchquerysfields'] - if mvconfig['searchstart'] != 'easyselection': - tmp['searchstart'] = mvconfig['searchstart'] - if mvconfig['playmovieselect'] != 'url_video_hd': - tmp['playmovieselect'] = mvconfig['playmovieselect'] - if mvconfig['moviesavedir'] != '/media/hdd/movie/': - tmp['moviesavedir'] = mvconfig['moviesavedir'] - if mvconfig.get('duration_min', 0) > 0: - tmp['duration_min'] = mvconfig['duration_min'] - if mvconfig.get('duration_max', 0) > 0: - tmp['duration_max'] = mvconfig['duration_max'] - with open(configfile, 'w') as (fp): - json.dump(tmp, fp, indent=2, sort_keys=True) diff --git a/src/Constants.py b/src/Constants.py index d5530dd..3739975 100644 --- a/src/Constants.py +++ b/src/Constants.py @@ -1,59 +1,62 @@ +#!/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: +# . + + plugindir = "/usr/lib/enigma2/python/Plugins/Extensions/MediathekCockpit/" -enigma2configdir = "/etc/enigma2/" -listindex = {} -listindex['channel'] = 0 -listindex['topic'] = 1 -listindex['title'] = 2 -listindex['description'] = 3 -listindex['time'] = 4 -listindex['date'] = 5 -listindex['duration'] = 6 -listindex['size'] = 7 -listindex['channelpixmap'] = 8 -listindex['timetext'] = 9 -listindex['id'] = 10 -listindex['url_video_low'] = 11 -listindex['url_video'] = 12 -listindex['url_video_hd'] = 13 -listindex['url_website'] = 14 -listindex['listend'] = 15 -listempty = [''] * listindex['listend'] -listempty[listindex['size']] = 0 -listempty[listindex['channelpixmap']] = None -listsearchquerys = {} -listsearchquerys['name'] = 0 -listsearchquerys['fields'] = 1 -listsearchquerys['channel'] = 2 -listsearchquerys['queries'] = 3 -listsearchquerys['listend'] = 4 -listchannel = {} -listchannel['channel'] = 0 -listchannel['dummy'] = 1 -listchannel['channelpixmap'] = 2 -listchannel['listend'] = 3 -liveindex = {} -liveindex['name'] = 0 -liveindex['for_lcd'] = 1 -liveindex['channelpixmap'] = 2 -liveindex['master_url'] = 3 -liveindex['index_url'] = 4 -liveindex['audio_url'] = 5 -liveindex['service'] = 6 -liveindex['options'] = 7 -liveindex['eservice'] = 8 -liveindex['default'] = 9 -liveindex['logo_name'] = 10 -liveindex['listend'] = 11 -liveempty = [''] * liveindex['listend'] -liveempty[liveindex['channelpixmap']] = None -listfields = {} -listfields['channel'] = ['channel'] -listfields['topic'] = ['topic'] -listfields['title'] = ['title'] -listfields['description'] = ['description'] -listfields['topictitle'] = ['topic', 'title'] -listfields['topictitledescription'] = ['topic', 'title', 'description'] -mainindex = {} -mainindex['livestream'] = 2 -mainindex['moviliste'] = listindex['listend'] +LIST_CHANNEL = 0 +LIST_TOPIC = 1 +LIST_TITLE = 2 +LIST_DESCRIPTION = 3 +LIST_TIME = 4 +LIST_DATE = 5 +LIST_DURATION = 6 +LIST_SIZE = 7 +LIST_CHANNELPIXMAP = 8 +LIST_ID = 9 +LIST_URL_VIDEO_LOW = 10 +LIST_URL_VIDEO = 11 +LIST_URL_VIDEO_HD = 12 +LIST_URL_WEBSITE = 13 +LIST_END = 14 + +listempty = [''] * LIST_END +listempty[LIST_SIZE] = 0 +listempty[LIST_CHANNELPIXMAP] = None + +CHAN_CHANNEL = 0 +CHAN_CHANNELPIXMAP = 1 +CHAN_END = 2 + +LIVE_NAME = 0 +LIVE_FOR_LCD = 1 +LIVE_CHANNELPIXMAP = 2 +LIVE_MASTER_URL = 3 +LIVE_INDEX_URL = 4 +LIVE_AUDIO_URL = 5 +LIVE_SERVICE = 6 +LIVE_OPTIONS = 7 +LIVE_ESERVICE = 8 +LIVE_DEFAULT = 9 +LIVE_LOGO_NAME = 10 +LIVE_END = 11 + +liveempty = [''] * LIVE_END +liveempty[LIVE_CHANNELPIXMAP] = None diff --git a/src/MediathekCockpitDirBrowser.py b/src/DirBrowser.py similarity index 62% rename from src/MediathekCockpitDirBrowser.py rename to src/DirBrowser.py index b3b9e99..728fedd 100644 --- a/src/MediathekCockpitDirBrowser.py +++ b/src/DirBrowser.py @@ -1,3 +1,24 @@ +#!/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 Screens.SimpleSummary import SimpleSummary from Components.ActionMap import ActionMap @@ -7,11 +28,11 @@ from .Debug import logger -class MediathekCockpitDirBrowser(Screen): +class DirBrowser(Screen): def __init__(self, session, directory=''): logger.info("...") - self.skinName = 'MediathekCockpitDirBrowser' + self.skinName = 'DirBrowser' Screen.__init__(self, session) if directory == '': directory = '/' diff --git a/src/Downloader.py b/src/Downloader.py index e47b9ef..bb5d747 100644 --- a/src/Downloader.py +++ b/src/Downloader.py @@ -1,3 +1,24 @@ +#!/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 cookielib import CookieJar from twisted.web.http_headers import Headers from twisted.web.client import Agent, RedirectAgent, _GzipProtocol, CookieAgent, PartialDownloadError, BrowserLikePolicyForHTTPS, HTTPConnectionPool, _requireSSL @@ -61,9 +82,9 @@ def _identityVerifyingInfoCallback(self, connection, where, _ret): try: verifyHostname(connection, self._hostnameASCII) except (CertificateError, VerificationError) as e: - print('Remote certificate is not valid for hostname "%s"; %s' % (self._hostnameASCII, e)) + logger.error('Remote certificate is not valid for hostname "%s"; %s', self._hostnameASCII, e) except ValueError as e: - print('Ignoring error while verifying certificate from host "%s" (exception: %s)' % (self._hostnameASCII, repr(e))) + logger.error('Ignoring error while verifying certificate from host "%s" (exception: %s)', self._hostnameASCII, repr(e)) try: @@ -104,8 +125,7 @@ def getContext(self, hostname=None, port=None): @_requireSSL def creatorForNetloc(self, hostname, port): - logger.info("...") - print('creatorForNetloc', hostname) + logger.info("hostname: %s", hostname) return MyClientTLSOptions(hostname.decode('ascii'), self.getContext(hostname, port)) @@ -130,7 +150,6 @@ def stop(self): def addProgress(self, progress_callback): logger.info("...") - print('[addProgress]') self.factory.progress_callback = progress_callback @@ -139,8 +158,12 @@ def MydownloadPage(url, file=None, method='GET', headers=_headers, postdata=None 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): +def MyGetPage(url, fileOrName=None, method='GET', headers=_headers, postdata=None, contextFactory=ClientContextFactory(), *args, **kwargs): logger.info("...") + logger.debug( + "url: %s, fileOrName: %s, method: %s, headers: %s, postdata: %s", + url, fileOrName, method, headers, postdata + ) return getPagenew(url, fileOrName, method, headers, postdata, contextFactory, *args, **kwargs).deferred @@ -248,7 +271,7 @@ def connectionLost(self, reason=None): self.finished.callback(None) elif reason.check(PotentialDataLoss): self.finished.errback(Failure()) - print('PotentialDataLoss') + logger.error('PotentialDataLoss') else: self.finished.errback(reason) @@ -282,7 +305,7 @@ def _cancel(_): try: response._transport._producer.abortConnection() except Exception as e: - print('####################################', e) + logger.error('exception: %s', e) finished = Deferred(canceller=_cancel) if 'CallbackResponse' in kwargs: @@ -313,9 +336,9 @@ def http_failed(failure_instance=None, *args, **kwargs): 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.debug(text, failure_instance, args, kwargs) - logger.debug(failure_instance.printDetailedTraceback()) + text += _('Download failed') + '\n\n' + error_message + '\n' + logger.debug("%s, %s, %s, %s", text, failure_instance, args, kwargs) + logger.error("traceback: %s", failure_instance.printDetailedTraceback()) try: if mysession: mysession.toastManager.showToast(text, int(kwargs.get('duration', 20))) diff --git a/src/MediathekCockpitDownloadView.py b/src/Downloads.py old mode 100644 new mode 100755 similarity index 61% rename from src/MediathekCockpitDownloadView.py rename to src/Downloads.py index 8d51ce0..26567f0 --- a/src/MediathekCockpitDownloadView.py +++ b/src/Downloads.py @@ -1,3 +1,24 @@ +#!/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 Components.ActionMap import ActionMap from Components.Sources.StaticText import StaticText @@ -5,32 +26,33 @@ from MyJobManager import downloadManager from enigma import eTimer from .__init__ import _ +from .FileUtils import deleteFile from .Debug import logger -class MediathekCockpitDownloadView(Screen): +class Downloads(Screen): IS_DIALOG = True def __init__(self, session): logger.info("...") Screen.__init__(self, session) - self.skinName = 'MediathekCockpitDownloadView' + self.skinName = 'Downloads' self['actions'] = ActionMap( - ['MVD_Actions'], + ['MTC_Actions'], { 'ok': self.close, 'cancel': self.close, - 'red': self.currabort, + 'red': self.key_red, 'green': self.key_green, 'yellow': self.key_yellow, 'blue': self._createSetup } ) - self['key_red'] = StaticText(_('Current') + ' ' + _('Abort')) - self['key_green'] = StaticText(_('All') + ' ' + _('Abort')) - self['key_yellow'] = StaticText(_('All open') + ' ' + _('Abort')) + self['key_red'] = StaticText(_('Abort current download')) + self['key_green'] = StaticText(_('Abort all downloads')) + self['key_yellow'] = StaticText(_('Abort all pending downloads')) self['key_blue'] = StaticText('') - self['liste'] = List([]) + self['list'] = List([]) self.currindex = 0 self.__dlRefreshTimer = eTimer() self.__dlRefreshTimer_conn = self.__dlRefreshTimer.timeout.connect(self._createSetup) @@ -39,7 +61,7 @@ def __init__(self, session): def _createSetup(self): logger.info("...") self.__dlRefreshTimer.stop() - self.currindex = self['liste'].index + self.currindex = self['list'].index result = [] for job in downloadManager.getPendingJobs(): if job.status == job.IN_PROGRESS: @@ -51,8 +73,8 @@ def _createSetup(self): else: result.append([job.name, job.getStatustext(), -1, '', job]) - self['liste'].setList(result) - self['liste'].index = self.currindex + self['list'].setList(result) + self['list'].index = self.currindex if len(result) > 0 and not self.__dlRefreshTimer.isActive(): self.__dlRefreshTimer.startLongTimer(2) @@ -61,7 +83,7 @@ def key_yellow(self): self.__dlRefreshTimer.stop() downloadManager.active_jobs = [] for job in downloadManager.active_jobs: - print(job.name) + logger.debug("job.name: %s", job.name) job.abort() self._createSetup() @@ -75,14 +97,16 @@ def key_green(self): currjob.cancel() self._createSetup() - def currabort(self): + def key_red(self): logger.info("...") - curr = self['liste'].getCurrent() + curr = self['list'].getCurrent() if curr and len(curr) == 5: self.__dlRefreshTimer.stop() currjob = curr[4] + logger.debug("currjob: %s", currjob.file_name) if currjob.status == currjob.NOT_STARTED: downloadManager.active_jobs.remove(currjob) elif currjob.status == currjob.IN_PROGRESS: currjob.cancel() + deleteFile(currjob.file_name) self._createSetup() diff --git a/src/EventView.py b/src/EventView.py new file mode 100644 index 0000000..e0e735b --- /dev/null +++ b/src/EventView.py @@ -0,0 +1,54 @@ +#!/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 Components.ActionMap import ActionMap +from Components.Label import Label +from Components.ScrollLabel import ScrollLabel +from Components.Sources.StaticText import StaticText +from .Debug import logger +from .__init__ import _ +from .Constants import LIST_TOPIC, LIST_TITLE, LIST_DESCRIPTION, LIST_DATE, LIST_DURATION, LIST_CHANNEL, LIST_TIME + + +class EventView(Screen): + + def __init__(self, session, curr): + logger.info("...") + Screen.__init__(self, session, windowTitle=curr[LIST_TOPIC]) + self.skinName = 'MTCEventView' + self['actions'] = ActionMap( + ['MTC_Actions', 'OkCancelActions', 'ChannelSelectEPGActions'], + { + 'red': self.close, + 'ok': self.close, + 'cancel': self.close, + 'showEPGList': self.close + } + ) + self['key_red'] = StaticText(_("Abort")) + self['key_green'] = StaticText() + self['key_yellow'] = StaticText() + self['key_blue'] = StaticText() + self['epg_description'] = ScrollLabel(curr[LIST_TITLE] + '\n\n\n' + curr[LIST_DESCRIPTION]) + self['datetime'] = Label(curr[LIST_DATE] + ' ' + curr[LIST_TIME]) + self['duration'] = Label(curr[LIST_DURATION]) + self['channel'] = Label(curr[LIST_CHANNEL]) diff --git a/src/FavoriteUtils.py b/src/FavoriteUtils.py deleted file mode 100644 index b52ad82..0000000 --- a/src/FavoriteUtils.py +++ /dev/null @@ -1,91 +0,0 @@ -import os -import json -from .Debug import logger -from .Constants import plugindir, enigma2configdir, listindex, listempty -from .LoadPixmap import Load_My_Pixmap -from .__init__ import _ - - -favoritesfile = enigma2configdir + 'mv_favorites.json' - - -def convert_favorites(value, tmplist): - logger.info("...") - tmp = listempty[:] - if 'channel' in value: - name = value['channel'].encode('utf-8') - ptr = Load_My_Pixmap('%slogos/%s.png' % (plugindir, name.upper())) - tmp[listindex['channel']] = name - tmp[listindex['channelpixmap']] = ptr - tmp[listindex['timetext']] = _('Clock') - if 'topic' in value: - tmp[listindex['topic']] = value['topic'].encode('utf-8') - if 'topic' in value: - tmp[listindex['topic']] = value['topic'].encode('utf-8') - if 'title' in value: - tmp[listindex['title']] = value['title'].encode('utf-8') - if 'description' in value: - tmp[listindex['description']] = value['description'].encode('utf-8') - if 'time' in value: - tmp[listindex['time']] = value['time'].encode('utf-8') - if 'date' in value: - tmp[listindex['date']] = value['date'].encode('utf-8') - if 'duration' in value: - tmp[listindex['duration']] = value['duration'].encode('utf-8') - if 'size' in value: - tmp[listindex['size']] = value['size'] - if 'id' in value: - tmplist['favodict'][value['id']] = True - tmp[listindex['id']] = value['id'] - if 'url_video_low' in value: - tmp[listindex['url_video_low']] = value['url_video_low'] - if 'url_video' in value: - tmp[listindex['url_video']] = value['url_video'] - if 'url_video_hd' in value: - tmp[listindex['url_video_hd']] = value['url_video_hd'] - if 'url_website' in value: - tmp[listindex['url_website']] = value['url_website'] - return tmp, tmplist - - -def read_favorites(tmplist): - logger.info("...") - favorites = [] - changed = False - if os.path.exists(favoritesfile): - with open(favoritesfile) as (data_file): - data = json.load(data_file) - for value in data: - if isinstance(value, list): - changed = True - tmp = {} - for xres in value: - tmp.update(xres) - - value = tmp - favorites.append(convert_favorites(value, tmplist)) - return favorites, tmplist, changed - - -def write_favorites(favorites): - logger.info("...") - with open(favoritesfile, 'w') as (fp): - result = [] - for value in favorites: - tmp = {} - tmp['channel'] = value[listindex['channel']] - tmp['topic'] = value[listindex['topic']] - tmp['title'] = value[listindex['title']] - tmp['description'] = value[listindex['description']] - tmp['time'] = value[listindex['time']] - tmp['date'] = value[listindex['date']] - tmp['duration'] = value[listindex['duration']] - tmp['size'] = value[listindex['size']] - tmp['id'] = value[listindex['id']] - tmp['url_video_low'] = value[listindex['url_video_low']] - tmp['url_video'] = value[listindex['url_video']] - tmp['url_video_hd'] = value[listindex['url_video_hd']] - tmp['url_website'] = value[listindex['url_website']] - result.append(tmp) - - json.dump(result, fp, encoding='utf-8', indent=2, sort_keys=True) diff --git a/src/Live.py b/src/Live.py new file mode 100644 index 0000000..e36b312 --- /dev/null +++ b/src/Live.py @@ -0,0 +1,216 @@ +#!/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 uuid import uuid4 +from enigma import eServiceReference +from Screens.Screen import Screen +from Screens.MessageBox import MessageBox +from Components.ActionMap import ActionMap +from Components.Label import Label +from Components.Sources.StaticText import StaticText +from Components.Sources.List import List +from .Debug import logger +from .__init__ import _ +from .Version import PLUGIN +from .LiveUtils import readLiveChannels, writeLiveChannels +from .MoviePlayer import StreamPlayer +from .M3U8Parser import M3U8Parser +from .Downloader import MyGetPage, _headers +from .MyDeferredSemaphore import MyDeferredSemaphore +from .Menu import Menu +from .Constants import LIVE_MASTER_URL, LIVE_INDEX_URL, LIVE_AUDIO_URL, LIVE_DEFAULT, LIVE_OPTIONS, LIVE_SERVICE, LIVE_NAME, LIVE_ESERVICE + + +class Live(Screen): + sessionid = str(uuid4()) + plutosessionid = str(uuid4()) + + def __init__(self, session, postdata): + self.postdata = postdata + Screen.__init__(self, session) + self.skinName = 'MediathekCockpit' + self.title = PLUGIN + ' - ' + _('Live') + + self['key_red'] = StaticText() + self['key_green'] = StaticText(_('Channels')) + self['key_yellow'] = StaticText(_('Movies')) + self['key_blue'] = StaticText(_('Search')) + + self['description'] = Label('') + self['date'] = Label('') + self['sresult'] = Label('') + + self['list'] = List() + + self.changed = False + + self['actions'] = ActionMap( + ['MTC_Actions'], + { + 'ok': self.pressOk, + 'cancel': self.pressClose, + # 'red': self.pressRed, + 'green': self.pressGreen, + 'yellow': self.pressYellow, + 'blue': self.pressBlue, + 'menu': self.pressMenu, + # 'info': self.pressInfo + } + ) + self.download = MyDeferredSemaphore(tokens=1) + self['list'].onSelectionChanged.append(self.__SelectionChanged) + self.onLayoutFinish.append(self.__onLayoutFinish) + + def __onLayoutFinish(self): + logger.info("...") + self.loadLiveChannels() + + def __SelectionChanged(self): + logger.info("...") + self['description'].setText('') + self['date'].setText('') + + self.curr = self['list'].getCurrent() + if self.curr: + txt = ('master_url\n{0}').format(self.curr[LIVE_MASTER_URL]) + if self.curr[LIVE_INDEX_URL]: + txt += ('\n\nindex_url\n{0}').format(self.curr[LIVE_INDEX_URL]) + if self.curr[LIVE_AUDIO_URL]: + txt += ('\n\naudio_url\n{0}').format(self.curr[LIVE_AUDIO_URL]) + dtxt = ('{0} ({1})\n{2} ({3})').format(_('Default'), self.curr[LIVE_DEFAULT], _('options'), (', ').join(self.curr[LIVE_OPTIONS])) + self['date'].setText(dtxt) + self['description'].setText(txt) + + def loadLiveChannels(self): + logger.info("...") + self['list'].style = 'default' + self.list = readLiveChannels() + self['list'].setList(self.list) + + def playlive(self, url, suburi=None): + logger.info("...") + mservice = str(self.curr[LIVE_SERVICE]) + if mservice and mservice.count(':') == 10: + sref = eServiceReference(mservice) + sref.setPath(url.encode('utf-8')) + else: + sref = eServiceReference(eServiceReference.idGST, 256, url.encode('utf-8')) + sref.setName(self.curr[LIVE_NAME].encode('utf-8')) + if suburi: + sref.setSuburi(suburi.encode('utf-8')) + currindex = self["list"].getIndex() + if self.curr[LIVE_DEFAULT] == 'verifyandupdate': + if 'playindex' in self.curr[LIVE_OPTIONS]: + default = 'playindex' + elif 'playmaster' in self.curr[LIVE_OPTIONS]: + default = 'playmaster' + else: + default = 'verify' + self.curr[LIVE_ESERVICE] = sref + self.curr[LIVE_INDEX_URL] = url + self.curr[LIVE_AUDIO_URL] = suburi or '' + self.curr[LIVE_DEFAULT] = default + self["list"].modifyEntry(currindex, self.curr) + self.changed = True + self.__SelectionChanged() + elif 'cached' in self.curr[LIVE_OPTIONS]: + self.curr[LIVE_ESERVICE] = sref + self["list"].modifyEntry(currindex, self.curr) + self.session.open(StreamPlayer, service=sref) + + def downloadFailed(self, failure, *args): + logger.info("...") + error_message = str(failure.getErrorMessage()) + if not error_message: + error_message = str(failure) + logger.error("%s, %s", error_message, str(args)) + if 'CancelledError' not in error_message: + self.session.open(MessageBox, error_message, MessageBox.TYPE_INFO, timeout=10, title=_('Download failed')) + + def pressOk(self): + logger.info("...") + if self.curr and self.curr[LIVE_MASTER_URL]: + if 'dash' in self.curr[LIVE_OPTIONS]: + mservice = str(self.curr[LIVE_SERVICE]) + sref = eServiceReference(mservice) + sref.setPath(str(self.curr[LIVE_MASTER_URL])) + sref.setName('%s' % self.curr[0].encode('utf-8')) + self.session.open(StreamPlayer, sref) + elif 'm3u8' in self.curr[LIVE_OPTIONS]: + if self.curr[LIVE_DEFAULT] in ('verify', 'verifyandupdate', 'cached'): + if 'cached' in self.curr[LIVE_OPTIONS] and isinstance(self.curr[LIVE_ESERVICE], eServiceReference): + self.session.open(StreamPlayer, service=self.curr[LIVE_ESERVICE]) + else: + urlval = self.curr[LIVE_MASTER_URL].encode('utf-8') + if 'pluto' in self.curr[LIVE_OPTIONS] and 'deviceId' not in self.curr[LIVE_MASTER_URL]: + urlval = ('{0}&sid={1}&deviceId={2}').format(self.curr[LIVE_MASTER_URL], self.plutosessionid, self.sessionid) + self.download.start(MyGetPage, url=urlval, headers=_headers, location=True).addCallback(self.m3u8checkback, self.playlive).addErrback(self.downloadFailed) + elif self.curr[LIVE_DEFAULT] in ('playindex', 'playmaster', 'cached') and self.curr[LIVE_MASTER_URL]: + if 'cached' in self.curr[LIVE_OPTIONS] and isinstance(self.curr[LIVE_ESERVICE], eServiceReference): + self.session.open(StreamPlayer, service=self.curr[LIVE_ESERVICE]) + elif self.curr[LIVE_DEFAULT] == 'playindex' and not self.curr[LIVE_INDEX_URL] and self.curr[LIVE_MASTER_URL]: + currindex = self['list'].getIndex() + self.curr[LIVE_DEFAULT] = 'verify' + urlval = self.curr[LIVE_MASTER_URL].encode('utf-8') + self['list'].modifyEntry(currindex, self.curr) + self.changed = True + self.__SelectionChanged() + self.download.start(MyGetPage, url=urlval, headers=_headers, location=True).addCallback(self.m3u8checkback, self.playlive).addErrback(self.downloadFailed) + elif self.curr[LIVE_DEFAULT] == 'playmaster' and self.curr[LIVE_MASTER_URL]: + urlval = self.curr[LIVE_MASTER_URL].encode('utf-8') + self.playlive(urlval) + + def m3u8checkback(self, result, play): + logger.info("...") + m3u8 = result[0] + url = result[1] + if '#EXTM3U' in m3u8: + m3u8res = M3U8Parser(m3u8, url) + if m3u8res.extxmedia_play(): + play(url) + elif m3u8res.extxmedia_parse(): + urlval, suburi = m3u8res.parser_all() + if urlval: + play(urlval, suburi) + + def pressRed(self): + pass + + def pressGreen(self): + self.close("channels") + + def pressYellow(self): + self.close("movies") + + def pressBlue(self): + self.close("search") + + def pressMenu(self): + Menu(self.session, self.postdata) + + def pressInfo(self): + pass + + def pressClose(self): + logger.info("...") + if self.changed: + writeLiveChannels(self['list'].list) + self.close("exit") diff --git a/src/LiveChannelUtils.py b/src/LiveChannelUtils.py deleted file mode 100644 index 6596bda..0000000 --- a/src/LiveChannelUtils.py +++ /dev/null @@ -1,88 +0,0 @@ -import os -import json -from enigma import eServiceReference -from .Debug import logger -from .__init__ import _ -from .LoadPixmap import Load_My_Pixmap -from .Constants import plugindir, liveindex, liveempty - - -livechannelsfile = plugindir + 'livechannels.json' - - -def read_livechannels(): - logger.info("...") - livechannels = [] - if os.path.exists(livechannelsfile): - with open(livechannelsfile) as (data_file): - data = json.load(data_file) - for value in data: - tmp = liveempty[:] - tmp[liveindex['for_lcd']] = _('Live channels') - if 'name' in value: - tmp[liveindex['name']] = value['name'].encode('utf-8') - if 'logo_name' in value: - tmp[liveindex['logo_name']] = value['logo_name'] - tmp[liveindex['channelpixmap']] = Load_My_Pixmap('%slogos/%s.png' % (plugindir, value['logo_name'].upper().encode('utf-8'))) - if 'master_url' in value: - tmp[liveindex['master_url']] = value['master_url'].encode('utf-8') - if 'index_url' in value: - tmp[liveindex['index_url']] = value['index_url'].encode('utf-8') - if 'audio_url' in value: - tmp[liveindex['audio_url']] = value['audio_url'].encode('utf-8') - if 'service' in value: - tmp[liveindex['service']] = value['service'].encode('utf-8') - if 'options' in value: - tmp[liveindex['options']] = value['options'] - if 'cached' in value['options']: - ref = convert_service(value) - if ref: - tmp[liveindex['eservice']] = ref - if 'default' in value: - tmp[liveindex['default']] = value['default'] - livechannels.append(tmp) - return livechannels - - -def write_livechannels(livechannels): - logger.info("...") - with open(livechannelsfile, 'w') as (fp): - result = [] - for value in livechannels: - tmp = {} - tmp['logo_name'] = value[liveindex['logo_name']] - tmp['name'] = value[liveindex['name']] - tmp['service'] = value[liveindex['service']] - tmp['index_url'] = value[liveindex['index_url']] - tmp['default'] = value[liveindex['default']] - tmp['master_url'] = value[liveindex['master_url']] - tmp['audio_url'] = value[liveindex['audio_url']] - tmp['options'] = value[liveindex['options']] - tmp['name'] = value[liveindex['name']] - tmp['name'] = value[liveindex['name']] - tmp['name'] = value[liveindex['name']] - result.append(tmp) - - json.dump(result, fp, encoding='utf-8', indent=2, sort_keys=False) - - -def convert_service(value): - logger.info("...") - if ('cached' in value['options'] and value['master_url'] or value['index_url']) and 'service' in value: - if 'playmaster' in value['options'] and not value['index_url']: - murl = value['master_url'].encode('utf-8') - else: - if value['index_url']: - murl = value['index_url'].encode('utf-8') - else: - return None - if value['service'] and value['service'].count(':') == 10: - sref = eServiceReference(str(value['service'])) - sref.setPath(murl) - else: - sref = eServiceReference(eServiceReference.idGST, 256, murl) - sref.setName(value['name'].encode('utf-8')) - if 'audio_url' in value and value['audio_url']: - sref.setSuburi(value['audio_url'].encode('utf-8')) - return sref - return None diff --git a/src/LiveUtils.py b/src/LiveUtils.py new file mode 100644 index 0000000..4c03409 --- /dev/null +++ b/src/LiveUtils.py @@ -0,0 +1,109 @@ +#!/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 enigma import eServiceReference +from .Debug import logger +from .__init__ import _ +from .LoadPixmap import loadPixmap +from .Constants import plugindir, liveempty, LIVE_ESERVICE, LIVE_FOR_LCD, LIVE_NAME, LIVE_LOGO_NAME, LIVE_CHANNELPIXMAP, LIVE_MASTER_URL, LIVE_INDEX_URL, LIVE_AUDIO_URL, LIVE_SERVICE, LIVE_OPTIONS, LIVE_DEFAULT + + +livechannelsfile = plugindir + 'livechannels.json' + + +def readLiveChannels(): + logger.info("...") + livechannels = [] + if os.path.exists(livechannelsfile): + with open(livechannelsfile) as (data_file): + data = json.load(data_file) + for value in data: + tmp = liveempty[:] + tmp[LIVE_FOR_LCD] = _('Live channels') + if 'name' in value: + tmp[LIVE_NAME] = value['name'].encode('utf-8') + if 'logo_name' in value: + tmp[LIVE_LOGO_NAME] = value['logo_name'] + tmp[LIVE_CHANNELPIXMAP] = loadPixmap('%slogos/%s.png' % (plugindir, value['logo_name'].upper().encode('utf-8'))) + if 'master_url' in value: + tmp[LIVE_MASTER_URL] = value['master_url'].encode('utf-8') + if 'index_url' in value: + tmp[LIVE_INDEX_URL] = value['index_url'].encode('utf-8') + if 'audio_url' in value: + tmp[LIVE_AUDIO_URL] = value['audio_url'].encode('utf-8') + if 'service' in value: + tmp[LIVE_SERVICE] = value['service'].encode('utf-8') + if 'options' in value: + tmp[LIVE_OPTIONS] = value['options'] + if 'cached' in value['options']: + ref = convertService(value) + if ref: + tmp[LIVE_ESERVICE] = ref + if 'default' in value: + tmp[LIVE_DEFAULT] = value['default'] + livechannels.append(tmp) + return livechannels + + +def writeLiveChannels(livechannels): + logger.info("...") + with open(livechannelsfile, 'w') as (fp): + result = [] + for value in livechannels: + tmp = {} + tmp['logo_name'] = value[LIVE_LOGO_NAME] + tmp['name'] = value[LIVE_NAME] + tmp['service'] = value[LIVE_SERVICE] + tmp['index_url'] = value[LIVE_INDEX_URL] + tmp['default'] = value[LIVE_DEFAULT] + tmp['master_url'] = value[LIVE_MASTER_URL] + tmp['audio_url'] = value[LIVE_AUDIO_URL] + tmp['options'] = value[LIVE_OPTIONS] + tmp['name'] = value[LIVE_NAME] + tmp['name'] = value[LIVE_NAME] + tmp['name'] = value[LIVE_NAME] + result.append(tmp) + + json.dump(result, fp, encoding='utf-8', indent=2, sort_keys=False) + + +def convertService(value): + logger.info("...") + if ('cached' in value['options'] and value['master_url'] or value['index_url']) and 'service' in value: + if 'playmaster' in value['options'] and not value['index_url']: + murl = value['master_url'].encode('utf-8') + else: + if value['index_url']: + murl = value['index_url'].encode('utf-8') + else: + return None + if value['service'] and value['service'].count(':') == 10: + sref = eServiceReference(str(value['service'])) + sref.setPath(murl) + else: + sref = eServiceReference(eServiceReference.idGST, 256, murl) + sref.setName(value['name'].encode('utf-8')) + if 'audio_url' in value and value['audio_url']: + sref.setSuburi(value['audio_url'].encode('utf-8')) + return sref + return None diff --git a/src/LoadPixmap.py b/src/LoadPixmap.py index 9f100c9..587f978 100644 --- a/src/LoadPixmap.py +++ b/src/LoadPixmap.py @@ -1,3 +1,24 @@ +#!/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 Tools.LoadPixmap import LoadPixmap from .Debug import logger @@ -6,7 +27,7 @@ _pixmap_cache = {} -def Load_My_Pixmap(path): +def loadPixmap(path): logger.info("...") if path: svgpath = path[:-3] + 'svg' diff --git a/src/M3U8Parser.py b/src/M3U8Parser.py index 2ce4903..3ed2c60 100644 --- a/src/M3U8Parser.py +++ b/src/M3U8Parser.py @@ -1,16 +1,36 @@ +#!/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 io import BytesIO from .Debug import logger -m3u8parserlist = {} -m3u8parserlist['url'] = 0 -m3u8parserlist['audio_url'] = 1 -m3u8parserlist['audio_name'] = 2 -m3u8parserlist['sort1'] = 3 -m3u8parserlist['sort2'] = 4 -m3u8parserlist['listend'] = 5 -m3u8parserval = [''] * m3u8parserlist['listend'] +PARSER_URL = 0 +PARSER_AUDIO_URL = 1 +PARSER_AUDIO_NAME = 2 +PARSER_SORT1 = 3 +PARSER_SORT2 = 4 +PARSER_END = 5 +m3u8parserval = [''] * PARSER_END _codecs = re.compile('CODECS="(.+?)"', re.I | re.X) _resolution = re.compile('RESOLUTION=(.+?)[,|\\n]', re.I | re.X) _bandwidth = re.compile('BANDWIDTH=(.+?)[,|\\n]', re.I | re.X) @@ -23,7 +43,7 @@ _language = re.compile('LANGUAGE="(.+?)"', re.I | re.X) -class m3u8parser(object): +class M3U8Parser(object): def __init__(self, result=None, murl=None): logger.info("...") @@ -31,7 +51,7 @@ def __init__(self, result=None, murl=None): self.murl = murl self.vurl = None self.aurl = None - self.resdict = {'urlliste': [], 'audioliste': []} + self.resdict = {'url_list': [], 'audio_list': []} def findvaluesplit(self, pattern, line): logger.info("...") @@ -56,33 +76,33 @@ def parser_all(self, result=None, murl=None): self.result = result if murl: self.murl = murl - urlliste = m3u8parserval[:] + url_list = m3u8parserval[:] for line in BytesIO(self.result): if 'EXT-X-MEDIA:TYPE=AUDIO' in line and 'URI' in line: - self.resdict['audioliste'].append([self.findvalue(_groupid, line), self.urlfix(self.findvalue(_aurlval, line))]) + self.resdict['audio_list'].append([self.findvalue(_groupid, line), self.urlfix(self.findvalue(_aurlval, line))]) elif 'EXT-X-STREAM-INF' in line: - urlliste[m3u8parserlist['audio_name']] = self.findvalue(_audio, line) - urlliste[m3u8parserlist['sort1']] = int((self.findvalue(_resolution, line) or '0').replace('x', '')) - urlliste[m3u8parserlist['sort2']] = int(self.findvalue(_bandwidth, line) or '0') + url_list[PARSER_AUDIO_NAME] = self.findvalue(_audio, line) + url_list[PARSER_SORT1] = int((self.findvalue(_resolution, line) or '0').replace('x', '')) + url_list[PARSER_SORT2] = int(self.findvalue(_bandwidth, line) or '0') elif line[0] != '#' and '.' in line: - urlliste[m3u8parserlist['url']] = self.urlfix(line.strip()) - self.resdict['urlliste'].append(urlliste[:]) - urlliste = m3u8parserval[:] - - self.resdict['urlliste'].sort(key=lambda x: x[m3u8parserlist['sort1']] or x[m3u8parserlist['sort2']], reverse=True) - for x in self.resdict['urlliste']: - if x[m3u8parserlist['url']] and x[m3u8parserlist['url']].startswith('http'): - self.vurl = x[m3u8parserlist['url']] - if self.resdict['audioliste']: - for y in self.resdict['audioliste']: - if x[m3u8parserlist['audio_name']] == y[0]: + url_list[PARSER_URL] = self.urlfix(line.strip()) + self.resdict['url_list'].append(url_list[:]) + url_list = m3u8parserval[:] + + self.resdict['url_list'].sort(key=lambda x: x[PARSER_SORT1] or x[PARSER_SORT2], reverse=True) + for x in self.resdict['url_list']: + if x[PARSER_URL] and x[PARSER_URL].startswith('http'): + self.vurl = x[PARSER_URL] + if self.resdict['audio_list']: + for y in self.resdict['audio_list']: + if x[PARSER_AUDIO_NAME] == y[0]: self.aurl = y[1] if self.vurl and self.aurl and self.aurl.startswith('http'): - print('play', self.vurl, self.aurl) + logger.debug('vurl: %s, aurl: %s', self.vurl, self.aurl) return (self.vurl, self.aurl) else: - print('play', self.vurl, self.aurl) + logger.debug('vurl: %s, aurl: %s', self.vurl, self.aurl) return (self.vurl, self.aurl) return (self.vurl, self.aurl) @@ -102,35 +122,35 @@ def parser_all_ok(self, result=None, murl=None): _subtitles = re.compile('SUBTITLES="(.+?)"', re.I | re.X) _aurlval = re.compile('URI="(.+?)"', re.I | re.X) _nameval = re.compile('NAME="(.+?)"', re.I | re.X) - urlliste = [] + url_list = [] for line in BytesIO(self.result): if 'EXT-X-MEDIA:TYPE=AUDIO' in line: audig = self.findvalue(_groupid, line) - if audig and audig not in self.resdict['audioliste']: - self.resdict['audioliste'][audig] = [] + if audig and audig not in self.resdict['audio_list']: + self.resdict['audio_list'][audig] = [] if audig: aurlval = self.findvalue(_aurlval, line) if aurlval: nameval = self.findvalue(_nameval, line) - self.resdict['audioliste'][audig].append([self.urlfix(aurlval), nameval]) + self.resdict['audio_list'][audig].append([self.urlfix(aurlval), nameval]) elif 'EXT-X-STREAM-INF' in line: audi = self.findvalue(_audio, line) audina = '' audisp = None - if audi and audi in self.resdict['audioliste']: - for audispres, audinares in self.resdict['audioliste'][audi]: + if audi and audi in self.resdict['audio_list']: + for audispres, audinares in self.resdict['audio_list'][audi]: audisp = audispres audina = audinares break - urlliste = ['', audisp, self.findvaluesplit(_resolution, line) or '0', self.findvaluesplit(_bandwidth, line) or '0', audina] - elif line[0] != '#' and urlliste: - urlliste[0] = self.urlfix(line.strip()) - self.resdict['urlliste'].append(urlliste[:]) - urlliste = [] + url_list = ['', audisp, self.findvaluesplit(_resolution, line) or '0', self.findvaluesplit(_bandwidth, line) or '0', audina] + elif line[0] != '#' and url_list: + url_list[0] = self.urlfix(line.strip()) + self.resdict['url_list'].append(url_list[:]) + url_list = [] - self.resdict['urlliste'].sort(key=lambda x: int(x[3]) or int(x[2].replace('x', '')), reverse=True) - for x in self.resdict['urlliste']: + self.resdict['url_list'].sort(key=lambda x: int(x[3]) or int(x[2].replace('x', '')), reverse=True) + for x in self.resdict['url_list']: if x[0] and x[0].startswith('http'): self.vurl = x[0] self.aurl = x[1] @@ -159,36 +179,27 @@ def extxmedia_play(self, result=None): logger.info("...") if result: self.result = result - if '#EXT-X-MEDIA-SEQUENCE' in self.result and ('#EXT-X-MEDIA:TYPE' or '#EXT-X-STREAM-INF') not in self.result: - return True - return False + return '#EXT-X-MEDIA-SEQUENCE' in self.result and ('#EXT-X-MEDIA:TYPE' or '#EXT-X-STREAM-INF') not in self.result def extxmedia_parse(self, result=None): logger.info("...") if result: self.result = result - if '#EXT-X-STREAM-INF' in self.result and '#EXT-X-MEDIA-SEQUENCE' not in self.result: - return True - return False + return '#EXT-X-STREAM-INF' in self.result and '#EXT-X-MEDIA-SEQUENCE' not in self.result def extxmedia_hls(self, result=None): logger.info("...") if result: self.result = result - if '#EXT-X-MEDIA:TYPE=AUDIO' in self.result and '#EXT-X-STREAM-INF' in self.result and '#EXT-X-MEDIA-SEQUENCE' not in self.result: - return True - return False + return '#EXT-X-MEDIA:TYPE=AUDIO' in self.result and '#EXT-X-STREAM-INF' in self.result and '#EXT-X-MEDIA-SEQUENCE' not in self.result def extxmedia_chunk(self, result=None): logger.info("...") if result: self.result = result - if '#EXT-X-STREAM-INF' in self.result and 'chunk' in self.result and 'm3u8' in self.result and '#EXT-X-MEDIA-SEQUENCE' not in self.result: - return True - return False + return '#EXT-X-STREAM-INF' in self.result and 'chunk' in self.result and 'm3u8' in self.result and '#EXT-X-MEDIA-SEQUENCE' not in self.result def __del__(self): logger.info("...") - print('__del__ m3u8parser') self.resdict.clear() self.vurl = self.aurl = self.result = self.murl = None diff --git a/src/MediathekCockpit.py b/src/MediathekCockpit.py index 92eb2a4..f962521 100644 --- a/src/MediathekCockpit.py +++ b/src/MediathekCockpit.py @@ -1,1032 +1,70 @@ -import re -import json -from time import time -from uuid import uuid4 -from datetime import datetime, timedelta -from Screens.MessageBox import MessageBox -from Screens.Screen import Screen -from Screens.ChoiceBox import ChoiceBox -from Components.ActionMap import ActionMap -from Components.Label import Label -from Components.Sources.StaticText import StaticText -from Components.Sources.List import List -from enigma import eServiceReference -from Tools.Directories import pathExists, getRecordingFilename -from Plugins.SystemPlugins.Toolkit.NTIVirtualKeyBoard import NTIVirtualKeyBoard -try: - from Plugins.Extensions.MediaInfo.plugin import MediaInfo -except Exception: - MediaInfo = False -from MyJobManager import downloadManager, DownloadJob -from MoviePlayer import StreamPlayer, MoviePlayer -from .Downloader import MygetPage, _headers, headers_ts, headersplain -from .MyDeferredSemaphore import MyDeferredSemaphore -from .MediathekCockpitEventView import MediathekCockpitEventView -from .MediathekCockpitDownloadView import MediathekCockpitDownloadView -from .MediathekCockpitSetup import MediathekCockpitSetup -from .MediathekCockpitSearchEntry import MediathekCockpitSearchEntry -from .LoadPixmap import Load_My_Pixmap -from .SearchUtils import read_searchquerys, write_searchquerys -from .ConfigUtils import read_mvconfig, write_mvconfig -from .FavoriteUtils import read_favorites, write_favorites -from .LiveChannelUtils import read_livechannels, write_livechannels -from .M3U8Parser import m3u8parser -from .__init__ import _ +#!/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 .Constants import plugindir, listindex, listempty, liveindex, listfields, listsearchquerys, listchannel +from .Channels import Channels +from .Live import Live +from .Movies import Movies +from .Search import Search +from .Settings import Settings -class MediathekCockpitSummary(Screen): - - def __init__(self, session, parent): - logger.info("...") - Screen.__init__(self, session, parent=parent) - self.skinName = ['MediathekCockpitSummary'] - self.skinName.append('SimpleSummary') - - -class MediathekCockpit(Screen): - sessionid = str(uuid4()) - plutosessionid = str(uuid4()) - +class MediathekCockpit(Search): def __init__(self, session, query=""): - logger.info("...") - self.query = query - Screen.__init__(self, session) + logger.info("query: %s", query) self.session = session - self.skinName = 'MediathekCockpit' - self['actions'] = ActionMap( - ['MVD_Actions'], - { - 'ok': self.key_ok, - 'cancel': self.close, - 'red': self.key_red, - 'green': self.key_green, - 'yellow': self.key_yellow, - 'blue': self.key_blue, - 'next': self.livestreammoveDown, - 'back': self.livestreammoveUp, - 'menu': self.showMenu, - 'info': self.key_info - } - ) - self.changed = {'config': False, 'favo': False, 'querys': False, 'live': False} - self.tmplist = {'favodict': {}} - self.mvconfig = read_mvconfig() - self['key_red'] = StaticText(_('Channel selection')) - self['key_green'] = StaticText(_('All movies')) - self['key_yellow'] = StaticText(_('Search')) - self['key_blue'] = StaticText(_('Favorites')) - self['description'] = Label('') - self['date'] = Label('') - self['sresult'] = Label('') - self['message'] = Label() - self['message'].hide() - self['liste'] = List([]) - self['summaryliste'] = List([]) - self['liste'].onSelectionChanged.append(self.__SelectionChanged) - self.onClose.append(self.__onClose) - self.onFirstExecBegin.append(self.__onFirstExecBegin) - self.currindex = 0 - self.channelscurrindex = 0 - self.searchentriesindex = 0 - self.titeltext = _('MediathekCockpit') - self.lastservice = self.session.nav.getCurrentlyPlayingServiceReference() - self.download = MyDeferredSemaphore(tokens=1) - - def __onFirstExecBegin(self): - logger.info("...") - self.key_yellow_text() - summaryempty = [''] * listindex['id'] - summaryempty[listindex['channel']] = self.getTitle() - summaryempty[listindex['topic']] = self.getTitle() - summaryempty[listindex['channelpixmap']] = Load_My_Pixmap(('{0}plugin.png').format(plugindir)) - self['summaryliste'].setList(summaryempty) - if self.query: - self.manualsearch(self.query) - - def key_ok(self): - - def playm3u8(url, suburi=None): - logger.info("...") - sref = eServiceReference(eServiceReference.idGST, 0, url.encode('utf-8')) - if curr[listindex['channel']].upper() not in self.name.upper(): - sref.setName('%s: %s' % (curr[listindex['channel']].encode('utf-8'), self.name.encode('utf-8'))) - else: - sref.setName('%s' % self.name.encode('utf-8')) - if suburi: - sref.setSuburi(suburi.encode('utf-8')) - if MediaInfo: - menuval = (MediaInfo,) - else: - menuval = None - self.session.open(MoviePlayer, sref, menuval=menuval, infoval=(MediathekCockpitEventView, curr), myconfig=self.mvconfig) - - def playlive(url, suburi=None): - logger.info("...") - mservice = str(curr[liveindex['service']]) - if mservice and mservice.count(':') == 10: - sref = eServiceReference(mservice) - sref.setPath(url.encode('utf-8')) - else: - sref = eServiceReference(eServiceReference.idGST, 256, url.encode('utf-8')) - sref.setName(curr[liveindex['name']].encode('utf-8')) - if suburi: - sref.setSuburi(suburi.encode('utf-8')) - currindex = self['liste'].getIndex() - if curr[liveindex['default']] == 'verifyandupdate': - if 'playindex' in curr[liveindex['options']]: - default = 'playindex' - elif 'playmaster' in curr[liveindex['options']]: - default = 'playmaster' - else: - default = 'verify' - curr[liveindex['eservice']] = sref - curr[liveindex['index_url']] = url - curr[liveindex['audio_url']] = suburi or '' - curr[liveindex['default']] = default - self['liste'].modifyEntry(currindex, curr) - self.mvconfig['livechannels'][currindex][liveindex['index_url']] = url - self.mvconfig['livechannels'][currindex][liveindex['audio_url']] = suburi or '' - self.mvconfig['livechannels'][currindex][liveindex['default']] = default - self.changed['live'] = True - self.__SelectionChanged() - elif 'cached' in curr[liveindex['options']]: - curr[liveindex['eservice']] = sref - self['liste'].modifyEntry(currindex, curr) - self.session.open(StreamPlayer, service=sref) - - def m3u8checkback(result, play): - logger.info("...") - self['message'].hide() - m3u8 = result[0] - url = result[1] - if '#EXTM3U' in m3u8: - m3u8res = m3u8parser(m3u8, url) - if m3u8res.extxmedia_play(): - play(url) - elif m3u8res.extxmedia_parse(): - urlval, suburi = m3u8res.parser_all() - if urlval: - play(urlval, suburi) - - def ChoiceBoxCallback(answer): - logger.info("...") - if answer and answer[1]: - self.url = answer[1].encode('utf-8') - if curr[listindex['topic']].replace('&', 'und').upper() not in curr[listindex['title']].replace('&', 'und').upper(): - self.name = curr[listindex['topic']] + ' ' + curr[listindex['title']] - else: - self.name = curr[listindex['title']] - - if '.m3u8' in self.url: - self['message'].text = _('Download started...') - self['message'].show() - self.download.start(MygetPage, url=self.url, headers=_headers, location=True).addCallback(m3u8checkback, playm3u8).addErrback(self.http_failed) - elif self.url.endswith(('mp4', 'flv')): - playm3u8(self.url) - - def checkvideourl(was): - logger.info("...") - if was in listindex and curr[listindex[was]] and curr[listindex[was]].startswith('http'): - return True - return False - - def getquali(was): - logger.info("...") - restext = '' - pos = curr[listindex[was]].rfind('.') - if pos != -1: - restext = curr[listindex[was]][pos + 1:].encode('utf-8') + ' / ' - return restext - - logger.info("...") - curr = self['liste'].getCurrent() - if curr and len(curr) == listindex['listend']: - if curr and curr and curr[listindex['channel']] == '>>>': - self.currindex = self['liste'].index - self.mvconfig['postdata']['offset'] += self.mvconfig.get('size', 500) - self['liste'].list.remove(curr) - self.download_page() - elif self['liste'].style == 'movi_liste': - val = self.mvconfig.get('playmovieselect', 'url_video_hd') - if val == 'playmovieselect': - options = [] - if checkvideourl('url_video_low'): - options.append((getquali('url_video_low') + _('Low'), curr[listindex['url_video_low']])) - if checkvideourl('url_video'): - options.append((getquali('url_video') + _('Medium'), curr[listindex['url_video']])) - if checkvideourl('url_video_hd'): - options.append((getquali('url_video_hd') + _('Maximum'), curr[listindex['url_video_hd']])) - if options: - self.session.openWithCallback(ChoiceBoxCallback, ChoiceBox, title=_('Video') + ' ' + _('Resolution'), list=options, selection=len(options), titlebartext=_('Option Selector')) - elif val in listindex: - if checkvideourl(val): - ChoiceBoxCallback((val, curr[listindex[val]])) - elif checkvideourl('url_video_hd'): - ChoiceBoxCallback(('url_video_hd', curr[listindex['url_video_hd']])) - elif checkvideourl('url_video'): - ChoiceBoxCallback(('url_video', curr[listindex['url_video']])) - elif checkvideourl('url_video_low'): - ChoiceBoxCallback(('url_video_low', curr[listindex['url_video_low']])) - elif curr and len(curr) == listchannel['listend'] and curr[listchannel['channel']]: - self.mvconfig['postdata']['queries'] = [] - self.mvconfig['postdata']['queries'].append({'fields': ['channel'], 'query': curr[listchannel['channel']].encode('utf-8')}) - self.channelscurrindex = self['liste'].index - self['liste'].setList([]) - self['sresult'].setText('') - self.mvconfig['postdata']['offset'] = 0 - self.download_page() - elif curr and len(curr) == listsearchquerys['listend'] and curr[listsearchquerys['queries']]: - self.searchentriesindex = self['liste'].index - self.mvconfig['postdata']['queries'] = curr[listsearchquerys['queries']] - self['liste'].setList([]) - self['sresult'].setText('') - self.currindex = 0 - self.mvconfig['postdata']['offset'] = 0 - self.download_page() - elif curr and len(curr) == liveindex['listend'] and curr[liveindex['master_url']]: - if 'dash' in curr[liveindex['options']]: - mservice = str(curr[liveindex['service']]) - sref = eServiceReference(mservice) - sref.setPath(str(curr[liveindex['master_url']])) - sref.setName('%s' % curr[0].encode('utf-8')) - self.session.open(StreamPlayer, sref) - elif 'm3u8' in curr[liveindex['options']]: - if curr[liveindex['default']] in ('verify', 'verifyandupdate', 'cached'): - if 'cached' in curr[liveindex['options']] and isinstance(curr[liveindex['eservice']], eServiceReference): - self.session.open(StreamPlayer, service=curr[liveindex['eservice']]) - else: - urlval = curr[liveindex['master_url']].encode('utf-8') - if 'pluto' in curr[liveindex['options']] and 'deviceId' not in curr[liveindex['master_url']]: - urlval = ('{0}&sid={1}&deviceId={2}').format(curr[liveindex['master_url']], self.plutosessionid, self.sessionid) - self['message'].text = _('Download started...') - self['message'].show() - self.download.start(MygetPage, url=urlval, headers=_headers, location=True).addCallback(m3u8checkback, playlive).addErrback(self.http_failed) - elif curr[liveindex['default']] in ('playindex', 'playmaster', 'cached') and curr[liveindex['master_url']]: - if 'cached' in curr[liveindex['options']] and isinstance(curr[liveindex['eservice']], eServiceReference): - self.session.open(StreamPlayer, service=curr[liveindex['eservice']]) - elif curr[liveindex['default']] == 'playindex' and not curr[liveindex['index_url']] and curr[liveindex['master_url']]: - currindex = self['liste'].getIndex() - curr[liveindex['default']] = 'verify' - self.mvconfig['livechannels'][currindex][liveindex['default']] = 'verify' - urlval = curr[liveindex['master_url']].encode('utf-8') - self.changed['live'] = True - self['liste'].modifyEntry(currindex, curr) - self.__SelectionChanged() - self.download.start(MygetPage, url=urlval, headers=_headers, location=True).addCallback(m3u8checkback, playlive).addErrback(self.http_failed) - elif curr[liveindex['default']] == 'playmaster' and curr[liveindex['master_url']]: - urlval = curr[liveindex['master_url']].encode('utf-8') - playlive(urlval) - - def key_red(self): - logger.info("...") - self.setTitle(self.titeltext + ' ' + self['key_red'].text) - self['liste'].style = 'default' - self.currindex = 0 - if self.mvconfig['channelslist']: - self['liste'].setList(self.mvconfig['channelslist'][:]) - self['liste'].index = self.channelscurrindex - self.set_sresult_entries() - else: - self['liste'].setList([]) - self['message'].text = _('Channel selection') + '...' - self['message'].show() - url = 'https://mediathekviewweb.de/api/channels' - self.download.start(MygetPage, url=url, headers=headersplain).addCallback(self.result_back_channels).addErrback(self.http_failed) - - def key_green(self): - logger.info("...") - self.setTitle(self.titeltext + ' ' + self['key_green'].text) - self['sresult'].setText('') - self['liste'].setList([]) - self['liste'].style = 'movi_liste' - self.currindex = 0 - if 'queries' in self.mvconfig['postdata']: - del self.mvconfig['postdata']['queries'] - self.mvconfig['postdata']['offset'] = 0 - self.download_page() - - def key_blue(self): - logger.info("...") - self.setTitle(self.titeltext + ' ' + self['key_blue'].text + ' ' + _('Movies')) - if not self.mvconfig['favorites']: - self.mvconfig['favorites'], self.tmplist, changed = read_favorites(self.tmplist) - if changed: - self.changed['favo'] = True - if self.mvconfig['favorites']: - self['liste'].style = 'movi_liste' - self['liste'].setList(self.mvconfig['favorites'][:]) - self.set_sresult_entries() - else: - self.session.open(MessageBox, _('No favorites available'), MessageBox.TYPE_INFO, timeout=3) - - def searchentries(self, res=False): - logger.info("...") - if res: - self.setTitle(self.titeltext + ' ' + _('Search list')) - self['liste'].style = 'search_querys' - self['liste'].setList(self.mvconfig['searchquerys'][:]) - self.currindex = 0 - self['liste'].index = self.searchentriesindex - self.set_sresult_entries() - - def searchallentries(self, res=False): - logger.info("...") - if res: - if self.mvconfig['searchquerys']: - self['liste'].style = 'movi_liste' - self['liste'].setList([]) - self['sresult'].setText('') - self.currindex = 0 - self.mvconfig['postdata']['offset'] = 0 - self.mvconfig['postdata']['queries'] = list() - _have = {} - for searchquerys in self.mvconfig['searchquerys']: - for x in searchquerys[listsearchquerys['queries']]: - if x.get('fields') != listfields['channel']: - if x['query'] not in _have: - _have[x['query']] = True - self.mvconfig['postdata']['queries'].append({'fields': self.mvconfig['searchquerysfields'], 'query': x['query'].encode('utf-8')}) - - self.download_page() - else: - self.session.open(MessageBox, _('No search list available'), MessageBox.TYPE_INFO, timeout=3) - - def searchfor(self, name='', fields=None): - if fields is None: - fields = ['topic', 'title'] - logger.info("name: %s, fields: %s", name, fields) - if name: - self['liste'].setList([]) - self['sresult'].setText('') - self['liste'].style = 'movi_liste' - self.currindex = 0 - self.mvconfig['postdata']['offset'] = 0 - self.mvconfig['postdata']['queries'] = list() - self.mvconfig['postdata']['queries'].append({'fields': fields, 'query': name.encode('utf-8')}) - self.download_page() - - def addsearchentries(self, querys=None): - if querys is None: - querys = {} - logger.info("...") - curr = self['liste'].getCurrent() - if not querys and curr and len(curr) >= listindex['url_video_hd'] and curr[listindex['channel']] != '>>>': - querys = {} - querys['queries'] = [] - querys['queries'].append({'fields': ['topic'], 'query': curr[listindex['topic']].encode('utf-8')}) - querys['queries'].append({'fields': ['channel'], 'query': curr[listindex['channel']]}) - elif not querys: - querys = {} - querys['queries'] = [] - querys['queries'].append({'fields': ['topic'], 'query': 'text'}) - self.session.openWithCallback(self.searchEntryCallback, MediathekCockpitSearchEntry, self.mvconfig, currquery=querys) - - def searchEntryCallback(self, res): - logger.info("res: %s", res) - if res: - self.changed['querys'] = True - self.mvconfig = res - - def searchentriesremove(self): - logger.info("...") - curr = self['liste'].getCurrent() - if curr: - - def del_curr(answer=None): - logger.info("...") - if answer: - self.searchentriesindex = self['liste'].index - del self.mvconfig['searchquerys'][self.searchentriesindex] - self.searchentries(True) - self.changed['querys'] = True + Search.__init__(self, session, self.keyboardCallback) + self.last_service = self.session.nav.getCurrentlyPlayingServiceReference() - text = '%s\n%s\n\n%s' % (curr[0], curr[1], _('Delete')) - self.session.openWithCallback(del_curr, MessageBox, text) + self.postdata = {} + self.postdata = {'sortOrder': 'desc', 'sortBy': 'timestamp'} + self.postdata['size'] = config.plugins.mediathekcockpit.size.value + self.postdata['offset'] = 0 + self.postdata['future'] = config.plugins.mediathekcockpit.future.value - def manualsearch(self, query=""): - logger.info("...") - text = query if query else "" - curr = self['liste'].getCurrent() - if curr and len(curr) == listindex['listend'] and curr[listindex['channel']] != '>>>': - if curr[listindex['topic']]: - text = curr[listindex['topic']] - self.session.openWithCallback(self.searchfor, NTIVirtualKeyBoard, title=_('Enter search text'), text=text) - - def key_yellow_text(self): - logger.info("...") - if self.mvconfig['searchstart'] == 'easyselection': - text = _('Easy selection') - elif self.mvconfig['searchstart'] == 'searchentries': - text = _('Search list') - elif self.mvconfig['searchstart'] == 'searchallentries': - text = _('All') - elif self.mvconfig['searchstart'] == 'manualsearch': - text = _('Manual search') - elif self.mvconfig['searchstart'] == 'livechannels': - text = _('Live channels') + if query: + self.openKeyboard(query, self.postdata) else: - text = _('Search') - self['key_yellow'].text = text - self['sresult'].setText('') - - def key_yellow(self): - logger.info("...") - curr = self['liste'].getCurrent() - if not self.mvconfig['searchquerys']: - self.mvconfig['searchquerys'] = read_searchquerys() - - def ChoiceBoxCallback(answer): - logger.info("...") - answer = answer and answer[1] - if answer == 'searchentries': - self.searchentries(True) - elif answer == 'searchallentries': - self.searchallentries(True) - elif answer == 'searchfor': - self.searchfor(curr[listindex['topic']]) - elif answer == 'searchfortitle': - self.searchfor(curr[listindex['title']], ['title']) - elif answer == 'addsearchentries': - self.addsearchentries() - elif answer == 'manualsearch': - self.manualsearch() - elif answer == 'livechannels': - self.load_livechannels() - elif answer == 'searchentriesedit': - self.searchentriesindex = self['liste'].index - self.session.openWithCallback(self.searchentries, MediathekCockpitSearchEntry, currquery={'queries': curr[listsearchquerys['queries']], 'queryindex': self['liste'].index}) - elif answer == 'searchentriesremove': - self.searchentriesremove() - elif answer == 'moveUp': - self.moveUp() - elif answer == 'moveDown': - self.moveDown() - - if self.mvconfig['searchstart'] == 'easyselection': - options = [] - # havesearchquerys = False - if len(self.mvconfig['searchquerys']) > 0: - options.append((_('Search list'), 'searchentries')) - options.append((_('Search for all entries in the search list'), 'searchallentries')) - if curr and len(curr) == listsearchquerys['listend'] and curr[listsearchquerys['queries']] and self['liste'].style == 'search_querys': - # title = _('Name') + ': ' + curr[0] + '\n' + _('fields') + ': ' + curr[1] + '\n' + _('Channel') + ': ' + curr[2] - options.append((_('Search list') + ' ' + _('Edit selected entry'), 'searchentriesedit')) - options.append((_('Search list') + ' ' + _('Remove entry'), 'searchentriesremove')) - options.append((_('Search list') + ' ' + _('Add entry'), 'addsearchentries')) - if curr and len(curr) == listindex['listend'] and curr[listindex['channel']] != '>>>': - if curr[listindex['topic']]: - options.append(('--', '--')) - options.append((_("Search for '%s'") % curr[listindex['topic']], 'searchfor')) - if curr[listindex['title']]: - options.append((_("Search for '%s'") % curr[listindex['title']], 'searchfortitle')) - options.append(('--', '--')) - options.append((_('Manual Search'), 'manualsearch')) - options.append((_('Live channels'), 'livechannels')) - if options: - self.session.openWithCallback(ChoiceBoxCallback, ChoiceBox, title=_('Easy selection'), list=options, titlebartext='MediathekCockpit') + self.showScreen(Channels, self.postdata) + + def showScreen(self, screen, *args): + logger.info("screen: %s", screen) + self.session.openWithCallback(self.showScreenCallback, screen, *args) + + def showScreenCallback(self, return_screen): + logger.info("return_screen: %s", return_screen) + if return_screen == "channels": + self.showScreen(Channels, self.postdata) + elif return_screen == "streams": + self.showScreen(Live, self.postdata) + elif return_screen == "movies": + self.showScreen(Movies, self.postdata) + elif return_screen == "search": + self.openKeyboard("", self.postdata) + elif return_screen == "settings": + self.showScreen(Settings, self.postdata) else: - ChoiceBoxCallback((self.mvconfig['searchstart'], self.mvconfig['searchstart'])) - - def showMenu(self): - logger.info("...") - curr = self['liste'].getCurrent() - options = [] - title = _('Select') - titlebartext = 'MediathekCockpit' - if not self.mvconfig['favorites']: - self.mvconfig['favorites'], self.tmplist, changed = read_favorites(self.tmplist) - if changed: - self.changed['favo'] = True - if not self.mvconfig['searchquerys']: - self.mvconfig['searchquerys'] = read_searchquerys() - - def ChoiceBoxCallback(answer): - logger.info("...") - answer = answer and answer[1] - if answer == 'setupview': - - def setupback(res=None): - logger.info("...") - if res: - self.mvconfig = res - self.changed['config'] = True - self['liste'].setList([]) - self.currindex = 0 - self.mvconfig['postdata']['offset'] = 0 - self.key_yellow_text() - - self.session.openWithCallback(setupback, MediathekCockpitSetup, self.mvconfig) - elif answer == 'searchentries': - self.searchentries(True) - elif answer == 'searchallentries': - self.searchallentries(True) - elif answer == 'searchentriesedit': - self.searchentriesindex = self['liste'].index - self.session.openWithCallback(self.searchentries, MediathekCockpitSearchEntry, currquery={'queries': curr[3], 'queryindex': self['liste'].index}) - elif answer == 'searchentriesremove': - self.searchentriesremove() - elif answer == 'searchfor': - self.searchfor(curr[listindex['topic']]) - elif answer == 'searchfortitle': - self.searchfor(curr[listindex['title']], ['title']) - elif answer == 'addsearchentries': - self.addsearchentries() - elif answer == 'manualsearch': - self.manualsearch() - elif answer == 'moveUp': - self.moveUp() - elif answer == 'moveDown': - self.moveDown() - elif answer == 'livestreammoveUp': - self.livestreammoveUp() - elif answer == 'livestreammoveDown': - self.livestreammoveDown() - elif answer == 'addtofavorites': - if curr[listindex['id']] not in self.tmplist['favodict']: - self.mvconfig['favorites'].insert(0, curr) - self.tmplist['favodict'][curr[listindex['id']]] = True - self.changed['favo'] = True - tmpname = '' - tmpname += curr[listindex['channel']] - tmpname += '\n' + curr[listindex['topic']] - tmpname += '\n' + curr[listindex['title']] - self.session.open(MessageBox, _("Added '%s'") % tmpname, type=MessageBox.TYPE_INFO, timeout=3) - else: - self.session.open(MessageBox, _('Entry already exists'), type=MessageBox.TYPE_INFO, timeout=3) - elif answer == 'delfavorites': - - def del_curr(answer=None): - logger.info("...") - if answer: - self.mvconfig['favorites'].pop(self['liste'].getIndex()) - self['liste'].updateList(self.mvconfig['favorites'][:]) - self.set_sresult_entries() - self.__SelectionChanged() - self.changed['favo'] = True - if curr[listindex['id']] in self.tmplist['favodict']: - del self.tmplist['favodict'][curr[listindex['id']]] - - text = '%s\n%s\n\n%s' % (curr[0], curr[1], _('Delete')) - self.session.openWithCallback(del_curr, MessageBox, text) - elif answer in ('moviesave', 'movierecord'): - - def moviesavecallback(answerres): - logger.info("...") - answerres = answerres and answerres[1] - if answerres: - - def SaveStreamToDisk(path): - logger.info("...") - if path and pathExists(path): - if curr[listindex['topic']].replace('&', 'und').upper() not in curr[listindex['title']].replace('&', 'und').upper(): - name = curr[listindex['topic']].encode('utf-8') + ' ' + curr[listindex['title']].encode('utf-8') - else: - name = curr[listindex['title']].encode('utf-8') - description = curr[listindex['description']].encode('utf-8') - # datestring = datetime.now().strftime('%Y%m%d - ') - p = re.compile('[.:,!/]') - disname = name - name = p.sub('', name) - url = answerres.encode('utf-8') - formatval = '.mp4' - pos = url.rfind('.') - if pos != -1: - formatval = url[pos:] - recordfilename = getRecordingFilename(name, path.encode('utf-8')) - if answer == 'moviesave': - downloadManager.AddJob(DownloadJob(url, recordfilename + formatval, disname, description, headers_ts)) - self.session.open(MessageBox, _('Added:') + '\n\n' + disname, type=MessageBox.TYPE_INFO, timeout=4) - elif answer == 'movierecord': - - def downloadsegment2(m3u8list, _urlval): - logger.info("...") - file1 = open(recordfilename + '.ts', 'wb') - file1.close() - filemeta = open(recordfilename + '.ts.meta', 'wb') - filemeta.write('0:0:0:0:0:0:C00000:0:0:0:' + '\n') - filemeta.write(disname + '\n') - filemeta.write(curr[listindex['channel']].encode('utf-8') + '\n') - filemeta.write(str(int(time())) + '\n') - filemeta.close() - maxlen = len(m3u8list) - for x, m3u8 in enumerate(m3u8list): - if m3u8: - file = open(recordfilename + '.ts', 'ab') - downloadManager.active_jobs.append(DownloadJob(m3u8, file, '%s (%d/%d) %s' % ('Segment', x + 1, maxlen, disname), description, headers_ts)) - - if maxlen: - downloadManager.kick() - self.session.open(MessageBox, _('Added:') + '\n\n' + disname, type=MessageBox.TYPE_INFO, timeout=4) - - def backm3u8result(result): - logger.info("...") - m3u8 = result[0] - url = result[1] - if '#EXTM3U' in m3u8: - m3u8res = m3u8parser(m3u8, url) - if m3u8res.extxmedia_play(): - segment = m3u8res.parser_segment() - if segment: - downloadsegment2(segment, url) - elif m3u8res.extxmedia_hls(): - print('hls') - elif m3u8res.extxmedia_parse(): - print('download') - chunkurl, _suburi = m3u8res.parser_all() - if chunkurl: - self.download.start(MygetPage, url=chunkurl, headers=headers_ts, location=True).addCallback(backm3u8result).addErrback(self.http_failed) - - self.download.start(MygetPage, url=url, headers=headers_ts, location=True).addCallback(backm3u8result).addErrback(self.http_failed) - elif path: - self.session.open(MessageBox, _('Directory %s does not exist.') % path, type=MessageBox.TYPE_ERROR, timeout=5) - - SaveStreamToDisk(self.mvconfig.get('moviesavedir', '/media/hdd/movie/').encode('utf-8')) - - def checkvideourl(was): - logger.info("...") - if was in listindex and curr[listindex[was]] and curr[listindex[was]].startswith('http'): - return True - return False - - def getquali(was): - logger.info("...") - restext = '' - pos = curr[listindex[was]].rfind('.') - if pos != -1: - restext = curr[listindex[was]][pos + 1:].encode('utf-8') + ' / ' - return restext - - val = self.mvconfig.get('playmovieselect', 'url_video_hd') - if val == 'playmovieselect': - options = [] - if checkvideourl('url_video_low'): - options.append((getquali('url_video_low') + _('Low'), curr[listindex['url_video_low']])) - if checkvideourl('url_video'): - options.append((getquali('url_video') + _('Medium'), curr[listindex['url_video']])) - if checkvideourl('url_video_hd'): - options.append((getquali('url_video_hd') + _('Maximum'), curr[listindex['url_video_hd']])) - if options: - self.session.openWithCallback(moviesavecallback, ChoiceBox, title=_('Video') + ' ' + _('Resolution'), list=options, selection=len(options), titlebartext=_('Option Selector')) - elif val in listindex: - if checkvideourl(val): - moviesavecallback((val, curr[listindex[val]])) - elif checkvideourl('url_video_hd'): - moviesavecallback(('url_video_hd', curr[listindex['url_video_hd']])) - elif checkvideourl('url_video'): - moviesavecallback(('url_video', curr[listindex['url_video']])) - elif checkvideourl('url_video_low'): - moviesavecallback(('url_video_low', curr[listindex['url_video_low']])) - elif answer == 'downloadview': - self.session.open(MediathekCockpitDownloadView) - elif answer == 'livechannels': - self.load_livechannels() - - if len(self.mvconfig['searchquerys']) > 0: - options.append((_('Search list'), 'searchentries')) - options.append((_('Search for all entries in the search list'), 'searchallentries')) - if curr and len(curr) == listsearchquerys['listend'] and curr[listsearchquerys['queries']] and self['liste'].style == 'search_querys': - title = _('Name') + ': ' + curr[0] + '\n' + _('Fields:') + curr[1] + '\n' + _('Channel') + ': ' + curr[2] - options.append((_('Search list') + ' ' + _('Edit selected entry'), 'searchentriesedit')) - options.append((_('Search list') + ' ' + _('Remove entry'), 'searchentriesremove')) - options.append((_('Search list') + ' ' + _('Add entry'), 'addsearchentries')) - cantofavo = False - if curr and len(curr) == listindex['listend'] and curr[listindex['channel']] != '>>>': - cantofavo = True - if curr[listindex['topic']]: - titlebartext = curr[listindex['topic']] - options.append(('--', '--')) - options.append((_("Search for '%s'") % curr[listindex['topic']][:65], 'searchfor')) - if curr[listindex['title']]: - title = curr[listindex['title']] - options.append((_("Search for '%s'") % curr[listindex['title']][:65], 'searchfortitle')) - options.append(('--', '--')) - options.append((_('Manual Search'), 'manualsearch')) - if cantofavo and not self['key_blue'].text in self.title: - options.append(('--', '--')) - options.append((_('Add favorite'), 'addtofavorites')) - elif len(self.mvconfig['favorites']) > 0 and self['key_blue'].text in self.title: - options.append(('--', '--')) - options.append((_('Remove favorite'), 'delfavorites')) - if DownloadJob and curr and len(curr) >= listindex['url_video_hd'] and curr[listindex['channel']] != '>>>': - if curr[listindex['url_video_low']].endswith(('mp4', 'flv')) or curr[listindex['url_video']].endswith(('mp4', 'flv')) or curr[listindex['url_video_hd']].endswith(('mp4', 'flv')): - options.append((_('movie') + ' ' + _('Save'), 'moviesave')) - elif curr[listindex['url_video_low']].endswith('m3u8') or curr[listindex['url_video']].endswith('m3u8') or curr[listindex['url_video_hd']].endswith('m3u8'): - if curr[listindex['duration']]: - options.append((_('movie') + ' ' + _('Save'), 'movierecord')) - options.append(('--', '--')) - options.append((_('Live channels'), 'livechannels')) - options.append((_('Setup'), 'setupview')) - options.append((_('Download manager'), 'downloadview')) - if options: - self.session.openWithCallback(ChoiceBoxCallback, ChoiceBox, title=title, list=options, skin_name='ChoiceBoxMvMenu', titlebartext=titlebartext) - - def key_info(self): - logger.info("...") - curr = self['liste'].getCurrent() - options = [] - title = _('Select') - titlebartext = 'MediathekCockpit' - - def ChoiceBoxCallback(answer): - logger.info("...") - answer = answer and answer[1] - if answer == 'moveUp': - self.moveUp() - elif answer == 'moveDown': - self.moveDown() - elif answer == 'livestreammoveUp': - self.livestreammoveUp() - elif answer == 'livestreammoveDown': - self.livestreammoveDown() - elif answer == 'livestreamdel': - - def del_curr(answer1=None): - logger.info("...") - if answer1: - self.changed['live'] = True - self.mvconfig['livechannels'].pop(self['liste'].getIndex()) - self['liste'].updateList(self.mvconfig['livechannels'][:]) - self.__SelectionChanged() - self.set_sresult_entries() - - text = '%s\n\n%s' % (curr[0], _('Delete')) - self.session.openWithCallback(del_curr, MessageBox, text) - elif answer in ('verifyandupdate', 'cached', 'verify', 'playmaster'): - self.changed['live'] = True - currindex = self['liste'].getIndex() - curr[liveindex['default']] = answer - self.mvconfig['livechannels'][currindex][liveindex['default']] = answer - if answer in ('verifyandupdate', 'verify', 'playmaster'): - curr[liveindex['index_url']] = '' - curr[liveindex['audio_url']] = '' - curr[liveindex['eservice']] = '' - self.mvconfig['livechannels'][currindex][liveindex['index_url']] = '' - self.mvconfig['livechannels'][currindex][liveindex['audio_url']] = '' - self['liste'].modifyEntry(currindex, curr) - self.__SelectionChanged() - - if curr and len(curr) == listindex['listend'] and curr[listindex['channel']] != '>>>': - self.session.open(MediathekCockpitEventView, curr) - elif curr and len(curr) == liveindex['listend']: - title = ('{0} ({1})\n{2} ({3})').format(_('Default'), curr[liveindex['default']], _('options'), (', ').join(curr[liveindex['options']])) - titlebartext = curr[liveindex['name']] - options.append((_('Move selected item up'), 'livestreammoveUp')) - options.append((_('Move selected item down'), 'livestreammoveDown')) - if 'verifyandupdate' in curr[liveindex['options']] and curr[liveindex['default']] != 'verifyandupdate': - options.append((_('Reset') + ' (verifyandupdate)', 'verifyandupdate')) - if 'verify' in curr[liveindex['options']] and curr[liveindex['default']] != 'verify': - options.append((_('Reset') + ' (verify)', 'verify')) - if 'playmaster' in curr[liveindex['options']] and curr[liveindex['default']] != 'playmaster': - options.append((_('Reset') + ' (playmaster)', 'playmaster')) - if options: - options.append(('--', '--')) - options.append((_('remove entry'), 'livestreamdel')) - elif curr and len(curr) == 4 and curr[3] and self['liste'].style == 'search_querys': - title = _('Name') + ': ' + curr[0] + '\n' + _('Fields:') + curr[1] + '\n' + _('Channel') + ': ' + curr[2] - currindex = self['liste'].getIndex() - if currindex != 0: - options.append((_('Move selected item up'), 'moveUp')) - if currindex != self['liste'].count() - 1: - options.append((_('Move selected item down'), 'moveDown')) - if options: - self.session.openWithCallback(ChoiceBoxCallback, ChoiceBox, title=title, list=options, skin_name='ChoiceBoxMvMenu', titlebartext=titlebartext) - - def moveUp(self): - logger.info("...") - self.changed['querys'] = True - currindex = self['liste'].getIndex() - self['liste'].moveSelection('moveUp') - self['liste'].list.insert(self['liste'].getIndex(), self['liste'].list.pop(currindex)) - self.mvconfig['searchquerys'].insert(self['liste'].getIndex(), self.mvconfig['searchquerys'].pop(currindex)) - - def moveDown(self): - logger.info("...") - self.changed['querys'] = True - currindex = self['liste'].getIndex() - self['liste'].moveSelection('moveDown') - self['liste'].list.insert(self['liste'].getIndex(), self['liste'].list.pop(currindex)) - self.mvconfig['searchquerys'].insert(self['liste'].getIndex(), self.mvconfig['searchquerys'].pop(currindex)) - - def livestreammoveUp(self): - logger.info("...") - curr = self['liste'].getCurrent() - if curr and len(curr) == liveindex['listend']: - print('livestreammoveUp') - self.changed['live'] = True - currindex = self['liste'].getIndex() - self['liste'].moveSelection('moveUp') - self['liste'].list.insert(self['liste'].getIndex(), self['liste'].list.pop(currindex)) - self.mvconfig['livechannels'].insert(self['liste'].getIndex(), self.mvconfig['livechannels'].pop(currindex)) - - def livestreammoveDown(self): - logger.info("...") - curr = self['liste'].getCurrent() - if curr and len(curr) == liveindex['listend']: - self.changed['live'] = True - currindex = self['liste'].getIndex() - self['liste'].moveSelection('moveDown') - self['liste'].list.insert(self['liste'].getIndex(), self['liste'].list.pop(currindex)) - self.mvconfig['livechannels'].insert(self['liste'].getIndex(), self.mvconfig['livechannels'].pop(currindex)) - - def download_page(self): - logger.info("...") - page = self.mvconfig['postdata']['offset'] / self.mvconfig['size'] + 1 - self['message'].text = _('Please wait... Loading list...') + ' ' + _('Page:') + ' ' + str(page) - self['message'].show() - url = 'https://mediathekviewweb.de/api/query' - self.download.start(MygetPage, url=url, method='POST', postdata=json.dumps(self.mvconfig['postdata']), headers=headersplain).addCallback(self.result_back).addErrback(self.http_failed) - - def result_back(self, result): - logger.info("...") - if result: - alist = [] - self.setTitle(self.titeltext + ' ' + _('Online') + ' ' + _('Movies')) - self['message'].text = _('Please wait...') + ' Parse' - self['message'].show() - self['liste'].style = 'movi_liste' - data = json.loads(result) - if data.get('error'): - return - del result - logger.debug("data: %s", data) - queryInfo = data['result']['queryInfo'] - self.mvconfig['resultCount'] = queryInfo['resultCount'] - self.mvconfig['totalResults'] = queryInfo['totalResults'] - self.mvconfig['searchEngineTime'] = queryInfo['searchEngineTime'] - self.mvconfig['filmlisteTimestamp'] = datetime.fromtimestamp(int(queryInfo['filmlisteTimestamp'])).strftime('%d.%m.%Y %H:%M:%S') - queryInfo.clear() - results = data['result']['results'] - data.clear() - for x in results: - tmp = listempty[:] - if 'timestamp' in x: - dtmp = datetime.fromtimestamp(int(x['timestamp'])).strftime('%d.%m.%Y %H:%M:%S') - tmp[listindex['date']] = dtmp[0:10] - tmp[listindex['time']] = dtmp[11:16] - if 'duration' in x: - tmp[listindex['duration']] = str(timedelta(seconds=x['duration'] or 0)) - if 'channel' in x: - name = x['channel'].encode('utf-8') - ptr = Load_My_Pixmap('%slogos/%s.png' % (plugindir, name.replace(' ', '').upper())) - tmp[listindex['channel']] = name - tmp[listindex['channelpixmap']] = ptr - tmp[listindex['timetext']] = _('Clock') - if 'topic' in x: - tmp[listindex['topic']] = x['topic'].encode('utf-8') - if 'title' in x: - tmp[listindex['title']] = x['title'].encode('utf-8') - if 'description' in x: - tmp[listindex['description']] = x['description'].encode('utf-8') - if 'size' in x: - tmp[listindex['size']] = int(x['size'] or 0) / 1048576 - if 'id' in x: - tmp[listindex['id']] = x['id'] - if 'url_video_low' in x: - tmp[listindex['url_video_low']] = x['url_video_low'] - if 'url_video' in x: - tmp[listindex['url_video']] = x['url_video'] - if 'url_video_hd' in x: - tmp[listindex['url_video_hd']] = x['url_video_hd'] - if 'url_website' in x: - tmp[listindex['url_website']] = x['url_website'] - alist.append(tmp) - - math = min(self.mvconfig['postdata']['offset'] + self.mvconfig['resultCount'], self.mvconfig['totalResults']) - if self.mvconfig['totalResults'] != math: - addtmp = listempty[:] - addtmp[listindex['channel']] = '>>>' - addtmp[listindex['topic']] = _('Next page') - addtmp[listindex['title']] = _('Select') - addtmp[listindex['date']] = '>>>' - alist.append(addtmp) - self['liste'].setList(alist) - if self.currindex: - self['liste'].setIndex(self.currindex) - self.set_sresult() - return - - def result_back_channels(self, result): - logger.info("...") - if result: - self['liste'].style = 'default' - data = json.loads(result) - if data.get('error', True): - return - channels = data['channels'] - self.mvconfig['channelslist'] = [] - self.mvconfig['channels'] = [] - for val in channels: - name = val.encode('utf-8') - ptr = Load_My_Pixmap('%slogos/%s.png' % (plugindir, name.replace(' ', '').upper())) - self['liste'].list.append((name, '', ptr)) - self.mvconfig['channelslist'].append((name, '', ptr)) - self.mvconfig['channels'].append(name) - - self['liste'].setList(self.mvconfig['channelslist'][:]) - self.set_sresult_entries() - self['message'].hide() - return - - def load_livechannels(self): - logger.info("...") - if not self.mvconfig['livechannels']: - self.mvconfig['livechannels'] = read_livechannels() - self.setTitle(self.titeltext + ' ' + _('Live channels')) - self['liste'].style = 'default' - if self.mvconfig['livechannels']: - self['liste'].setList(self.mvconfig['livechannels'][:]) - self.set_sresult_entries() - - def set_sresult(self): - logger.info("...") - self['message'].hide() - math = min(self.mvconfig['postdata']['offset'] + self.mvconfig['resultCount'], self.mvconfig['totalResults']) - self['sresult'].setText('%s: (%s/%s)\n%s: %s ms\n%s: %s' % ( - _('Entries'), math, str(self.mvconfig['totalResults']), _('Time'), str(self.mvconfig['searchEngineTime']), _('From'), str(self.mvconfig['filmlisteTimestamp']))) - - def set_sresult_entries(self): - logger.info("...") - self['sresult'].setText(('{0}:{1}').format(_('Entries'), self['liste'].count())) - - def __SelectionChanged(self): - logger.info("...") - - def clearall(): - logger.info("...") - self['description'].setText('') - self['date'].setText('') - - curr = self['liste'].getCurrent() - if curr: - summaryempty = [''] * listindex['id'] - currlen = len(curr) - if currlen == listindex['listend'] and curr[listindex['channel']] != '>>>': - self['description'].setText(curr[listindex['description']]) - size = curr[listindex['size']] - sizetext = '' - if size: - sizetext = ' %d MB' % size - self['date'].setText('%s: %s\n%s: %s\n%s: %s%s' % (_('Date'), curr[listindex['date']], _('Time'), curr[listindex['time']], _('Duration'), curr[listindex['duration']], sizetext)) - summaryempty = curr[:listindex['id']] - summaryempty[listindex['size']] = sizetext - elif currlen == listindex['listend'] and curr[listindex['channel']] == '>>>': - summaryempty[listindex['channel']] = curr[listindex['topic']] - summaryempty[listindex['title']] = curr[listindex['title']] - elif currlen == liveindex['listend']: - txt = ('master_url\n{0}').format(curr[liveindex['master_url']]) - if curr[liveindex['index_url']]: - txt += ('\n\nindex_url\n{0}').format(curr[liveindex['index_url']]) - if curr[liveindex['audio_url']]: - txt += ('\n\naudio_url\n{0}').format(curr[liveindex['audio_url']]) - dtxt = ('{0} ({1})\n{2} ({3})').format(_('Default'), curr[liveindex['default']], _('options'), (', ').join(curr[liveindex['options']])) - self['date'].setText(dtxt) - self['description'].setText(txt) - summaryempty[listindex['channel']] = curr[liveindex['name']] - summaryempty[listindex['channelpixmap']] = curr[liveindex['channelpixmap']] - elif currlen == listchannel['listend']: - clearall() - summaryempty[listindex['channel']] = curr[listchannel['channel']] - summaryempty[listindex['channelpixmap']] = curr[listchannel['channelpixmap']] - elif currlen == listsearchquerys['listend']: - summaryempty[listindex['channel']] = curr[listsearchquerys['name']] - summaryempty[listindex['title']] = _('Fields:') + ' ' + curr[listsearchquerys['fields']] - clearall() - else: - clearall() - self['summaryliste'].setList(summaryempty) - else: - clearall() - - def http_failed(self, failure_instance, *args): - logger.info("...") - error_message = str(failure_instance.getErrorMessage()) - if not error_message: - error_message = str(failure_instance) - print('#' * 50) - print(error_message, str(args)) - if 'CancelledError' not in error_message: - print('#' * 50) - self.session.open(MessageBox, error_message, MessageBox.TYPE_INFO, timeout=10, title=_('Download failed')) - self['message'].hide() - - def createSummary(self): - logger.info("...") - return MediathekCockpitSummary + # exit + self.session.nav.playService(self.last_service) - def __onClose(self): - logger.info("...") - if self.changed['config']: - write_mvconfig(self.mvconfig) - if self.changed['favo']: - write_favorites(self.mvconfig['favorites']) - if self.changed['querys']: - write_searchquerys(self.mvconfig['searchquerys']) - if self.changed['live']: - write_livechannels(self.mvconfig['livechannels']) - # _pixmap_cache.clear() - self.mvconfig.clear() - self.tmplist.clear() - self.changed.clear() - self.session.nav.playService(self.lastservice) + def keyboardCallback(self, postdata): + self.showScreen(Movies, postdata) diff --git a/src/MediathekCockpitEventView.py b/src/MediathekCockpitEventView.py deleted file mode 100644 index ce5f059..0000000 --- a/src/MediathekCockpitEventView.py +++ /dev/null @@ -1,31 +0,0 @@ -from Screens.Screen import Screen -from Components.ActionMap import ActionMap -from Components.Label import Label -from Components.ScrollLabel import ScrollLabel -from Components.Button import Button -from .Debug import logger -from .Constants import listindex - - -class MediathekCockpitEventView(Screen): - - def __init__(self, session, curr): - logger.info("...") - self.skinName = 'MediathekCockpitEventView' - Screen.__init__(self, session, windowTitle=curr[listindex['topic']]) - self['actions'] = ActionMap( - ['OkCancelActions', 'ChannelSelectEPGActions'], - { - 'ok': self.close, - 'cancel': self.close, - 'showEPGList': self.close - } - ) - self['key_red'] = Button('') - self['key_green'] = Button('') - self['key_yellow'] = Button('') - self['key_blue'] = Button('') - self['epg_description'] = ScrollLabel(curr[listindex['title']] + '\n\n\n' + curr[listindex['description']]) - self['datetime'] = Label(curr[listindex['date']]) - self['channel'] = Label(curr[listindex['duration']] + ' ' + curr[listindex['channel']]) - self['duration'] = Label(curr[listindex['time']]) diff --git a/src/MediathekCockpitSearchEntry.py b/src/MediathekCockpitSearchEntry.py deleted file mode 100644 index f0c48d2..0000000 --- a/src/MediathekCockpitSearchEntry.py +++ /dev/null @@ -1,172 +0,0 @@ -from enigma import eTimer -from Screens.Screen import Screen -from Components.ActionMap import ActionMap -from Components.Sources.List import List -from Components.Sources.StaticText import StaticText -from Components.ConfigList import ConfigListScreen -from Components.config import ConfigSubsection, getConfigListEntry, ConfigSubList -from Components.config import ConfigSelection, ConfigYesNo, NoSave, ConfigDirectory -from Components.config import KEY_OK -from Plugins.SystemPlugins.Toolkit.NTIVirtualKeyBoard import NTIVirtualKeyBoard -from MyJobManager import downloadManager -from .__init__ import _ -from .Debug import logger -from .Constants import listfields -from .SearchUtils import convert_searchquerys - - -class MediathekCockpitSearchEntry(Screen, ConfigListScreen): - IS_DIALOG = True - - def __init__(self, session, mvconfig, windowTitle='MediathekCockpit ' + _('Search entry'), currquery=None): - logger.info("...") - self.mvconfig = mvconfig - if currquery is None: - currquery = {'queries': [{'fields': ['topic'], 'query': 'Tatort'}]} - Screen.__init__(self, session, windowTitle=windowTitle) - ConfigListScreen.__init__(self, [], session=session) - self.skinName = 'Setup' - self.queryindex = currquery.get('queryindex', None) - self.default = 'Tatort' - self.defaultfields = listfields['topic'] - self.defaultchannel = [] - for queries in currquery['queries']: - if queries.get('fields') == listfields['channel']: - self.defaultchannel.append(queries.get('query', None)) - elif queries.get('fields') != listfields['channel']: - self.default = queries.get('query', None) - self.defaultfields = queries.get('fields', ['topic']) - - self['key_red'] = StaticText(_('Cancel')) - self['key_green'] = StaticText(_('Save')) - self['actions'] = ActionMap( - ['SetupActions', 'ColorActions'], - { - 'cancel': self.keyCancel, - 'save': self.keySave - } - ) - self.settings = ConfigSubsection() - self.settings.query = NoSave(ConfigDirectory(default=self.default)) - choices = [] - choices.append((listfields['topic'], _('Topic'))) - choices.append((listfields['title'], _('Title'))) - choices.append((listfields['description'], _('Description'))) - choices.append((listfields['topictitle'], _('Topic') + ' / ' + _('Title'))) - choices.append((listfields['topictitledescription'], _('Topic') + ' / ' + _('Title') + ' / ' + _('Description'))) - self.settings.fields = NoSave(ConfigSelection(default=self.defaultfields, choices=choices)) - self.channels = ConfigSubList() - self['liste'] = List([]) - self.currindex = 0 - self.__dlRefreshTimer = eTimer() - self.__dlRefreshTimer_conn = self.__dlRefreshTimer.timeout.connect(self._createSetup) - self._createSetup() - - def _createSetup(self): - logger.info("...") - entries = [] - entries.append(getConfigListEntry(_('Search for:'), self.settings.query)) - entries.append(getConfigListEntry(_('Fields:'), self.settings.fields)) - entries.append(getConfigListEntry(_('Channels:'))) - for channel in self.mvconfig['channels']: - if self.defaultchannel: - ischannel = channel in self.defaultchannel - else: - ischannel = True - tmp = NoSave(ConfigYesNo(default=ischannel)) - self.channels.append(tmp) - entries.append(getConfigListEntry(channel, tmp)) - - self['config'].list = entries - - def keyOK(self): - logger.info("...") - curr = self['config'].getCurrent() - if curr and curr[1] == self.settings.query: - - def resulttext(res=None): - logger.info("...") - if res: - self.settings.query.value = res - self._createSetup() - - self.session.openWithCallback(resulttext, NTIVirtualKeyBoard, title=_('Enter text to search for'), text=self.settings.query.value) - else: - self['config'].handleKey(KEY_OK) - - def keyCancel(self): - logger.info("...") - self.close(None) - - def keySave(self): - logger.info("...") - searchquerys = {} - searchquerys['queries'] = [] - searchquerys['queries'].append({'fields': self.settings.fields.value, 'query': self.settings.query.value}) - tmp = [] - for channel in range(len(self.mvconfig['channels'])): - if self.channels[channel].value: - tmp.append({'fields': ['channel'], 'query': self.mvconfig['channels'][channel]}) - - if len(self.mvconfig['channels']) != len(tmp): - searchquerys['queries'].extend(tmp) - if self.queryindex is None: - querys2 = convert_searchquerys(searchquerys['queries']) - if querys2 not in self.mvconfig['searchquerys']: - self.mvconfig['searchquerys'].insert(0, querys2) - elif self['config'].isChanged(): - querys2 = convert_searchquerys(searchquerys['queries']) - if self.mvconfig['searchquerys'][self.queryindex] != querys2: - self.mvconfig['searchquerys'][self.queryindex] = querys2 - self.close(self.mvconfig) - - def _createSetup(self): - logger.info("...") - self.__dlRefreshTimer.stop() - self.currindex = self['liste'].index - result = [] - for job in downloadManager.getPendingJobs(): - if job.status == job.IN_PROGRESS: - if job.recvbytes >= 5242880: - mbinfo = '%d%% (%d/%d) Mb' % (job.progress, job.recvbytes / 1024 / 1024, job.totalbytes / 1024 / 1024) - else: - mbinfo = '%d%% (%d/%d) Byte' % (job.progress, job.recvbytes / 1024, job.totalbytes / 1024) - result.append([job.name, job.getStatustext(), job.progress, str(mbinfo), job]) - else: - result.append([job.name, job.getStatustext(), -1, '', job]) - - self['liste'].setList(result) - self['liste'].index = self.currindex - if len(result) > 0 and not self.__dlRefreshTimer.isActive(): - self.__dlRefreshTimer.startLongTimer(2) - - def key_yellow(self): - logger.info("...") - self.__dlRefreshTimer.stop() - downloadManager.active_jobs = [] - for job in downloadManager.active_jobs: - print(job.name) - job.abort() - - self._createSetup() - - def key_green(self): - logger.info("...") - self.__dlRefreshTimer.stop() - del downloadManager.active_jobs[:] - currjob = downloadManager.active_job - if currjob and currjob.status == currjob.IN_PROGRESS: - currjob.cancel() - self._createSetup() - - def currabort(self): - logger.info("...") - curr = self['liste'].getCurrent() - if curr and len(curr) == 5: - self.__dlRefreshTimer.stop() - currjob = curr[4] - if currjob.status == currjob.NOT_STARTED: - downloadManager.active_jobs.remove(currjob) - elif currjob.status == currjob.IN_PROGRESS: - currjob.cancel() - self._createSetup() diff --git a/src/MediathekCockpitSetup.py b/src/MediathekCockpitSetup.py deleted file mode 100644 index 85480d5..0000000 --- a/src/MediathekCockpitSetup.py +++ /dev/null @@ -1,125 +0,0 @@ -from Screens.Screen import Screen -from Components.ActionMap import ActionMap -from Components.Sources.StaticText import StaticText -from Components.ConfigList import ConfigListScreen -from Components.config import ConfigSubsection, getConfigListEntry -from Components.config import ConfigSelection, ConfigYesNo, ConfigSelectionNumber, NoSave, ConfigDirectory -from Components.config import KEY_OK -from Tools.Directories import pathExists -from .MediathekCockpitDirBrowser import MediathekCockpitDirBrowser -from .__init__ import _ -from .Debug import logger -from .Constants import listfields - - -class MediathekCockpitSetup(Screen, ConfigListScreen): - IS_DIALOG = True - - def __init__(self, session, mvconfig, windowTitle=_('MediathekCockpit') + ' ' + _('Setup')): - logger.info("...") - self.mvconfig = mvconfig - Screen.__init__(self, session, windowTitle=windowTitle) - ConfigListScreen.__init__(self, [], session=session) - self.skinName = 'Setup' - self['key_red'] = StaticText(_('Cancel')) - self['key_green'] = StaticText(_('Save')) - self['actions'] = ActionMap( - ['SetupActions', 'ColorActions'], - { - 'cancel': self.keyCancel, - 'save': self.keySave - } - ) - self.settings = ConfigSubsection() - self.settings.size = NoSave(ConfigSelectionNumber(min=50, max=1500, stepwidth=50, default=self.mvconfig.get('size', 500), wraparound=True)) - choices = [] - choices.append((listfields['topic'], _('Topic'))) - choices.append((listfields['title'], _('Title'))) - choices.append((listfields['description'], _('Description'))) - choices.append((listfields['topictitle'], _('Topic') + ' ' + _('Title'))) - choices.append((listfields['topictitledescription'], _('Topic') + ' ' + _('Title') + ' ' + _('Description'))) - self.settings.searchquerysfields = NoSave(ConfigSelection(default=self.mvconfig.get('searchquerysfields', listfields['topic']), choices=choices)) - self.settings.future = NoSave(ConfigYesNo(default=self.mvconfig.get('future', False))) - choices = [] - choices.append(('easyselection', _('Easy selection'))) - choices.append(('searchentries', _('Search list'))) - choices.append(('searchallentries', _('Search for all entries in the search list'))) - choices.append(('manualsearch', _('Manual Search'))) - choices.append(('livechannels', _('Live channels'))) - self.settings.searchstart = NoSave(ConfigSelection(default=self.mvconfig.get('searchstart', 'easyselection'), choices=choices)) - choices = [] - choices.append(('quit', _('No, do nothing.'))) - choices.append(('ask', _('Ask user'))) - self.settings.askstopmovie = NoSave(ConfigSelection(default=self.mvconfig.get('askstopmovie', 'quit'), choices=choices)) - choices = [] - choices.append(('playmovieselect', _('Ask user'))) - choices.append(('url_video_low', _('Low'))) - choices.append(('url_video', _('Medium'))) - choices.append(('url_video_hd', _('Maximum'))) - self.settings.playmovieselect = NoSave(ConfigSelection(default=self.mvconfig.get('playmovieselect', 'url_video_hd'), choices=choices)) - self.settings.moviesavedir = NoSave(ConfigDirectory(default=self.mvconfig.get('moviesavedir', '/media/hdd/movie/'))) - self.settings.duration_min = NoSave(ConfigSelectionNumber(min=0, max=240, stepwidth=1, default=self.mvconfig.get('duration_min', 0), wraparound=True)) - self.settings.duration_max = NoSave(ConfigSelectionNumber(min=0, max=240, stepwidth=1, default=self.mvconfig.get('duration_max', 0), wraparound=True)) - self._createSetup() - - def _createSetup(self): - logger.info("...") - entries = [] - entries.append(getConfigListEntry(_('Entries per page'), self.settings.size)) - entries.append(getConfigListEntry(_('Fields:') + ' ' + _('Search for all entries in the search list'), self.settings.searchquerysfields)) - entries.append(getConfigListEntry(_('Future'), self.settings.future)) - entries.append(getConfigListEntry(_('Yellow button mapping'), self.settings.searchstart)) - entries.append(getConfigListEntry('')) - entries.append(getConfigListEntry(_('Minimum movie') + ' ' + _('Duration') + ' (' + _('minutes') + ') (0=' + _('disabled') + ')', self.settings.duration_min)) - entries.append(getConfigListEntry(_('Maximum movie') + ' ' + _('Duration') + ' (' + _('minutes') + ') (0=' + _('disabled') + ')', self.settings.duration_max)) - entries.append(getConfigListEntry(_('Video') + ' ' + _('Resolution'), self.settings.playmovieselect)) - entries.append(getConfigListEntry(_('Behavior when a movie is stopped'), self.settings.askstopmovie)) - entries.append(getConfigListEntry(_('Select movie path'), self.settings.moviesavedir)) - self['config'].list = entries - - def LocationBoxback(self, res): - logger.info("res: %s", res) - if res: - if pathExists(res): - self.settings.moviesavedir.value = res - - def keyOK(self): - logger.info("...") - curr = self['config'].getCurrent() - if curr and curr[1] == self.settings.moviesavedir: - self.session.openWithCallback(self.LocationBoxback, MediathekCockpitDirBrowser, self.settings.moviesavedir.value) - else: - self['config'].handleKey(KEY_OK) - - def keySave(self): - logger.info("...") - if self['config'].isChanged(): - self.mvconfig['size'] = int(self.settings.size.value) - self.mvconfig['postdata']['size'] = self.mvconfig['size'] - self.mvconfig['searchquerysfields'] = self.settings.searchquerysfields.value - self.mvconfig['future'] = self.settings.future.value - self.mvconfig['askstopmovie'] = self.settings.askstopmovie.value - self.mvconfig['postdata']['Show future movies'] = self.mvconfig['future'] - self.mvconfig['searchstart'] = self.settings.searchstart.value - self.mvconfig['playmovieselect'] = self.settings.playmovieselect.value - self.mvconfig['postdata']['offset'] = 0 - self.mvconfig['moviesavedir'] = self.settings.moviesavedir.value - if int(self.settings.duration_min.value) > 0: - self.mvconfig['duration_min'] = int(self.settings.duration_min.value) - self.mvconfig['postdata']['duration_min'] = self.mvconfig['duration_min'] * 60 - else: - if 'duration_min' in self.mvconfig: - del self.mvconfig['duration_min'] - if 'duration_min' in self.mvconfig['postdata']: - del self.mvconfig['postdata']['duration_min'] - if int(self.settings.duration_max.value) > 0: - self.mvconfig['duration_max'] = int(self.settings.duration_max.value) - self.mvconfig['postdata']['duration_max'] = self.mvconfig['duration_max'] * 60 - else: - if 'duration_max' in self.mvconfig: - del self.mvconfig['duration_max'] - if 'duration_max' in self.mvconfig['postdata']: - del self.mvconfig['postdata']['duration_max'] - self.close(self.mvconfig) - else: - self.close(False) diff --git a/src/Menu.py b/src/Menu.py new file mode 100644 index 0000000..aa89fd8 --- /dev/null +++ b/src/Menu.py @@ -0,0 +1,55 @@ +#!/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 .Downloads import Downloads +from .Settings import Settings +from .About import about +from .Debug import logger +from .__init__ import _ + + +class Menu(): + def __init__(self, session, postdata): + self.session = session + self.postdata = postdata + options = [] + options.append((_('Download Manager'), self.showDownloadManager)) + options.append((_('Settings'), self.showSettings)) + options.append((_('About'), self.showAbout)) + self.session.openWithCallback(self.ChoiceBoxCallback, ChoiceBox, title=_('Functions'), list=options, titlebartext='MediathekCockpit' + " " + _("Menu")) + + def ChoiceBoxCallback(self, selection): + logger.info("...") + if selection: + selection[1]() + + def showDownloadManager(self): + logger.info("...") + self.session.open(Downloads) + + def showSettings(self): + logger.info("...") + self.session.open(Settings, self.postdata) + + def showAbout(self): + logger.info("...") + about(self.session) diff --git a/src/MoviePlayer.py b/src/MoviePlayer.py index 4fde353..274bb0b 100644 --- a/src/MoviePlayer.py +++ b/src/MoviePlayer.py @@ -1,9 +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 Components.config import config +from Components.ActionMap import ActionMap +from Components.ServiceEventTracker import InfoBarBase from Screens.Screen import Screen from Screens.SimpleSummary import SimpleSummary from Screens.InfoBarGenerics import PlayerBase, InfoBarNotifications, InfoBarSeek, InfoBarShowHide, InfoBarAudioSelection, InfoBarSubtitleSupport, InfoBarServiceErrorPopupSupport, InfoBarGstreamerErrorPopupSupport, InfoBarServiceNotifications, InfoBarPVRState from Screens.ChoiceBox import ChoiceBox -from Components.ActionMap import ActionMap -from Components.ServiceEventTracker import InfoBarBase from enigma import iServiceInformation, iPlayableService from .__init__ import _ from .Debug import logger @@ -17,7 +39,7 @@ class BasePlayer(InfoBarBase, InfoBarShowHide, InfoBarAudioSelection, InfoBarSub ENABLE_RESUME_SUPPORT = False ALLOW_SUSPEND = True - def __init__(self, session, service, infoval=None, menuval=None, myconfig=None, lastservice=None): + def __init__(self, session, service, infoval=None, menuval=None, lastservice=None): logger.info("...") for x in [ InfoBarBase, InfoBarShowHide, InfoBarAudioSelection, @@ -26,14 +48,11 @@ def __init__(self, session, service, infoval=None, menuval=None, myconfig=None, ]: x.__init__(self) - if myconfig is None: - myconfig = {'askstopmovie': 'quit'} self.session = session self.service = service self.lastservice = lastservice self.infoval = infoval self.menuval = menuval - self.myconfig = myconfig self['ShowHideActions'] = ActionMap( ['InfobarShowHideActions', 'MoviePlayerActions', 'MenuActions', 'ChannelSelectEPGActions'], { @@ -81,7 +100,6 @@ def __evVideoSizeChanged(self): if service: info = service.info() if info: - print('**********') _xres = info.getInfo(iServiceInformation.sVideoWidth) _yres = info.getInfo(iServiceInformation.sVideoHeight) frame_rate = info.getInfo(iServiceInformation.sFrameRate) @@ -90,11 +108,10 @@ def __evVideoSizeChanged(self): frame_rate *= 2 frame_rate = (frame_rate + 500) / 1000 _p = 'p' if progressive else 'i' - print(iPlayableService.evVideoTypeReady) - print(iPlayableService.evVideoSizeChanged) - print(iPlayableService.evVideoFramerateChanged) - print(iPlayableService.evVideoProgressiveChanged) - print('**********') + logger.debug("evVideoTypeReady: %s", iPlayableService.evVideoTypeReady) + logger.debug("evVideoSizeChanged: %s", iPlayableService.evVideoSizeChanged) + logger.debug("evVideoFramerateChanged: %s", iPlayableService.evVideoFramerateChanged) + logger.debug("evVideoProgressiveChanged: %s", iPlayableService.evVideoProgressiveChanged) def createSummary(self): logger.info("...") @@ -106,7 +123,7 @@ class StreamPlayer(Screen, PlayerBase, BasePlayer): def __init__(self, session, service, *args, **kwargs): logger.info("...") Screen.__init__(self, session) - self.skinName = ['MvStreamPlayer', 'MvMoviePlayer', 'MoviePlayer'] + self.skinName = ['MTCStreamPlayer', 'MTCMoviePlayer', 'MoviePlayer'] PlayerBase.__init__(self) BasePlayer.__init__(self, session, service, *args, **kwargs) @@ -116,7 +133,7 @@ class MoviePlayer(Screen, BasePlayer, InfoBarSeek, InfoBarServiceNotifications, def __init__(self, session, service, *args, **kwargs): logger.info("...") Screen.__init__(self, session) - self.skinName = ['MvMoviePlayer', 'MoviePlayer'] + self.skinName = ['MTCMoviePlayer', 'MoviePlayer'] InfoBarSeek.__init__(self) BasePlayer.__init__(self, session, service, *args, **kwargs) InfoBarServiceNotifications.__init__(self) @@ -128,11 +145,11 @@ def doEofInternal(self, playing): return if not playing: return - self.handleLeave(self.myconfig.get('askstopmovie', 'quit')) + self.handleLeave(config.plugins.mediathekcockpit.askstopmovie.value) def leavePlayer(self): logger.info("...") - self.handleLeave(self.myconfig.get('askstopmovie', 'quit')) + self.handleLeave(config.plugins.mediathekcockpit.askstopmovie.value) def handleLeave(self, how): logger.info("...") diff --git a/src/Movies.py b/src/Movies.py new file mode 100644 index 0000000..413bb56 --- /dev/null +++ b/src/Movies.py @@ -0,0 +1,324 @@ +#!/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 re +import json +from datetime import datetime, timedelta +from enigma import eServiceReference +from Screens.Screen import Screen +from Screens.MessageBox import MessageBox +from Components.ActionMap import ActionMap +from Components.config import config +from Components.Label import Label +from Components.Sources.StaticText import StaticText +from Components.Sources.List import List +from Tools.Directories import getRecordingFilename +from .Debug import logger +from .LoadPixmap import loadPixmap +from .Downloader import MyGetPage, _headers, headers_ts, headersplain +from .MyDeferredSemaphore import MyDeferredSemaphore +from .__init__ import _ +from .Version import PLUGIN +from .MoviePlayer import MoviePlayer +from .EventView import EventView +from .M3U8Parser import M3U8Parser +from .MyJobManager import downloadManager, DownloadJob +from .Menu import Menu +from .ConfigInit import VIDEO_RESOLUTIONS, VIDEO_RESOLUTIONS_DICT +from .Constants import plugindir, listempty, LIST_DATE, LIST_TIME, LIST_DURATION, LIST_CHANNEL, LIST_CHANNELPIXMAP, LIST_TOPIC, LIST_TITLE, LIST_DESCRIPTION, LIST_SIZE, LIST_ID, LIST_URL_VIDEO_LOW, LIST_URL_VIDEO, LIST_URL_VIDEO_HD, LIST_URL_WEBSITE + + +class Movies(Screen): + def __init__(self, session, postdata): + self.postdata = postdata + Screen.__init__(self, session) + self.skinName = 'MediathekCockpit' + self.title = PLUGIN + ' - ' + _('Movies') + if "queries" in postdata: + self.title += " - " + _('Search results') + + self['key_red'] = StaticText(_('Live')) + self['key_green'] = StaticText(_('Channels')) + self['key_yellow'] = StaticText(_('Download')) + self['key_blue'] = StaticText(_('Search')) + + self['description'] = Label('') + self['date'] = Label('') + self['sresult'] = Label('') + + self['list'] = List() + self['list'].style = 'movie_list' + self.list = [] + self.currindex = 0 + self.queryInfo = {} + + self['actions'] = ActionMap( + ['MTC_Actions'], + { + 'ok': self.pressOk, + 'cancel': self.pressClose, + 'red': self.pressRed, + 'green': self.pressGreen, + 'yellow': self.pressYellow, + 'blue': self.pressBlue, + 'menu': self.pressMenu, + 'info': self.pressInfo + } + ) + self['list'].onSelectionChanged.append(self.__SelectionChanged) + self.onLayoutFinish.append(self.__onLayoutFinish) + self.download = MyDeferredSemaphore(tokens=1) + + def __onLayoutFinish(self): + logger.info("...") + self.postdata['offset'] = 0 + self.downloadPage() + + def downloadPage(self): + logger.info("...") + url = 'https://mediathekviewweb.de/api/query' + self.download.start(MyGetPage, url=url, method='POST', postdata=json.dumps(self.postdata), headers=headersplain).addCallback(self.downloadSucceeded).addErrback(self.downloadFailed) + + def downloadSucceeded(self, result): + logger.info("...") + if result: + data = json.loads(result) + logger.debug("data: %s", data) + if not data.get('error'): + logger.debug("data available") + self.queryInfo = data['result']['queryInfo'] + self.queryInfo['filmlisteTimestamp'] = datetime.fromtimestamp(int(self.queryInfo['filmlisteTimestamp'])).strftime('%d.%m.%Y %H:%M:%S') + logger.debug("queryInfo: %s", self.queryInfo) + results = data['result']['results'] + logger.debug("results: %s", results) + for x in results: + logger.debug("x: %s") + tmp = listempty[:] + if 'timestamp' in x: + dtmp = datetime.fromtimestamp(int(x['timestamp'])).strftime('%d.%m.%Y %H:%M:%S') + tmp[LIST_DATE] = dtmp[0:10] + tmp[LIST_TIME] = dtmp[11:16] + if 'duration' in x: + tmp[LIST_DURATION] = str(timedelta(seconds=x['duration'] or 0)) + if 'channel' in x: + name = x['channel'].encode('utf-8') + ptr = loadPixmap('%slogos/%s.png' % (plugindir, name.replace(' ', '').upper())) + tmp[LIST_CHANNEL] = name + tmp[LIST_CHANNELPIXMAP] = ptr + if 'topic' in x: + tmp[LIST_TOPIC] = x['topic'].encode('utf-8') + if 'title' in x: + tmp[LIST_TITLE] = x['title'].encode('utf-8') + if 'description' in x: + tmp[LIST_DESCRIPTION] = x['description'].encode('utf-8') + if 'size' in x: + tmp[LIST_SIZE] = int(x['size'] or 0) / (1024 * 1024) + if 'id' in x: + tmp[LIST_ID] = x['id'] + if 'url_video_low' in x: + tmp[LIST_URL_VIDEO_LOW] = x['url_video_low'] + if 'url_video' in x: + tmp[LIST_URL_VIDEO] = x['url_video'] + if 'url_video_hd' in x: + tmp[LIST_URL_VIDEO_HD] = x['url_video_hd'] + if 'url_website' in x: + tmp[LIST_URL_WEBSITE] = x['url_website'] + logger.debug("tmp: %s", tmp) + self.list.append(tmp) + + math = min(self.postdata['offset'] + self.queryInfo['resultCount'], self.queryInfo['totalResults']) + if self.queryInfo['totalResults'] != math: + addtmp = listempty[:] + addtmp[LIST_CHANNEL] = '>>>' + addtmp[LIST_TOPIC] = _('Next page') + addtmp[LIST_TITLE] = _('Select') + addtmp[LIST_DATE] = '>>>' + logger.debug("addtmp: %s", addtmp) + self.list.append(addtmp) + # logger.info("list: %s", self.list) + self["list"].setList(self.list) + self['list'].changed((self['list'].CHANGED_ALL,)) + logger.debug("setIndex: %s", self.currindex) + self['list'].setIndex(self.currindex) + self.set_sresult() + + def downloadFailed(self, failure, *args): + logger.info("...") + error_message = str(failure.getErrorMessage()) + if not error_message: + error_message = str(failure) + logger.error("%s, %s", error_message, str(args)) + if 'CancelledError' not in error_message: + self.session.open(MessageBox, error_message, MessageBox.TYPE_INFO, timeout=10, title=_('Download failed')) + + def __SelectionChanged(self): + logger.info("...") + self['description'].setText('') + self['date'].setText('') + self.curr = self['list'].getCurrent() + if self.curr and self.curr[LIST_CHANNEL] != '>>>': + self['description'].setText(self.curr[LIST_DESCRIPTION]) + # size = self.curr[LIST_SIZE] + # size_text = '%d MB' % size if size else '' + resolutions = self.getVideoResolutions() + self['date'].setText( + '%s: %s %s\n%s: %s\n%s: %s' % ( + _("Broadcast time"), self.curr[LIST_DATE], self.curr[LIST_TIME], + _('Duration'), self.curr[LIST_DURATION], + _("Quality"), ", ".join(resolutions) + ) + ) + + def pressOk(self): + if self.curr: + if self.curr[LIST_CHANNEL] == '>>>': + self.currindex = self["list"].getIndex() + logger.debug("getIndex: %s", self.currindex) + self.postdata['offset'] += config.plugins.mediathekcockpit.size.value + self["list"].list.remove(self.curr) + del self.list[len(self.list) - 1] + self.downloadPage() + else: + val = int(config.plugins.mediathekcockpit.movie_resolution.value) + url, _resolution = self.getVideoUrl(self.curr, val) + if url: + url = url.encode('utf-8') + if self.curr[LIST_TOPIC].replace('&', 'und').upper() not in self.curr[LIST_TITLE].replace('&', 'und').upper(): + self.name = self.curr[LIST_TOPIC] + ' ' + self.curr[LIST_TITLE] + else: + self.name = self.curr[LIST_TITLE] + + if '.m3u8' in url: + self.download.start(MyGetPage, url=url, headers=_headers, location=True).addCallback(self.m3u8checkback, self.playm3u8).addErrback(self.downloadFailed) + elif url.endswith(('mp4', 'flv')): + self.playm3u8(url) + + def playm3u8(self, url, suburi=None): + logger.info("...") + sref = eServiceReference(eServiceReference.idGST, 0, url.encode('utf-8')) + if self.curr[LIST_CHANNEL].upper() not in self.name.upper(): + sref.setName('%s: %s' % (self.curr[LIST_CHANNEL].encode('utf-8'), self.name.encode('utf-8'))) + else: + sref.setName('%s' % self.name.encode('utf-8')) + if suburi: + sref.setSuburi(suburi.encode('utf-8')) + self.session.open(MoviePlayer, sref, menuval=None, infoval=(EventView, self.curr)) + + def m3u8checkback(self, result, play): + logger.info("...") + m3u8 = result[0] + url = result[1] + if '#EXTM3U' in m3u8: + m3u8res = M3U8Parser(m3u8, url) + if m3u8res.extxmedia_play(): + play(url) + elif m3u8res.extxmedia_parse(): + urlval, suburi = m3u8res.parser_all() + if urlval: + play(urlval, suburi) + + def checkVideoUrl(self, was): + return self.curr[was] and self.curr[was].startswith('http') + + def getVideoResolutions(self): + resolutions = [] + if self.checkVideoUrl(LIST_URL_VIDEO_LOW): + resolutions.append(_('Low')) + if self.checkVideoUrl(LIST_URL_VIDEO): + resolutions.append(_('Medium')) + if self.checkVideoUrl(LIST_URL_VIDEO_HD): + resolutions.append(_('High')) + return resolutions + + def getVideoUrl(self, curr, val): + url = "" + resolution_text = "" + resolutions = [val] + VIDEO_RESOLUTIONS + for resolution in resolutions: + if curr[resolution] and curr[resolution].startswith('http'): + url = curr[resolution] + resolution_text = VIDEO_RESOLUTIONS_DICT[resolution] + break + return url, resolution_text + + def set_sresult(self): + logger.info("...") + if self.queryInfo: + math = min(self.postdata['offset'] + self.queryInfo['resultCount'], self.queryInfo['totalResults']) + self['sresult'].setText('%s: %s/%s\n%s: %s ms\n%s: %s' % ( + _('Entries'), math, str(self.queryInfo['totalResults']), + _('Load time'), str(self.queryInfo['searchEngineTime']), + _('From'), str(self.queryInfo['filmlisteTimestamp'])) + ) + + def pressRed(self): + self.close("streams") + + def pressGreen(self): + self.close("channels") + + def pressYellow(self): + logger.info("...") + path = config.plugins.mediathekcockpit.moviesavedir.value + if os.path.exists(path): + url, resolution = self.getVideoUrl(self.curr, int(config.plugins.mediathekcockpit.movie_resolution.value)) + if self.curr[LIST_TOPIC].replace('&', 'und').upper() not in self.curr[LIST_TITLE].replace('&', 'und').upper(): + name = self.curr[LIST_TOPIC].encode('utf-8') + ' ' + self.curr[LIST_TITLE].encode('utf-8') + else: + name = self.curr[LIST_TITLE].encode('utf-8') + description = self.curr[LIST_DESCRIPTION].encode('utf-8') + # datestring = datetime.now().strftime('%Y%m%d - ') + p = re.compile('[.:,!/]') + disname = name + name = p.sub('', name) + url = url.encode('utf-8') + formatval = '.mp4' + pos = url.rfind('.') + if pos != -1: + formatval = url[pos:] + recordfilename = getRecordingFilename(name, path.encode('utf-8')) + downloadManager.AddJob(DownloadJob(url, recordfilename + formatval, disname, description, headers_ts)) + self.session.open( + MessageBox, '%s:\n\n%s\n\n%s: %s' % ( + _('Download added'), + disname, + _('Video resolution'), resolution, + ), + type=MessageBox.TYPE_INFO, + timeout=4 + ) + else: + self.session.open(MessageBox, _("Movie directory does not exist") + ":\n\n" + path, type=MessageBox.TYPE_ERROR) + + def pressBlue(self): + self.close("search") + + def pressMenu(self): + Menu(self.session, self.postdata) + + def pressInfo(self): + if self.curr and self.curr[LIST_CHANNEL] != '>>>': + self.session.open(EventView, self.curr) + + def pressClose(self): + logger.info("...") + self.close("exit") diff --git a/src/MyDeferredSemaphore.py b/src/MyDeferredSemaphore.py index 88ce78a..90fcdc9 100644 --- a/src/MyDeferredSemaphore.py +++ b/src/MyDeferredSemaphore.py @@ -1,3 +1,24 @@ +#!/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 twisted.internet import reactor from twisted.internet.defer import Deferred, DeferredSemaphore from .Debug import logger @@ -12,7 +33,7 @@ def MyCallLater(acallable, *args, **kwargs): return reactor.callLater(0, acallable, *args, **kwargs) -def MydeferLater(acallable, *args, **kw): +def MyDeferLater(acallable, *args, **kw): logger.info("...") def deferLaterCancel(_deferred): @@ -49,7 +70,7 @@ def run(self, *args, **kwargs): def rundeferLater(self, _ltime, *args, **kwargs): logger.info("...") - return MydeferLater(self._ds.run, *args, **kwargs) + return MyDeferLater(self._ds.run, *args, **kwargs) def start(self, *args, **kwargs): logger.info("...") diff --git a/src/MyJobManager.py b/src/MyJobManager.py old mode 100644 new mode 100755 index 2540ee1..9670e0f --- a/src/MyJobManager.py +++ b/src/MyJobManager.py @@ -1,3 +1,24 @@ +#!/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.Task import Task, Job, JobManager from Downloader import mydownloadWithProgress @@ -7,16 +28,17 @@ from Plugins.SystemPlugins.CacheCockpit.FileManager import FileManager cachecockpit = True except Exception: - logger.Error("import error") + logger.error("CacheCockpit import error") cachecockpit = False class DownloadJob(Job): - def __init__(self, url, file, title, description, headers): + def __init__(self, url, file_name, title, description, headers): logger.info("...") Job.__init__(self, title) - DownloadTask(self, url, file, description, headers) + self.file_name = file_name + DownloadTask(self, url, file_name, description, headers) def gettotalbytes(self): logger.info("...") @@ -36,14 +58,14 @@ def getrecvbytes(self): class DownloadTask(Task): totalbytes = recvbytes = 0 - def __init__(self, job, url, fileName, description, headers): - logger.info("job: %s, url: %s, fileName: %s, description: %s", job, url, fileName, description) + def __init__(self, job, url, file_name, description, headers): + logger.info("job: %s, url: %s, file_name: %s, description: %s", job, url, file_name, description) self.description = description Task.__init__(self, job, 'download task') self.headers = headers self.end = 100 self.url = url - self.local = fileName + self.local = file_name self.download = None def prepare(self): @@ -68,8 +90,7 @@ def http_progress(self, recvbytes, totalbytes): self.recvbytes, self.totalbytes = recvbytes, totalbytes def response_headers(self, response_headers): - logger.info("...") - print(response_headers) + logger.info("response_headers: %s", response_headers) def http_finished(self, _string): logger.info("...") diff --git a/src/Search.py b/src/Search.py new file mode 100644 index 0000000..b0df10b --- /dev/null +++ b/src/Search.py @@ -0,0 +1,50 @@ +#!/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.VirtualKeyBoard import VirtualKeyBoard +from .Debug import logger +from .__init__ import _ + + +class Search(): + def __init__(self, session, callback): + self.session = session + self.callback = callback + + def openKeyboard(self, query, postdata): + logger.info("query: %s", query) + self.postdata = postdata + self.session.openWithCallback(self.resulttext, VirtualKeyBoard, title=_('Enter search text'), text=query) + + def resulttext(self, result=None): + logger.info("result: %s", result) + if result: + self.search(result) + + def search(self, name='', fields=None): + if fields is None: + fields = ['topic', 'title'] + logger.info("name: %s, fields: %s", name, fields) + if name: + self.postdata['offset'] = 0 + self.postdata['queries'] = list() + self.postdata['queries'].append({'fields': fields, 'query': name.encode('utf-8')}) + self.callback(self.postdata) diff --git a/src/SearchUtils.py b/src/SearchUtils.py deleted file mode 100644 index 6667b51..0000000 --- a/src/SearchUtils.py +++ /dev/null @@ -1,46 +0,0 @@ -import json -from Tools.Directories import pathExists -from .Debug import logger -from .Constants import enigma2configdir, listfields, listsearchquerys -from .__init__ import _ - - -searchquerysfile = enigma2configdir + 'mv_searchquerys.json' - - -def convert_searchquerys(data): - logger.info("...") - name = '' - channel = [] - fields = '' - for queriesres in data: - if queriesres.get('fields') == listfields['channel']: - channel.append(queriesres['query'].encode('utf-8')) - elif queriesres.get('fields') != listfields['channel']: - name = queriesres['query'].encode('utf-8') - for x in queriesres['fields']: - fields += _(x.encode('utf-8')) + ' ' - - if not channel: - channel = [_('All')] - return (name, fields, (', ').join(channel), data) - - -def read_searchquerys(): - logger.info("...") - searchquerys = [] - if pathExists(searchquerysfile): - with open(searchquerysfile) as (data_file): - data = json.load(data_file) - for query in data: - searchquerys.append(convert_searchquerys(query)) - return searchquerys - - -def write_searchquerys(searchquerys): - logger.info("...") - with open(searchquerysfile, 'w') as (fp): - result = [] - for value in searchquerys: - result.append(value[listsearchquerys['queries']]) - json.dump(result, fp, encoding='utf-8', indent=2, sort_keys=True) diff --git a/src/Settings.py b/src/Settings.py new file mode 100644 index 0000000..533cb8d --- /dev/null +++ b/src/Settings.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: +# . + + +from Screens.Screen import Screen +from Components.ActionMap import ActionMap +from Components.Sources.StaticText import StaticText +from Components.ConfigList import ConfigListScreen +from Components.config import config, configfile, getConfigListEntry, KEY_OK +from Tools.Directories import pathExists +from .DirBrowser import DirBrowser +from .__init__ import _ +from .Debug import logger + + +class Settings(Screen, ConfigListScreen): + + def __init__(self, session, postdata): + logger.info("...") + self.postdata = postdata + Screen.__init__(self, session, windowTitle=_('MediathekCockpit') + ' - ' + _('Setup')) + ConfigListScreen.__init__(self, [], session=session) + self.skinName = 'MTCSetup' + self['key_red'] = StaticText(_('Cancel')) + self['key_green'] = StaticText(_('Save')) + self['actions'] = ActionMap( + ['SetupActions', 'ColorActions'], + { + 'cancel': self.keyCancel, + 'save': self.keySave + } + ) + self._createSetup() + + def _createSetup(self): + logger.info("...") + self['config'].setList( + [ + getConfigListEntry(_('Entries per page'), config.plugins.mediathekcockpit.size), + getConfigListEntry(_('Show future movies'), config.plugins.mediathekcockpit.future), + getConfigListEntry(_('Video resolution'), config.plugins.mediathekcockpit.movie_resolution), + getConfigListEntry(_('Behavior when movie stopped'), config.plugins.mediathekcockpit.askstopmovie), + getConfigListEntry(_('Movie path'), config.plugins.mediathekcockpit.moviesavedir) + ] + ) + + def keyOK(self): + logger.info("...") + curr = self['config'].getCurrent() + if curr and curr[1] == config.plugins.mediathekcockpit.moviesavedir: + self.session.openWithCallback(self.LocationBoxCallback, DirBrowser, config.plugins.mediathekcockpit.moviesavedir.value) + else: + self['config'].handleKey(KEY_OK) + + def LocationBoxCallback(self, res): + logger.info("res: %s", res) + if res: + if pathExists(res): + config.plugins.mediathekcockpit.moviesavedir.value = res + + def keySave(self): + logger.info("...") + if self['config'].isChanged(): + config.plugins.mediathekcockpit.save() + configfile.save() + self.postdata['size'] = int(config.plugins.mediathekcockpit.size.value) + self.postdata['future'] = config.plugins.mediathekcockpit.future.value + self.postdata['offset'] = 0 + self.close(self.postdata) + else: + self.close(False) diff --git a/src/Version.py b/src/Version.py index 5ed3e52..c0e0ce5 100644 --- a/src/Version.py +++ b/src/Version.py @@ -21,6 +21,6 @@ PLUGIN = "MediathekCockpit" ID = "MTC" -VERSION = "0.1.2" +VERSION = "0.2.5" 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/keymap.xml b/src/keymap.xml index 6e9b9e2..dc2e03a 100644 --- a/src/keymap.xml +++ b/src/keymap.xml @@ -1,5 +1,5 @@ - + diff --git a/src/plugin.py b/src/plugin.py index e080bfd..61922bd 100644 --- a/src/plugin.py +++ b/src/plugin.py @@ -30,12 +30,12 @@ def search(session, query, **__kwargs): - session.open(MediathekCockpit, query) + MediathekCockpit(session, query) def main(session, **__kwargs): logger.info("...") - session.open(MediathekCockpit) + MediathekCockpit(session, "") def showDownloads(session, event="", service="", **_kwargs): @@ -47,8 +47,7 @@ def showDownloads(session, event="", service="", **_kwargs): 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) - # session.open(ScreenMain, event_name, 2) - session.open(MediathekCockpit, event_name) + MediathekCockpit(session, event_name) def autoStart(reason, **kwargs): diff --git a/src/skin/Default-FHD/skin.xml b/src/skin/Default-FHD/skin.xml index 781f554..7cfc33d 100644 --- a/src/skin/Default-FHD/skin.xml +++ b/src/skin/Default-FHD/skin.xml @@ -19,36 +19,30 @@ - - {"templates": {"default":(68,[ MultiContentEntryText(pos=(100,0),size=(1160,68),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = 0, backcolor=None), MultiContentEntryPixmapAlphaTest(pos=(5,5),size=(60,60),png=2, backcolor=None), MultiContentEntryText(pos = (0,67),size = (1259,1),font=0,flags = RT_VALIGN_CENTER,text = "", backcolor=0xa0a0a0) ]), "movi_liste":(68,[ MultiContentEntryText(pos=(65,0),size=(200,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = 0, color=0xa6781c, color_sel=0xa6781c, backcolor=None), MultiContentEntryPixmapAlphaTest(pos=(5,5),size=(50,50),png=8, backcolor=None), MultiContentEntryText(pos=(65,34),size=(130,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = 5, color=0xa0a0a0, color_sel=0xa0a0a0, backcolor=None), MultiContentEntryText(pos = (330,0),size = (930,34),font=2,flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = 1, backcolor=None), MultiContentEntryText(pos = (330,34),size = (930,34),font=0,flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = 2, color=0xa0a0a0, color_sel=0xa0a0a0, backcolor=None), MultiContentEntryText(pos = (205,34),size = (60,34),font=1,flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = 4, color=0xa0a0a0, color_sel=0xa0a0a0, backcolor=None), MultiContentEntryText(pos = (275,34),size = (40,34),font=1,flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = 9, color=0xa0a0a0, color_sel=0xa0a0a0, backcolor=None), MultiContentEntryText(pos = (0,67),size = (1259,1),font=0,flags = RT_VALIGN_CENTER,text = "", backcolor=0xa0a0a0), ]), "search_querys":(68,[ MultiContentEntryText(pos=(0,0),size=(160,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = _("Search for:"), backcolor=None), MultiContentEntryText(pos=(300,0),size=(960,34),font=2,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = 0, backcolor=None), MultiContentEntryText(pos=(0,34),size=(160,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = _("fields:"), backcolor=None), MultiContentEntryText(pos=(120,34),size=(330,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = 1, backcolor=None), MultiContentEntryText(pos=(450,34),size=(100,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = _("channels:"), backcolor=None), MultiContentEntryText(pos=(560,34),size=(700,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = 2, backcolor=None), MultiContentEntryText(pos = (0,67),size = (1259,1),font=0,flags = RT_VALIGN_CENTER,text = "", backcolor=0xa0a0a0) ]) }, "fonts": [gFont("Regular",25),gFont("Regular",22),gFont("Regular",28)], "itemHeight": 60 } + + {"templates": {"default":(68,[ MultiContentEntryText(pos=(100,0),size=(1160,68),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0, backcolor=None), MultiContentEntryPixmapAlphaTest(pos=(5,5),size=(60,60),png=2, backcolor=None), MultiContentEntryText(pos=(0,67),size=(1259,1),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0) ]), "movie_list":(68,[ MultiContentEntryText(pos=(65,0),size=(200,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0, color=0xa6781c, color_sel=0xa6781c, backcolor=None), MultiContentEntryPixmapAlphaTest(pos=(5,5),size=(50,50),png=8, backcolor=None), MultiContentEntryText(pos=(65,34),size=(130,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=5, color=0xa0a0a0, color_sel=0xa0a0a0, backcolor=None), MultiContentEntryText(pos=(330,0),size=(930,34),font=2,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1, backcolor=None), MultiContentEntryText(pos=(330,34),size=(930,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=2, color=0xa0a0a0, color_sel=0xa0a0a0, backcolor=None), MultiContentEntryText(pos=(205,34),size=(60,34),font=1,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=4, color=0xa0a0a0, color_sel=0xa0a0a0, backcolor=None), MultiContentEntryText(pos=(275,34),size=(40,34),font=1,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=9, color=0xa0a0a0, color_sel=0xa0a0a0, backcolor=None), MultiContentEntryText(pos=(0,67),size=(1259,1),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0), ]), "search_querys":(68,[ MultiContentEntryText(pos=(0,0),size=(160,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=_("Search for:"), backcolor=None), MultiContentEntryText(pos=(300,0),size=(960,34),font=2,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0, backcolor=None), MultiContentEntryText(pos=(0,34),size=(160,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=_("fields:"), backcolor=None), MultiContentEntryText(pos=(120,34),size=(330,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1, backcolor=None), MultiContentEntryText(pos=(450,34),size=(100,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=_("channels:"), backcolor=None), MultiContentEntryText(pos=(560,34),size=(700,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=2, backcolor=None), MultiContentEntryText(pos=(0,67),size=(1259,1),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0) ]) }, "fonts": [gFont("Regular",25),gFont("Regular",22),gFont("Regular",28)], "itemHeight": 60 } - + - - + - - - - + + + + - - + + - - - - # this should be factored out into some helper code,but currently demonstrates applets. from enigma import eSize,ePoint orgwidth=self.instance.size().width() orgpos=self.instance.position() textsize=self["text"].getSize() # y size still must be fixed in font stuff... textsize=(textsize[0] + 80,textsize[1] + 100) count=len(self.list) if count > 15: count=15 offset=45 * count wsizex=textsize[0] + 100 wsizey=textsize[1] + offset + 20 if (1180 > wsizex): wsizex=1180 wsize=(wsizex,wsizey) # resize self.instance.resize(eSize(*wsize)) # resize label self["text"].instance.resize(eSize(*textsize)) # move list listsize=(wsizex - 20,45 * count) self["list"].instance.move(ePoint(10,textsize[1])) self["list"].instance.resize(eSize(*listsize))#200d1940 # center window newwidth=wsize[0] self.instance.move(ePoint((1920-wsizex)/2,(1080-wsizey)/2)) - - + @@ -57,45 +51,29 @@ - - {"template": [ MultiContentEntryText(pos=(5,0),size=(1180,40),flags=RT_HALIGN_LEFT,font=0, text=0, backcolor=None), MultiContentEntryText(pos=(5,40),size=(200,40),flags=RT_HALIGN_LEFT,font=0, text=1, backcolor=None), MultiContentEntryProgress(pos=(250,42),size=(500,20),percent=-2, borderWidth=1, foreColor=0xe6bd00, backColor=0xe6bd00), MultiContentEntryText(pos=(800,40),size=(400,40),flags=RT_HALIGN_LEFT,font=0, text=3, backcolor=None), MultiContentEntryText(pos = (0,79),size = (1179,1),font=0,flags = RT_VALIGN_CENTER,text = "", backcolor=0xa0a0a0), ], "fonts": [gFont("Regular",28)], "itemHeight": 80 } + + {"template": [ MultiContentEntryText(pos=(5,0),size=(1180,40),flags=RT_HALIGN_LEFT,font=0, text=0, backcolor=None), MultiContentEntryText(pos=(5,40),size=(200,40),flags=RT_HALIGN_LEFT,font=0, text=1, backcolor=None), MultiContentEntryProgress(pos=(250,42),size=(500,20),percent=-2, borderWidth=1, foreColor=0xe6bd00, backColor=0xe6bd00), MultiContentEntryText(pos=(800,40),size=(400,40),flags=RT_HALIGN_LEFT,font=0, text=3, backcolor=None), MultiContentEntryText(pos=(0,79),size=(1179,1),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0), ], "fonts": [gFont("Regular",28)], "itemHeight": 80 } - - - - 0,8,0 - - - 0,6,1 - - - 1,8,1 - - - 2 - - - 4 - - - 5 - + + + + - + - + Name - MvVideoInfo + MTCVideoInfo @@ -129,13 +107,13 @@ - + Name - MvVideoInfo + MTCVideoInfo @@ -196,4 +174,25 @@ EndTime,ShowNoSeconds + + + + 0,8,0 + + + 0,6,1 + + + 1,8,1 + + + 2 + + + 4 + + + 5 + + diff --git a/src/skin/Default-HD/skin.xml b/src/skin/Default-HD/skin.xml index f45d3dc..a56848c 100644 --- a/src/skin/Default-HD/skin.xml +++ b/src/skin/Default-HD/skin.xml @@ -19,36 +19,30 @@ - - {"templates":{"default":(45,[MultiContentEntryText(pos=(67,0),size=(773,45),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0,backcolor=None),MultiContentEntryPixmapAlphaTest(pos=(3,3),size=(40,40),png=2,backcolor=None),MultiContentEntryText(pos=((,,)),size=((,,)),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0)]),"movi_liste":(45,[MultiContentEntryText(pos=(43,0),size=(133,23),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0,color=0xa6781c,color_sel=0xa6781c,backcolor=None),MultiContentEntryPixmapAlphaTest(pos=(3,3),size=(33,33),png=8,backcolor=None),MultiContentEntryText(pos=(43,23),size=(87,23),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=5,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=((,,)),size=((,,)),font=2,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1,backcolor=None),MultiContentEntryText(pos=((,,)),size=((,,)),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=2,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=((,,)),size=((,,)),font=1,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=4,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=((,,)),size=((,,)),font=1,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=9,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=((,,)),size=((,,)),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),]),"search_querys":(45,[MultiContentEntryText(pos=(0,0),size=(107,23),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=_("Search for:"),backcolor=None),MultiContentEntryText(pos=(200,0),size=(640,23),font=2,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0,backcolor=None),MultiContentEntryText(pos=(0,23),size=(107,23),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=_("fields:"),backcolor=None),MultiContentEntryText(pos=(80,23),size=(220,23),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1,backcolor=None),MultiContentEntryText(pos=(300,23),size=(67,23),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=_("channels:"),backcolor=None),MultiContentEntryText(pos=(373,23),size=(467,23),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=2,backcolor=None),MultiContentEntryText(pos=((,,)),size=((,,)),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0)])},"fonts":[gFont("Regular",17),gFont("Regular",15),gFont("Regular",19)],"itemHeight":40} + + {"templates":{"default":(45,[MultiContentEntryText(pos=(67,0),size=(773,45),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0,backcolor=None),MultiContentEntryPixmapAlphaTest(pos=(3,3),size=(40,40),png=2,backcolor=None),MultiContentEntryText(pos=(0,45),size=(839,1),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0)]),"movie_list":(45,[MultiContentEntryText(pos=(43,0),size=(133,23),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0,color=0xa6781c,color_sel=0xa6781c,backcolor=None),MultiContentEntryPixmapAlphaTest(pos=(3,3),size=(33,33),png=8,backcolor=None),MultiContentEntryText(pos=(43,23),size=(87,23),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=5,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=(220,0),size=(620,23),font=2,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1,backcolor=None),MultiContentEntryText(pos=(220,23),size=(620,23),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=2,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=(137,23),size=(40,23),font=1,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=4,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=(183,23),size=(27,23),font=1,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=9,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=(0,45),size=(839,1),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),]),"search_querys":(45,[MultiContentEntryText(pos=(0,0),size=(107,23),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=_("Search for:"),backcolor=None),MultiContentEntryText(pos=(200,0),size=(640,23),font=2,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0,backcolor=None),MultiContentEntryText(pos=(0,23),size=(107,23),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=_("fields:"),backcolor=None),MultiContentEntryText(pos=(80,23),size=(220,23),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1,backcolor=None),MultiContentEntryText(pos=(300,23),size=(67,23),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=_("channels:"),backcolor=None),MultiContentEntryText(pos=(373,23),size=(467,23),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=2,backcolor=None),MultiContentEntryText(pos=(0,45),size=(839,1),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0)])},"fonts":[gFont("Regular",17),gFont("Regular",15),gFont("Regular",19)],"itemHeight":40} - + - - + - - - - + + + + - - + + - - - - # this should be factored out into some helper code,but currently demonstrates applets. from enigma import eSize,ePoint orgwidth=self.instance.size().width() orgpos=self.instance.position() textsize=self["text"].getSize() # y size still must be fixed in font stuff... textsize=(textsize[0] + 80,textsize[1] + 100) count=len(self.list) if count > 15: count=15 offset=45 * count wsizex=textsize[0] + 100 wsizey=textsize[1] + offset + 20 if (1180 > wsizex): wsizex=1180 wsize=(wsizex,wsizey) # resize self.instance.resize(eSize(*wsize)) # resize label self["text"].instance.resize(eSize(*textsize)) # move list listsize=(wsizex - 20,45 * count) self["list"].instance.move(ePoint(10,textsize[1])) self["list"].instance.resize(eSize(*listsize))#200d1940 # center window newwidth=wsize[0] self.instance.move(ePoint((1920-wsizex)/2,(1080-wsizey)/2)) - - + @@ -57,45 +51,29 @@ - - {"template":[MultiContentEntryText(pos=(3,0),size=(787,27),flags=RT_HALIGN_LEFT,font=0,text=0,backcolor=None),MultiContentEntryText(pos=(3,27),size=(133,27),flags=RT_HALIGN_LEFT,font=0,text=1,backcolor=None),MultiContentEntryProgress(pos=(167,28),size=(333,13),percent=-2,borderWidth=1,foreColor=0xe6bd00,backColor=0xe6bd00),MultiContentEntryText(pos=(533,27),size=(267,27),flags=RT_HALIGN_LEFT,font=0,text=3,backcolor=None),MultiContentEntryText(pos=((,,)),size=((,,)),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),],"fonts":[gFont("Regular",19)],"itemHeight":53} + + {"template":[MultiContentEntryText(pos=(3,0),size=(787,27),flags=RT_HALIGN_LEFT,font=0,text=0,backcolor=None),MultiContentEntryText(pos=(3,27),size=(133,27),flags=RT_HALIGN_LEFT,font=0,text=1,backcolor=None),MultiContentEntryProgress(pos=(167,28),size=(333,13),percent=-2,borderWidth=1,foreColor=0xe6bd00,backColor=0xe6bd00),MultiContentEntryText(pos=(533,27),size=(267,27),flags=RT_HALIGN_LEFT,font=0,text=3,backcolor=None),MultiContentEntryText(pos=(0,53),size=(786,1),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),],"fonts":[gFont("Regular",19)],"itemHeight":53} - - - - 0,8,0 - - - 0,6,1 - - - 1,8,1 - - - 2 - - - 4 - - - 5 - + + + + - + - + Name - MvVideoInfo + MTCVideoInfo @@ -129,13 +107,13 @@ - + Name - MvVideoInfo + MTCVideoInfo @@ -196,4 +174,25 @@ EndTime,ShowNoSeconds + + + + 0,8,0 + + + 0,6,1 + + + 1,8,1 + + + 2 + + + 4 + + + 5 + + diff --git a/src/skin/Default-WQHD/skin.xml b/src/skin/Default-WQHD/skin.xml index 5df5781..a1638d7 100644 --- a/src/skin/Default-WQHD/skin.xml +++ b/src/skin/Default-WQHD/skin.xml @@ -19,36 +19,30 @@ - - {"templates":{"default":(91,[MultiContentEntryText(pos=(133,0),size=(1547,91),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0,backcolor=None),MultiContentEntryPixmapAlphaTest(pos=(7,7),size=(80,80),png=2,backcolor=None),MultiContentEntryText(pos=((,,)),size=((,,)),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0)]),"movi_liste":(91,[MultiContentEntryText(pos=(87,0),size=(267,45),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0,color=0xa6781c,color_sel=0xa6781c,backcolor=None),MultiContentEntryPixmapAlphaTest(pos=(7,7),size=(67,67),png=8,backcolor=None),MultiContentEntryText(pos=(87,45),size=(173,45),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=5,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=((,,)),size=((,,)),font=2,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1,backcolor=None),MultiContentEntryText(pos=((,,)),size=((,,)),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=2,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=((,,)),size=((,,)),font=1,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=4,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=((,,)),size=((,,)),font=1,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=9,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=((,,)),size=((,,)),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),]),"search_querys":(91,[MultiContentEntryText(pos=(0,0),size=(213,45),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=_("Search for:"),backcolor=None),MultiContentEntryText(pos=(400,0),size=(1280,45),font=2,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0,backcolor=None),MultiContentEntryText(pos=(0,45),size=(213,45),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=_("fields:"),backcolor=None),MultiContentEntryText(pos=(160,45),size=(440,45),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1,backcolor=None),MultiContentEntryText(pos=(600,45),size=(133,45),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=_("channels:"),backcolor=None),MultiContentEntryText(pos=(747,45),size=(933,45),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=2,backcolor=None),MultiContentEntryText(pos=((,,)),size=((,,)),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0)])},"fonts":[gFont("Regular",33),gFont("Regular",29),gFont("Regular",37)],"itemHeight":80} + + {"templates":{"default":(91,[MultiContentEntryText(pos=(133,0),size=(1547,91),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0,backcolor=None),MultiContentEntryPixmapAlphaTest(pos=(7,7),size=(80,80),png=2,backcolor=None),MultiContentEntryText(pos=(0,89),size=(1679,1),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0)]),"movie_list":(91,[MultiContentEntryText(pos=(87,0),size=(267,45),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0,color=0xa6781c,color_sel=0xa6781c,backcolor=None),MultiContentEntryPixmapAlphaTest(pos=(7,7),size=(67,67),png=8,backcolor=None),MultiContentEntryText(pos=(87,45),size=(173,45),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=5,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=(440,0),size=(1240,45),font=2,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1,backcolor=None),MultiContentEntryText(pos=(440,45),size=(1240,45),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=2,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=(273,45),size=(80,45),font=1,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=4,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=(367,45),size=(53,45),font=1,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=9,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=(0,89),size=(1679,1),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),]),"search_querys":(91,[MultiContentEntryText(pos=(0,0),size=(213,45),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=_("Search for:"),backcolor=None),MultiContentEntryText(pos=(400,0),size=(1280,45),font=2,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0,backcolor=None),MultiContentEntryText(pos=(0,45),size=(213,45),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=_("fields:"),backcolor=None),MultiContentEntryText(pos=(160,45),size=(440,45),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1,backcolor=None),MultiContentEntryText(pos=(600,45),size=(133,45),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=_("channels:"),backcolor=None),MultiContentEntryText(pos=(747,45),size=(933,45),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=2,backcolor=None),MultiContentEntryText(pos=(0,89),size=(1679,1),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0)])},"fonts":[gFont("Regular",33),gFont("Regular",29),gFont("Regular",37)],"itemHeight":80} - + - - + - - - - + + + + - - + + - - - - # this should be factored out into some helper code,but currently demonstrates applets. from enigma import eSize,ePoint orgwidth=self.instance.size().width() orgpos=self.instance.position() textsize=self["text"].getSize() # y size still must be fixed in font stuff... textsize=(textsize[0] + 80,textsize[1] + 100) count=len(self.list) if count > 15: count=15 offset=45 * count wsizex=textsize[0] + 100 wsizey=textsize[1] + offset + 20 if (1180 > wsizex): wsizex=1180 wsize=(wsizex,wsizey) # resize self.instance.resize(eSize(*wsize)) # resize label self["text"].instance.resize(eSize(*textsize)) # move list listsize=(wsizex - 20,45 * count) self["list"].instance.move(ePoint(10,textsize[1])) self["list"].instance.resize(eSize(*listsize))#200d1940 # center window newwidth=wsize[0] self.instance.move(ePoint((1920-wsizex)/2,(1080-wsizey)/2)) - - + @@ -57,45 +51,29 @@ - - {"template":[MultiContentEntryText(pos=(7,0),size=(1573,53),flags=RT_HALIGN_LEFT,font=0,text=0,backcolor=None),MultiContentEntryText(pos=(7,53),size=(267,53),flags=RT_HALIGN_LEFT,font=0,text=1,backcolor=None),MultiContentEntryProgress(pos=(333,56),size=(667,27),percent=-2,borderWidth=1,foreColor=0xe6bd00,backColor=0xe6bd00),MultiContentEntryText(pos=(1067,53),size=(533,53),flags=RT_HALIGN_LEFT,font=0,text=3,backcolor=None),MultiContentEntryText(pos=((,,)),size=((,,)),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),],"fonts":[gFont("Regular",37)],"itemHeight":107} + + {"template":[MultiContentEntryText(pos=(7,0),size=(1573,53),flags=RT_HALIGN_LEFT,font=0,text=0,backcolor=None),MultiContentEntryText(pos=(7,53),size=(267,53),flags=RT_HALIGN_LEFT,font=0,text=1,backcolor=None),MultiContentEntryProgress(pos=(333,56),size=(667,27),percent=-2,borderWidth=1,foreColor=0xe6bd00,backColor=0xe6bd00),MultiContentEntryText(pos=(1067,53),size=(533,53),flags=RT_HALIGN_LEFT,font=0,text=3,backcolor=None),MultiContentEntryText(pos=(0,105),size=(1572,1),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),],"fonts":[gFont("Regular",37)],"itemHeight":107} - - - - 0,8,0 - - - 0,6,1 - - - 1,8,1 - - - 2 - - - 4 - - - 5 - + + + + - + - + Name - MvVideoInfo + MTCVideoInfo @@ -129,13 +107,13 @@ - + Name - MvVideoInfo + MTCVideoInfo @@ -196,4 +174,25 @@ EndTime,ShowNoSeconds + + + + 0,8,0 + + + 0,6,1 + + + 1,8,1 + + + 2 + + + 4 + + + 5 + + diff --git a/src/skin/Other-WQHD/skin.xml b/src/skin/Other-WQHD/skin.xml index 5df5781..a1638d7 100644 --- a/src/skin/Other-WQHD/skin.xml +++ b/src/skin/Other-WQHD/skin.xml @@ -19,36 +19,30 @@ - - {"templates":{"default":(91,[MultiContentEntryText(pos=(133,0),size=(1547,91),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0,backcolor=None),MultiContentEntryPixmapAlphaTest(pos=(7,7),size=(80,80),png=2,backcolor=None),MultiContentEntryText(pos=((,,)),size=((,,)),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0)]),"movi_liste":(91,[MultiContentEntryText(pos=(87,0),size=(267,45),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0,color=0xa6781c,color_sel=0xa6781c,backcolor=None),MultiContentEntryPixmapAlphaTest(pos=(7,7),size=(67,67),png=8,backcolor=None),MultiContentEntryText(pos=(87,45),size=(173,45),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=5,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=((,,)),size=((,,)),font=2,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1,backcolor=None),MultiContentEntryText(pos=((,,)),size=((,,)),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=2,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=((,,)),size=((,,)),font=1,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=4,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=((,,)),size=((,,)),font=1,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=9,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=((,,)),size=((,,)),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),]),"search_querys":(91,[MultiContentEntryText(pos=(0,0),size=(213,45),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=_("Search for:"),backcolor=None),MultiContentEntryText(pos=(400,0),size=(1280,45),font=2,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0,backcolor=None),MultiContentEntryText(pos=(0,45),size=(213,45),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=_("fields:"),backcolor=None),MultiContentEntryText(pos=(160,45),size=(440,45),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1,backcolor=None),MultiContentEntryText(pos=(600,45),size=(133,45),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=_("channels:"),backcolor=None),MultiContentEntryText(pos=(747,45),size=(933,45),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=2,backcolor=None),MultiContentEntryText(pos=((,,)),size=((,,)),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0)])},"fonts":[gFont("Regular",33),gFont("Regular",29),gFont("Regular",37)],"itemHeight":80} + + {"templates":{"default":(91,[MultiContentEntryText(pos=(133,0),size=(1547,91),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0,backcolor=None),MultiContentEntryPixmapAlphaTest(pos=(7,7),size=(80,80),png=2,backcolor=None),MultiContentEntryText(pos=(0,89),size=(1679,1),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0)]),"movie_list":(91,[MultiContentEntryText(pos=(87,0),size=(267,45),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0,color=0xa6781c,color_sel=0xa6781c,backcolor=None),MultiContentEntryPixmapAlphaTest(pos=(7,7),size=(67,67),png=8,backcolor=None),MultiContentEntryText(pos=(87,45),size=(173,45),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=5,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=(440,0),size=(1240,45),font=2,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1,backcolor=None),MultiContentEntryText(pos=(440,45),size=(1240,45),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=2,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=(273,45),size=(80,45),font=1,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=4,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=(367,45),size=(53,45),font=1,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=9,color=0xa0a0a0,color_sel=0xa0a0a0,backcolor=None),MultiContentEntryText(pos=(0,89),size=(1679,1),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),]),"search_querys":(91,[MultiContentEntryText(pos=(0,0),size=(213,45),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=_("Search for:"),backcolor=None),MultiContentEntryText(pos=(400,0),size=(1280,45),font=2,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0,backcolor=None),MultiContentEntryText(pos=(0,45),size=(213,45),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=_("fields:"),backcolor=None),MultiContentEntryText(pos=(160,45),size=(440,45),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1,backcolor=None),MultiContentEntryText(pos=(600,45),size=(133,45),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=_("channels:"),backcolor=None),MultiContentEntryText(pos=(747,45),size=(933,45),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=2,backcolor=None),MultiContentEntryText(pos=(0,89),size=(1679,1),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0)])},"fonts":[gFont("Regular",33),gFont("Regular",29),gFont("Regular",37)],"itemHeight":80} - + - - + - - - - + + + + - - + + - - - - # this should be factored out into some helper code,but currently demonstrates applets. from enigma import eSize,ePoint orgwidth=self.instance.size().width() orgpos=self.instance.position() textsize=self["text"].getSize() # y size still must be fixed in font stuff... textsize=(textsize[0] + 80,textsize[1] + 100) count=len(self.list) if count > 15: count=15 offset=45 * count wsizex=textsize[0] + 100 wsizey=textsize[1] + offset + 20 if (1180 > wsizex): wsizex=1180 wsize=(wsizex,wsizey) # resize self.instance.resize(eSize(*wsize)) # resize label self["text"].instance.resize(eSize(*textsize)) # move list listsize=(wsizex - 20,45 * count) self["list"].instance.move(ePoint(10,textsize[1])) self["list"].instance.resize(eSize(*listsize))#200d1940 # center window newwidth=wsize[0] self.instance.move(ePoint((1920-wsizex)/2,(1080-wsizey)/2)) - - + @@ -57,45 +51,29 @@ - - {"template":[MultiContentEntryText(pos=(7,0),size=(1573,53),flags=RT_HALIGN_LEFT,font=0,text=0,backcolor=None),MultiContentEntryText(pos=(7,53),size=(267,53),flags=RT_HALIGN_LEFT,font=0,text=1,backcolor=None),MultiContentEntryProgress(pos=(333,56),size=(667,27),percent=-2,borderWidth=1,foreColor=0xe6bd00,backColor=0xe6bd00),MultiContentEntryText(pos=(1067,53),size=(533,53),flags=RT_HALIGN_LEFT,font=0,text=3,backcolor=None),MultiContentEntryText(pos=((,,)),size=((,,)),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),],"fonts":[gFont("Regular",37)],"itemHeight":107} + + {"template":[MultiContentEntryText(pos=(7,0),size=(1573,53),flags=RT_HALIGN_LEFT,font=0,text=0,backcolor=None),MultiContentEntryText(pos=(7,53),size=(267,53),flags=RT_HALIGN_LEFT,font=0,text=1,backcolor=None),MultiContentEntryProgress(pos=(333,56),size=(667,27),percent=-2,borderWidth=1,foreColor=0xe6bd00,backColor=0xe6bd00),MultiContentEntryText(pos=(1067,53),size=(533,53),flags=RT_HALIGN_LEFT,font=0,text=3,backcolor=None),MultiContentEntryText(pos=(0,105),size=(1572,1),font=0,flags=RT_VALIGN_CENTER,text="",backcolor=0xa0a0a0),],"fonts":[gFont("Regular",37)],"itemHeight":107} - - - - 0,8,0 - - - 0,6,1 - - - 1,8,1 - - - 2 - - - 4 - - - 5 - + + + + - + - + Name - MvVideoInfo + MTCVideoInfo @@ -129,13 +107,13 @@ - + Name - MvVideoInfo + MTCVideoInfo @@ -196,4 +174,25 @@ EndTime,ShowNoSeconds + + + + 0,8,0 + + + 0,6,1 + + + 1,8,1 + + + 2 + + + 4 + + + 5 + + diff --git a/src/skin/Shadow-FHD/skin.xml b/src/skin/Shadow-FHD/skin.xml index 781f554..7cfc33d 100644 --- a/src/skin/Shadow-FHD/skin.xml +++ b/src/skin/Shadow-FHD/skin.xml @@ -19,36 +19,30 @@ - - {"templates": {"default":(68,[ MultiContentEntryText(pos=(100,0),size=(1160,68),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = 0, backcolor=None), MultiContentEntryPixmapAlphaTest(pos=(5,5),size=(60,60),png=2, backcolor=None), MultiContentEntryText(pos = (0,67),size = (1259,1),font=0,flags = RT_VALIGN_CENTER,text = "", backcolor=0xa0a0a0) ]), "movi_liste":(68,[ MultiContentEntryText(pos=(65,0),size=(200,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = 0, color=0xa6781c, color_sel=0xa6781c, backcolor=None), MultiContentEntryPixmapAlphaTest(pos=(5,5),size=(50,50),png=8, backcolor=None), MultiContentEntryText(pos=(65,34),size=(130,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = 5, color=0xa0a0a0, color_sel=0xa0a0a0, backcolor=None), MultiContentEntryText(pos = (330,0),size = (930,34),font=2,flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = 1, backcolor=None), MultiContentEntryText(pos = (330,34),size = (930,34),font=0,flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = 2, color=0xa0a0a0, color_sel=0xa0a0a0, backcolor=None), MultiContentEntryText(pos = (205,34),size = (60,34),font=1,flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = 4, color=0xa0a0a0, color_sel=0xa0a0a0, backcolor=None), MultiContentEntryText(pos = (275,34),size = (40,34),font=1,flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = 9, color=0xa0a0a0, color_sel=0xa0a0a0, backcolor=None), MultiContentEntryText(pos = (0,67),size = (1259,1),font=0,flags = RT_VALIGN_CENTER,text = "", backcolor=0xa0a0a0), ]), "search_querys":(68,[ MultiContentEntryText(pos=(0,0),size=(160,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = _("Search for:"), backcolor=None), MultiContentEntryText(pos=(300,0),size=(960,34),font=2,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = 0, backcolor=None), MultiContentEntryText(pos=(0,34),size=(160,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = _("fields:"), backcolor=None), MultiContentEntryText(pos=(120,34),size=(330,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = 1, backcolor=None), MultiContentEntryText(pos=(450,34),size=(100,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = _("channels:"), backcolor=None), MultiContentEntryText(pos=(560,34),size=(700,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = 2, backcolor=None), MultiContentEntryText(pos = (0,67),size = (1259,1),font=0,flags = RT_VALIGN_CENTER,text = "", backcolor=0xa0a0a0) ]) }, "fonts": [gFont("Regular",25),gFont("Regular",22),gFont("Regular",28)], "itemHeight": 60 } + + {"templates": {"default":(68,[ MultiContentEntryText(pos=(100,0),size=(1160,68),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0, backcolor=None), MultiContentEntryPixmapAlphaTest(pos=(5,5),size=(60,60),png=2, backcolor=None), MultiContentEntryText(pos=(0,67),size=(1259,1),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0) ]), "movie_list":(68,[ MultiContentEntryText(pos=(65,0),size=(200,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0, color=0xa6781c, color_sel=0xa6781c, backcolor=None), MultiContentEntryPixmapAlphaTest(pos=(5,5),size=(50,50),png=8, backcolor=None), MultiContentEntryText(pos=(65,34),size=(130,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=5, color=0xa0a0a0, color_sel=0xa0a0a0, backcolor=None), MultiContentEntryText(pos=(330,0),size=(930,34),font=2,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1, backcolor=None), MultiContentEntryText(pos=(330,34),size=(930,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=2, color=0xa0a0a0, color_sel=0xa0a0a0, backcolor=None), MultiContentEntryText(pos=(205,34),size=(60,34),font=1,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=4, color=0xa0a0a0, color_sel=0xa0a0a0, backcolor=None), MultiContentEntryText(pos=(275,34),size=(40,34),font=1,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=9, color=0xa0a0a0, color_sel=0xa0a0a0, backcolor=None), MultiContentEntryText(pos=(0,67),size=(1259,1),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0), ]), "search_querys":(68,[ MultiContentEntryText(pos=(0,0),size=(160,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=_("Search for:"), backcolor=None), MultiContentEntryText(pos=(300,0),size=(960,34),font=2,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0, backcolor=None), MultiContentEntryText(pos=(0,34),size=(160,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=_("fields:"), backcolor=None), MultiContentEntryText(pos=(120,34),size=(330,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1, backcolor=None), MultiContentEntryText(pos=(450,34),size=(100,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=_("channels:"), backcolor=None), MultiContentEntryText(pos=(560,34),size=(700,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=2, backcolor=None), MultiContentEntryText(pos=(0,67),size=(1259,1),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0) ]) }, "fonts": [gFont("Regular",25),gFont("Regular",22),gFont("Regular",28)], "itemHeight": 60 } - + - - + - - - - + + + + - - + + - - - - # this should be factored out into some helper code,but currently demonstrates applets. from enigma import eSize,ePoint orgwidth=self.instance.size().width() orgpos=self.instance.position() textsize=self["text"].getSize() # y size still must be fixed in font stuff... textsize=(textsize[0] + 80,textsize[1] + 100) count=len(self.list) if count > 15: count=15 offset=45 * count wsizex=textsize[0] + 100 wsizey=textsize[1] + offset + 20 if (1180 > wsizex): wsizex=1180 wsize=(wsizex,wsizey) # resize self.instance.resize(eSize(*wsize)) # resize label self["text"].instance.resize(eSize(*textsize)) # move list listsize=(wsizex - 20,45 * count) self["list"].instance.move(ePoint(10,textsize[1])) self["list"].instance.resize(eSize(*listsize))#200d1940 # center window newwidth=wsize[0] self.instance.move(ePoint((1920-wsizex)/2,(1080-wsizey)/2)) - - + @@ -57,45 +51,29 @@ - - {"template": [ MultiContentEntryText(pos=(5,0),size=(1180,40),flags=RT_HALIGN_LEFT,font=0, text=0, backcolor=None), MultiContentEntryText(pos=(5,40),size=(200,40),flags=RT_HALIGN_LEFT,font=0, text=1, backcolor=None), MultiContentEntryProgress(pos=(250,42),size=(500,20),percent=-2, borderWidth=1, foreColor=0xe6bd00, backColor=0xe6bd00), MultiContentEntryText(pos=(800,40),size=(400,40),flags=RT_HALIGN_LEFT,font=0, text=3, backcolor=None), MultiContentEntryText(pos = (0,79),size = (1179,1),font=0,flags = RT_VALIGN_CENTER,text = "", backcolor=0xa0a0a0), ], "fonts": [gFont("Regular",28)], "itemHeight": 80 } + + {"template": [ MultiContentEntryText(pos=(5,0),size=(1180,40),flags=RT_HALIGN_LEFT,font=0, text=0, backcolor=None), MultiContentEntryText(pos=(5,40),size=(200,40),flags=RT_HALIGN_LEFT,font=0, text=1, backcolor=None), MultiContentEntryProgress(pos=(250,42),size=(500,20),percent=-2, borderWidth=1, foreColor=0xe6bd00, backColor=0xe6bd00), MultiContentEntryText(pos=(800,40),size=(400,40),flags=RT_HALIGN_LEFT,font=0, text=3, backcolor=None), MultiContentEntryText(pos=(0,79),size=(1179,1),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0), ], "fonts": [gFont("Regular",28)], "itemHeight": 80 } - - - - 0,8,0 - - - 0,6,1 - - - 1,8,1 - - - 2 - - - 4 - - - 5 - + + + + - + - + Name - MvVideoInfo + MTCVideoInfo @@ -129,13 +107,13 @@ - + Name - MvVideoInfo + MTCVideoInfo @@ -196,4 +174,25 @@ EndTime,ShowNoSeconds + + + + 0,8,0 + + + 0,6,1 + + + 1,8,1 + + + 2 + + + 4 + + + 5 + + diff --git a/src/skin/screen_DirBrowser.xmlinc b/src/skin/screen_DirBrowser.xmlinc new file mode 100755 index 0000000..192e79b --- /dev/null +++ b/src/skin/screen_DirBrowser.xmlinc @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/skin/screen_Downloads.xmlinc b/src/skin/screen_Downloads.xmlinc new file mode 100755 index 0000000..fe03023 --- /dev/null +++ b/src/skin/screen_Downloads.xmlinc @@ -0,0 +1,24 @@ + + + + + + + + + + + + {"template": [ + MultiContentEntryText(pos=(5,0),size=(1180,40),flags=RT_HALIGN_LEFT,font=0, text=0, backcolor=None), + MultiContentEntryText(pos=(5,40),size=(200,40),flags=RT_HALIGN_LEFT,font=0, text=1, backcolor=None), + MultiContentEntryProgress(pos=(250,42),size=(500,20),percent=-2, borderWidth=1, foreColor=0xe6bd00, backColor=0xe6bd00), + MultiContentEntryText(pos=(800,40),size=(400,40),flags=RT_HALIGN_LEFT,font=0, text=3, backcolor=None), + MultiContentEntryText(pos=(0,79),size=(1179,1),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0), + ], + "fonts": [gFont("Regular",28)], + "itemHeight": 80 + } + + + diff --git a/src/skin/screen_MTCEventView.xmlinc b/src/skin/screen_MTCEventView.xmlinc new file mode 100755 index 0000000..f808e80 --- /dev/null +++ b/src/skin/screen_MTCEventView.xmlinc @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/skin/screen_MTCMoviePlayer.xmlinc b/src/skin/screen_MTCMoviePlayer.xmlinc new file mode 100755 index 0000000..9c7f93e --- /dev/null +++ b/src/skin/screen_MTCMoviePlayer.xmlinc @@ -0,0 +1,67 @@ + + + + Name + + + MTCVideoInfo + + + + IsMultichannel + + + + + IsWidescreen + + + + VideoWidth + 0,720 + + + + VideoWidth + 721,1980 + + + + VideoWidth + 2160,3840 + + + + IsHdr + + + + Blink + + + + Position + + + + Position + + + Gauge + + + Remaining,Negate + + + Length,ShowHours + + + + + Default + + + + EndTime,ShowNoSeconds + + diff --git a/src/skin/screen_MTCSetup.xmlinc b/src/skin/screen_MTCSetup.xmlinc new file mode 100755 index 0000000..2ad7deb --- /dev/null +++ b/src/skin/screen_MTCSetup.xmlinc @@ -0,0 +1,5 @@ + + + + + diff --git a/src/skin/screen_MTCStreamPlayer.xmlinc b/src/skin/screen_MTCStreamPlayer.xmlinc new file mode 100755 index 0000000..27189ef --- /dev/null +++ b/src/skin/screen_MTCStreamPlayer.xmlinc @@ -0,0 +1,40 @@ + + + + Name + + + MTCVideoInfo + + + + IsMultichannel + + + + + IsWidescreen + + + + VideoWidth + 0,720 + + + + VideoWidth + 721,1980 + + + + VideoWidth + 2160,3840 + + + + Default + + + + + diff --git a/src/skin/screen_MediathekCockpit.xmlinc b/src/skin/screen_MediathekCockpit.xmlinc new file mode 100755 index 0000000..761884a --- /dev/null +++ b/src/skin/screen_MediathekCockpit.xmlinc @@ -0,0 +1,56 @@ + + + + + + + + + + + + + Default + + + Format:%A %d. %B + + + + + + {"templates": + {"default":(68,[ + MultiContentEntryText(pos=(100,0),size=(1160,68),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0, backcolor=None), + MultiContentEntryPixmapAlphaTest(pos=(5,5),size=(60,60),png=2, backcolor=None), + MultiContentEntryText(pos=(0,67),size=(1259,1),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0) + ]), + "movie_list":(68,[ + MultiContentEntryText(pos=(65,0),size=(200,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0, color=0xa6781c, color_sel=0xa6781c, backcolor=None), + MultiContentEntryPixmapAlphaTest(pos=(5,5),size=(50,50),png=8, backcolor=None), + MultiContentEntryText(pos=(65,34),size=(130,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=5, color=0xa0a0a0, color_sel=0xa0a0a0, backcolor=None), + MultiContentEntryText(pos=(330,0),size=(930,34),font=2,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1, backcolor=None), + MultiContentEntryText(pos=(330,34),size=(930,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=2, color=0xa0a0a0, color_sel=0xa0a0a0, backcolor=None), + MultiContentEntryText(pos=(205,34),size=(60,34),font=1,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=4, color=0xa0a0a0, color_sel=0xa0a0a0, backcolor=None), + MultiContentEntryText(pos=(275,34),size=(40,34),font=1,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=9, color=0xa0a0a0, color_sel=0xa0a0a0, backcolor=None), + MultiContentEntryText(pos=(0,67),size=(1259,1),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0), + ]), + "search_querys":(68,[ + MultiContentEntryText(pos=(0,0),size=(160,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=_("Search for:"), backcolor=None), + MultiContentEntryText(pos=(300,0),size=(960,34),font=2,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=0, backcolor=None), + MultiContentEntryText(pos=(0,34),size=(160,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=_("fields:"), backcolor=None), + MultiContentEntryText(pos=(120,34),size=(330,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=1, backcolor=None), + MultiContentEntryText(pos=(450,34),size=(100,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=_("channels:"), backcolor=None), + MultiContentEntryText(pos=(560,34),size=(700,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text=2, backcolor=None), + MultiContentEntryText(pos=(0,67),size=(1259,1),font=0,flags=RT_VALIGN_CENTER,text="", backcolor=0xa0a0a0) + ]) + }, + "fonts": [gFont("Regular",25),gFont("Regular",22),gFont("Regular",28)], + "itemHeight": 60 + } + + + + + + diff --git a/src/skin/screen_MediathekCockpitSummary.xmlinc b/src/skin/screen_MediathekCockpitSummary.xmlinc new file mode 100755 index 0000000..4d80bb2 --- /dev/null +++ b/src/skin/screen_MediathekCockpitSummary.xmlinc @@ -0,0 +1,21 @@ + + + + 0,8,0 + + + 0,6,1 + + + 1,8,1 + + + 2 + + + 4 + + + 5 + + diff --git a/src/skin/skin_src.xml b/src/skin/skin_src.xml index e85cddf..da97824 100755 --- a/src/skin/skin_src.xml +++ b/src/skin/skin_src.xml @@ -1,288 +1,11 @@ + - - - - - - - - - - - - - - Default - - Format:%A %d. %B - - - - - - {"templates": - {"default":(68,[ - MultiContentEntryText(pos=(100,0),size=(1160,68),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = 0, backcolor=None), - MultiContentEntryPixmapAlphaTest(pos=(5,5),size=(60,60),png=2, backcolor=None), - MultiContentEntryText(pos = (0,67),size = (1259,1),font=0,flags = RT_VALIGN_CENTER,text = "", backcolor=0xa0a0a0) - ]), - "movi_liste":(68,[ - MultiContentEntryText(pos=(65,0),size=(200,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = 0, color=0xa6781c, color_sel=0xa6781c, backcolor=None), - MultiContentEntryPixmapAlphaTest(pos=(5,5),size=(50,50),png=8, backcolor=None), - MultiContentEntryText(pos=(65,34),size=(130,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = 5, color=0xa0a0a0, color_sel=0xa0a0a0, backcolor=None), - MultiContentEntryText(pos = (330,0),size = (930,34),font=2,flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = 1, backcolor=None), - MultiContentEntryText(pos = (330,34),size = (930,34),font=0,flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = 2, color=0xa0a0a0, color_sel=0xa0a0a0, backcolor=None), - MultiContentEntryText(pos = (205,34),size = (60,34),font=1,flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = 4, color=0xa0a0a0, color_sel=0xa0a0a0, backcolor=None), - MultiContentEntryText(pos = (275,34),size = (40,34),font=1,flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = 9, color=0xa0a0a0, color_sel=0xa0a0a0, backcolor=None), - - MultiContentEntryText(pos = (0,67),size = (1259,1),font=0,flags = RT_VALIGN_CENTER,text = "", backcolor=0xa0a0a0), - ]), - "search_querys":(68,[ - MultiContentEntryText(pos=(0,0),size=(160,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = _("Search for:"), backcolor=None), - MultiContentEntryText(pos=(300,0),size=(960,34),font=2,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = 0, backcolor=None), - - MultiContentEntryText(pos=(0,34),size=(160,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = _("fields:"), backcolor=None), - MultiContentEntryText(pos=(120,34),size=(330,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = 1, backcolor=None), - - MultiContentEntryText(pos=(450,34),size=(100,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = _("channels:"), backcolor=None), - MultiContentEntryText(pos=(560,34),size=(700,34),font=0,flags=RT_HALIGN_LEFT|RT_VALIGN_CENTER,text = 2, backcolor=None), - - MultiContentEntryText(pos = (0,67),size = (1259,1),font=0,flags = RT_VALIGN_CENTER,text = "", backcolor=0xa0a0a0) - ]) - }, - "fonts": [gFont("Regular",25),gFont("Regular",22),gFont("Regular",28)], - "itemHeight": 60 - } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# this should be factored out into some helper code,but currently demonstrates applets. -from enigma import eSize,ePoint - -orgwidth=self.instance.size().width() -orgpos=self.instance.position() -textsize=self["text"].getSize() - -# y size still must be fixed in font stuff... -textsize=(textsize[0] + 80,textsize[1] + 100) -count=len(self.list) -if count > 15: - count=15 -offset=45 * count -wsizex=textsize[0] + 100 -wsizey=textsize[1] + offset + 20 - -if (1180 > wsizex): - wsizex=1180 -wsize=(wsizex,wsizey) - -# resize -self.instance.resize(eSize(*wsize)) - -# resize label -self["text"].instance.resize(eSize(*textsize)) - -# move list -listsize=(wsizex - 20,45 * count) -self["list"].instance.move(ePoint(10,textsize[1])) -self["list"].instance.resize(eSize(*listsize))#200d1940 - -# center window -newwidth=wsize[0] -self.instance.move(ePoint((1920-wsizex)/2,(1080-wsizey)/2)) - - - - - - - - - - - - - - - {"template": [ - MultiContentEntryText(pos=(5,0),size=(1180,40),flags=RT_HALIGN_LEFT,font=0, text=0, backcolor=None), - - MultiContentEntryText(pos=(5,40),size=(200,40),flags=RT_HALIGN_LEFT,font=0, text=1, backcolor=None), - MultiContentEntryProgress(pos=(250,42),size=(500,20),percent=-2, borderWidth=1, foreColor=0xe6bd00, backColor=0xe6bd00), - MultiContentEntryText(pos=(800,40),size=(400,40),flags=RT_HALIGN_LEFT,font=0, text=3, backcolor=None), - MultiContentEntryText(pos = (0,79),size = (1179,1),font=0,flags = RT_VALIGN_CENTER,text = "", backcolor=0xa0a0a0), - ], - "fonts": [gFont("Regular",28)], - "itemHeight": 80 - } - - - - - - - - - 0,8,0 - - - 0,6,1 - - - 1,8,1 - - - 2 - - - 4 - - - 5 - - - - - - - - - - - - - Name - - - MvVideoInfo - - - - IsMultichannel - - - - - IsWidescreen - - - - VideoWidth - 0,720 - - - - VideoWidth - 721,1980 - - - - VideoWidth - 2160,3840 - - - - Default - - - - - - - - - - Name - - - MvVideoInfo - - - - IsMultichannel - - - - - IsWidescreen - - - - VideoWidth - 0,720 - - - - VideoWidth - 721,1980 - - - - VideoWidth - 2160,3840 - - - - IsHdr - - - - Blink - - - - Position - - - - Position - - - Gauge - - - Remaining,Negate - - - Length,ShowHours - - - - - Default - - - - EndTime,ShowNoSeconds - - + + + + + + + +