diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..52e4e611 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.pyc +*.pyo diff --git a/script.xbmc.lcd/LICENSE.txt b/LICENSE.txt similarity index 97% rename from script.xbmc.lcd/LICENSE.txt rename to LICENSE.txt index ae4787df..b8b347fd 100644 --- a/script.xbmc.lcd/LICENSE.txt +++ b/LICENSE.txt @@ -1,12 +1,12 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. - Preamble + Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public @@ -15,7 +15,7 @@ software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to +the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not @@ -55,8 +55,8 @@ patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. - - GNU GENERAL PUBLIC LICENSE + + GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains @@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions: License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) - + These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in @@ -168,7 +168,7 @@ access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. - + 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is @@ -225,7 +225,7 @@ impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. - + 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License @@ -255,7 +255,7 @@ make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. - NO WARRANTY + NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN @@ -277,6 +277,5 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - END OF TERMS AND CONDITIONS -------------------------------------------------------------------------- + END OF TERMS AND CONDITIONS diff --git a/README.md b/README.md new file mode 100644 index 00000000..d2d142a1 --- /dev/null +++ b/README.md @@ -0,0 +1,18 @@ +Kodi (XBMC) LCDproc Python addon +================================= + +Copyright (C) 2012-2024 Team Kodi, Daniel 'herrnst' Scheller +Based on initial work (C) 2012 Memphiz/Team Kodi (formerly Team XBMC) + +LCDproc support for Kodi implemented in Python, direct drop-in replacement for +the LCD support that was present in prior versions of XBMC and it's core. + +See https://github.com/herrnst/script.xbmc.lcdproc/wiki for details and usage +information. + +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 2 of the License, or +(at your option) any later version. + +See LICENSE.txt for more information. diff --git a/addon.xml b/addon.xml new file mode 100644 index 00000000..440a9ed8 --- /dev/null +++ b/addon.xml @@ -0,0 +1,33 @@ + + + + + + + + + Kodi/XBMC LCDproc + Displays configurable information e.g. about playing media or Kodi status on any LC/VF-display driven by LCDproc, and acts as direct drop-in replacement to the LCD/VFD-feature previously available in Kodi/XBMC's core. Supports additional display elements (icons, bars) on SoundGraph iMON LCD and Targa/Futaba mdm166a VFD hardware. Requires a properly configured and running LCDd either locally or somewhere on the network. + Zeigt konfigurierbare Informationen z.B. über aktuelle Wiedergabe oder den Kodi Status auf beliebigen von LCDproc angesteuerten LC/VF-Displays, ersetzt die zuvor im Kodi/XBMC-Kern enthaltene LCD/VFD-Funktion. Unterstützt zusätzliche Elemente (Icons, Balken) von SoundGraph iMON LCD und Targa/Futaba mdm166a VFD Hardware. Benötigt einen konfigurierten, laufenden LCDd auf dem lokalen System oder im Netzwerk. + Affiche des informations définies par configuration telles que le média en cours de lecture, l'état de Kodi... et ce sur tout type d'afficheur LC/VF géré par LCDProc. Remplace la fonctionnalité LCD/VFD précédemment disponible par défaut dans Kodi/XBMC. Gère des éléments supplémentaires (icônes, barres) sur les écrans SoundGraph iMON LCD et Targa/Futaba mdm166a VFD. Nécessite un serveur LCDd correctement configuré et disponible localement ou sur le réseau. + Wyświetla konfigurowalne informacje np. o odtwarzanych mediach oraz statusie Kodi na dowolnym wyświetlaczu LCD/VFD sterowanym poprzez LCDproc. Działa jako bezpośredni zamiennik funkcji wyświetlania na LCD/VFD poprzednio dostępnej w rdzeniu Kodi/XBMC. Wspiera wyświetlanie dodatkowych elementów (np. ikon stanu, linijek diodowych lub pasków postępu) na wyświetlaczach SoundGraph iMON (LCD) oraz Targa/Futaba mdm166a (VFD). Wymaga poprawnie skonfigurowanego i uruchomionego serwera LCDd albo lokalnie, albo gdzieś w sieci. + Visar konfigurerbar information, t.ex. om uppspelning av media eller Kodi-status på valfri LC/VF-skärm som drivs av LCDproc, och fungerar som direkt ersättning för LCD/VFD-funktionen som tidigare fanns i Kodi/XBMC:s kärna. Stöder ytterligare skärmelement (ikoner, staplar) på SoundGraph iMON LCD och Targa/Futaba mdm166a VFD-hårdvara. Kräver en korrekt konfigurerad och körande LCDd antingen lokalt eller någonstans i nätverket. + Works with LCDproc only. Other LCD services like LCD4Linux or iMON Manager on Win32 are not supported. No liability taken for damaged hardware and/or software caused by this addon. + Funktioniert ausschliesslich mit LCDproc. Andere LCD-Dienste wie LCD4Linux, iMON Manager unter Win32 u.a. sind nicht unterstützt. Keine Haftung für durch dieses Addon beschädigte Hard-/Software. + Fonctionne uniquement avec LCDProc. Les services tels que LCD4Linux ou iMON Manager sur Win32 ne sont pas gérés. Nous déclinons toute responsabilité en cas de dégats survenus suite à l'utilisation de cette extension. + Działa wyłącznie z LCDproc. Inne usługi LCD jak LCD4Linux lub iMON Manager dla Win32 nie są obsługiwane. Nie ponosimy żadnej odpowiedzialności za uszkodzony sprzęt i/lub oprogramowanie spowodowane tym dodatkiem. + Fungerar endast med LCDproc. Andra LCD-tjänster som LCD4Linux eller iMON Manager på Win32 stöds inte. Vi tar inget ansvar för skador på hårdvara och/eller programvara som orsakas av detta tillägg. + GNU GENERAL PUBLIC LICENSE. Version 2, June 1991 + all + https://github.com/lcdproc/lcdproc + https://forum.kodi.tv/showthread.php?tid=143912 + https://github.com/herrnst/script.xbmc.lcdproc + nst at kodi dot tv + + resources/icon.png + + 4.1.1 +- Swedish translation (thanks yeager!) + + + diff --git a/changelog.txt b/changelog.txt new file mode 100644 index 00000000..328547b2 --- /dev/null +++ b/changelog.txt @@ -0,0 +1,90 @@ +4.1.1 +- Swedish translation (thanks yeager!) +4.1.0 +- Python 3.13 compat: Use raw strings for regex'es everywhere, fixes SyntaxError's (thanks alanswanson!) +- Python 3.13 compat: Replace long deprecated telnetlib usage with raw sockets (thanks m-wichmann!) +- Minor housekeepings +4.0.0 +- fix Python exception when using the HD44780 character encodings/translation maps +3.90.2 +- fix compatibility with Python 3.9 +3.90.1 +- replace LOGNOTICE with LOGINFO, remove LOGSEVERE +- use translatePath from xbmcvfs instead of xbmc +3.90.0 +- XBMC LCDproc for Kodi Matrix (Python 3) +- Allow LCDproc protocol version 0.4 +3.0.5 +- selectable BigDigit clock format by mskalski (thanks!) +3.0.4 +- Fix possible exception due to improper LCD.xml handling +3.0.3 +- Polish translation update by mskalski (thanks!) +- Fixed a possible UTF8 conversion crash/exception +- Updated video/audiocodec strings for extraicon display +3.0.2 +- Refactored the main addon handling into class XBMCLCDproc() +- Refactored the settings and infolabels modules into classes +- fixed connection status popup handling logic +- Code/vars move and cleanup +- Window ID cleanup (fixes the extraicon triggers during navigation) +3.0.1 +- Imports cleaned up +- Compatibility with Python 3 +3.0.0 (Leia) +- Compatibility with Kodi 18 Leia +- Polish translation by mskalski (thanks!) +- French translation by fengalin (thanks!) +- Strings finally migrated to strings.po format +- New progressbar+time linetype by Truong Ta (thanks!) +- Fixes, cleanups, cosmetics and optimizations all over the place +2.6.0 (Helix) +- Initial version for Kodi Helix +- Fix retrieval of application mute state +- Small addition to the HD44780-A00 charmap for polish chars +- Dropped unneeded dependency on xbmc.gui +2.5.1 +- Fix name conflict with the LCDproc PyEgg +- Split setup command list loop to initialise hbars before icons, fixes progress bars not being shown if placed after any icons on RasbPi +- Fix charset encoding exceptions on LCD.xml load if it contains UTF8 chars +2.5.0 (Gotham) +- Initial version for XBMC Gotham with updated dependencies +- BBcode tags are stripped before sending content to the display (reported to happen on e.g. OpenELEC) +- Change in behaviour: BigDigit tag will show the system time instead of current playtime if playing media is paused and the screensaver kicks in +- Missing german umlauts added to the HD44780-A00 character translation map +1.3.3 / 2.3.3 (Eden / Frodo) +- A02 char map enhanced to map czech characters +1.3.2 / 2.3.2 +- Fix "dim display on video playback" functionality +1.3.1 / 2.3.1 +- Recognize E-AC3 (Dolby Digital plus) as AC3 in extra stuff support (affect imonlcd support) +- Fix BigDigits overdrawing text on addon start when things change too fast +1.3.0 / 2.3.0 +- Alternate charmap selection, support for HD44780/iMON ROM (A00 and A02 variants) charsets +- New "tvshow" mode, active when playing media from the TV-shows database +- Refactored backlight dimming handling and configuration via GUI settings +- Cleaned up and improved TCP/Telnet socket handling +- Indicate internet stream on extraicon-supported displays +- Use XBMC's time for daytime display on BigDigit-mode and thus properly display 12/24h clocks, improve bigdigit handling +- Additional "finetuning"-options for extraicon/bar-support +- Option to entirely disable extra stuff support +- Always load defaults so LCD.xml in the masterprofile acts as user override, makes additions like new modes or wrong spelling in XML tags not result in empty displays +- Bugfixes and friends, of course +1.2.1 / 2.2.1 +- Bugfixes, Credits, slightly more convenient configuration option bools +1.2.0 / 2.2.0 +- Maintain versions for Eden (1.x.x) and Frodo+ (2.x.x) +- Support for extra stuff (icons, bars) on supporting displays +- Extra stuff handling for SoundGraph iMON LCD and Futaba/Targa mdm166a VFD + devices (presence will be autodetected) +- Align each line either left (default), centered or right +- Fixed connection problem popup annoyance +- GUI settings cleanup and some more LCD.xml configurables +- Take care of providing a default LCD.xml in the master profile +1.1.0 +- greatly improved client/server communication +- native widgets for bars, icons and bignumbers +- character conversion left to be done by LCDproc +- additional configuration options +1.0.0 +- initial addon release diff --git a/main.py b/main.py new file mode 100644 index 00000000..bae54802 --- /dev/null +++ b/main.py @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# XBMC LCDproc addon +# Copyright (C) 2012-2024 Team Kodi +# Copyright (C) 2012-2024 Daniel 'herrnst' Scheller +# +# Addon entry point +# + +from resources.lib.xbmclcdproc import XBMCLCDproc + +###### +# script entry point +if __name__ == "__main__": + xbmclcd = XBMCLCDproc() + xbmclcd.RunLCD() diff --git a/resources/LCD.xml.defaults b/resources/LCD.xml.defaults new file mode 100644 index 00000000..411a5a97 --- /dev/null +++ b/resources/LCD.xml.defaults @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + $INFO[System.CurrentWindow] + $INFO[System.CurrentControl] + Freemem: $INFO[System.FreeMemory] + $INFO[System.ScreenWidth]x$INFO[System.ScreenHeight] $INFO[System.ScreenMode] + + + $INFO[LCD.PlayIcon] $INFO[Player.Time]/$INFO[Player.Duration] + $INFO[MusicPlayer.Title] + $INFO[MusicPlayer.Artist] + $INFO[MusicPlayer.Album] ($INFO[MusicPlayer.Year]) + + + + $INFO[LCD.PlayIcon] $INFO[Player.Time]/$INFO[Player.Duration] + $INFO[VideoPlayer.TVShowTitle] + $INFO[VideoPlayer.Title] + $INFO[LCD.ProgressBar] + Freemem: $INFO[System.FreeMemory] + + + Kodi running... + $INFO[System.Time] $INFO[System.Date] + Freemem: $INFO[System.FreeMemory] + $INFO[System.ScreenWidth]x$INFO[System.ScreenHeight] $INFO[System.ScreenMode] + + + $INFO[System.CurrentWindow] + $INFO[LCD.TimeWide21] + $INFO[LCD.TimeWide22] + Freemem: $INFO[System.FreeMemory] + + + + Playing + $INFO[System.LaunchXBE] + + + $INFO[VideoPlayer.ChannelName] + $INFO[VideoPlayer.Title] + $INFO[LCD.PlayIcon] $INFO[PVR.EpgEventElapsedTime]$INFO[PVR.EpgEventDuration,/,] + $INFO[LCD.ProgressBar] + + + $INFO[MusicPlayer.ChannelName] + $INFO[MusicPlayer.Title] + $INFO[LCD.PlayIcon] $INFO[PVR.EpgEventElapsedTime]$INFO[PVR.EpgEventDuration,/,] + $INFO[LCD.ProgressBar] + + diff --git a/resources/__init__.py b/resources/__init__.py new file mode 100644 index 00000000..facd9397 --- /dev/null +++ b/resources/__init__.py @@ -0,0 +1 @@ +# dummy file for Python package directory labeling diff --git a/script.xbmc.lcd/icon.png b/resources/icon.png similarity index 100% rename from script.xbmc.lcd/icon.png rename to resources/icon.png diff --git a/resources/language/resource.language.de_de/strings.po b/resources/language/resource.language.de_de/strings.po new file mode 100644 index 00000000..63f5c00b --- /dev/null +++ b/resources/language/resource.language.de_de/strings.po @@ -0,0 +1,191 @@ +# Kodi Media Center language file +# Addon Name: XBMC LCDproc +# Addon id: script.xbmc.lcdproc +# Addon Provider: Team Kodi: Memphiz, Daniel 'herrnst' Scheller +msgid "" +msgstr "" +"Project-Id-Version: script.xbmc.lcdproc\n" +"Report-Msgid-Bugs-To: https://github.com/herrnst/script.xbmc.lcdproc\n" +"POT-Creation-Date: 2018-06-02 15:55+0200\n" +"PO-Revision-Date: 2018-06-02 15:55+0200\n" +"Last-Translator: Daniel Scheller \n" +"Language-Team: German\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: de\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" + +# Settings +# Behaviour + +msgctxt "#32100" +msgid "Behaviour" +msgstr "Verhalten" + +msgctxt "#32101" +msgid "Delay for scrolling text" +msgstr "Geschwindigkeit für gescrollten Text" + +msgctxt "#32102" +msgid "Scroll mode" +msgstr "Scroll-Modus" + +msgctxt "#32103" +msgid "Navigation display duration (s)" +msgstr "Anzeigedauer der Navigationsansicht (s)" + +msgctxt "#32104" +msgid "Display refresh rate (Hz)" +msgstr "Display-Aktualisierungsrate (Hz)" + +msgctxt "#32105" +msgid "Use alternate charset" +msgstr "Verwende alternativen Zeichensatz" + +msgctxt "#32106" +msgid "Charset" +msgstr "Zeichensatz" + +msgctxt "#32107" +msgid "Support for extra display elements (e.g. icons)" +msgstr "Zusatzdisplayelemente (z.B. Icons) unterstützen" + +msgctxt "#32108" +msgid "System time format" +msgstr "Systemzeitformat" + + +# empty strings from id 32109 to 32199 +# Backlight + +msgctxt "#32200" +msgid "Backlight" +msgstr "Beleuchtung" + +msgctxt "#32201" +msgid "on screensaver" +msgstr "wenn Bildschirmschoner aktiv" + +msgctxt "#32202" +msgid "Dim on shutdown" +msgstr "Beim Herunterfahren abdunkeln/abschalten" + +msgctxt "#32203" +msgid "on video/LiveTV playback" +msgstr "während Video/LiveTV-Wiedergabe" + +msgctxt "#32204" +msgid "on music/radio playback" +msgstr "während Musik/Radio-Wiedergabe" + +msgctxt "#32205" +msgid "Delay (s)" +msgstr "Verzögerung (s)" + +msgctxt "#32206" +msgid "Dim/turn off..." +msgstr "Abdunkeln/Abschalten..." + +# empty strings from id 32207 to 32299 +# Connection + +msgctxt "#32300" +msgid "Connection" +msgstr "Verbindung" + +msgctxt "#32301" +msgid "Use remote LCDProc" +msgstr "Entfernten LCDproc-Server benutzen" + +msgctxt "#32302" +msgid "LCDd IP" +msgstr "LCDd IP" + +msgctxt "#32303" +msgid "LCDd port" +msgstr "LCDd Port" + +msgctxt "#32304" +msgid "Show heartbeat symbol" +msgstr "Heartbeatsymbol anzeigen" + +msgctxt "#32305" +msgid "Hide connection error notifications" +msgstr "Verbindungsfehler-Benachrichtigung verstecken" + +# empty strings from id 32306 to 32400 +# Enum values: Scroll mode + +msgctxt "#32401" +msgid "Marquee" +msgstr "Durchlaufend" + +msgctxt "#32402" +msgid "Left/Right" +msgstr "Links/Rechts" + +# empty strings from id 32403 to 32410 +# Enum values: Charsets + +msgctxt "#32411" +msgid "ISO8859-1 (default)" +msgstr "ISO8859-1 (Standard)" + +msgctxt "#32412" +msgid "ISO8859-15" +msgstr "ISO8859-15" + +msgctxt "#32413" +msgid "KOI8-R" +msgstr "KOI8-R" + +msgctxt "#32414" +msgid "CP1251" +msgstr "CP1251" + +msgctxt "#32415" +msgid "ISO8859-5" +msgstr "ISO8859-5" + +msgctxt "#32416" +msgid "HD44780-ROM A00" +msgstr "HD44780-ROM A00" + +msgctxt "#32417" +msgid "HD44780-ROM A02" +msgstr "HD44780-ROM A02" + +# empty strings from id 32418 to 32420 +# Enum values: System time format + +msgctxt "#32421" +msgid "H:MM" +msgstr "" + +msgctxt "#32422" +msgid "HH:MM" +msgstr "" + +msgctxt "#32423" +msgid "H:MM:SS" +msgstr "" + +msgctxt "#32424" +msgid "HH:MM:SS" +msgstr "" + +# empty strings from id 32425 to 32499 +# Notifications + +msgctxt "#32500" +msgid "Failed to connect to LCDProc!" +msgstr "Fehler beim Verbinden zu LCDproc!" + +msgctxt "#32501" +msgid "Connected to LCDProc!" +msgstr "Verbunden mit LCDproc!" + +msgctxt "#32502" +msgid "Warning! Errors in LCD.xml or LCD.xml not found!" +msgstr "Warnung! Fehlerhafte LCD.xml oder LCD.xml nicht gefunden!" diff --git a/resources/language/resource.language.en_gb/strings.po b/resources/language/resource.language.en_gb/strings.po new file mode 100644 index 00000000..eb6bfe58 --- /dev/null +++ b/resources/language/resource.language.en_gb/strings.po @@ -0,0 +1,190 @@ +# Kodi Media Center language file +# Addon Name: XBMC LCDproc +# Addon id: script.xbmc.lcdproc +# Addon Provider: Team Kodi: Memphiz, Daniel 'herrnst' Scheller +msgid "" +msgstr "" +"Project-Id-Version: script.xbmc.lcdproc\n" +"Report-Msgid-Bugs-To: https://github.com/herrnst/script.xbmc.lcdproc\n" +"POT-Creation-Date: 2018-06-02 15:55+0200\n" +"PO-Revision-Date: 2018-06-02 15:55+0200\n" +"Last-Translator: Daniel Scheller \n" +"Language-Team: English\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: en\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" + +# Settings +# Behaviour + +msgctxt "#32100" +msgid "Behaviour" +msgstr "" + +msgctxt "#32101" +msgid "Delay for scrolling text" +msgstr "" + +msgctxt "#32102" +msgid "Scroll mode" +msgstr "" + +msgctxt "#32103" +msgid "Navigation display duration (s)" +msgstr "" + +msgctxt "#32104" +msgid "Display refresh rate (Hz)" +msgstr "" + +msgctxt "#32105" +msgid "Use alternate charset" +msgstr "" + +msgctxt "#32106" +msgid "Charset" +msgstr "" + +msgctxt "#32107" +msgid "Support for extra display elements (e.g. icons)" +msgstr "" + +msgctxt "#32108" +msgid "System time format" +msgstr "" + +# empty strings from id 32109 to 32199 +# Backlight + +msgctxt "#32200" +msgid "Backlight" +msgstr "" + +msgctxt "#32201" +msgid "on screensaver" +msgstr "" + +msgctxt "#32202" +msgid "Dim on shutdown" +msgstr "" + +msgctxt "#32203" +msgid "on video/LiveTV playback" +msgstr "" + +msgctxt "#32204" +msgid "on music/radio playback" +msgstr "" + +msgctxt "#32205" +msgid "Delay (s)" +msgstr "" + +msgctxt "#32206" +msgid "Dim/turn off..." +msgstr "" + +# empty strings from id 32207 to 32299 +# Connection + +msgctxt "#32300" +msgid "Connection" +msgstr "" + +msgctxt "#32301" +msgid "Use remote LCDProc" +msgstr "" + +msgctxt "#32302" +msgid "LCDd IP" +msgstr "" + +msgctxt "#32303" +msgid "LCDd port" +msgstr "" + +msgctxt "#32304" +msgid "Show heartbeat symbol" +msgstr "" + +msgctxt "#32305" +msgid "Hide connection error notifications" +msgstr "" + +# empty strings from id 32306 to 32400 +# Enum values: Scroll mode + +msgctxt "#32401" +msgid "Marquee" +msgstr "" + +msgctxt "#32402" +msgid "Left/Right" +msgstr "" + +# empty strings from id 32403 to 32410 +# Enum values: Charsets + +msgctxt "#32411" +msgid "ISO8859-1 (default)" +msgstr "" + +msgctxt "#32412" +msgid "ISO8859-15" +msgstr "" + +msgctxt "#32413" +msgid "KOI8-R" +msgstr "" + +msgctxt "#32414" +msgid "CP1251" +msgstr "" + +msgctxt "#32415" +msgid "ISO8859-5" +msgstr "" + +msgctxt "#32416" +msgid "HD44780-ROM A00" +msgstr "" + +msgctxt "#32417" +msgid "HD44780-ROM A02" +msgstr "" + +# empty strings from id 32418 to 32420 +# Enum values: System time format + +msgctxt "#32421" +msgid "H:MM" +msgstr "" + +msgctxt "#32422" +msgid "HH:MM" +msgstr "" + +msgctxt "#32423" +msgid "H:MM:SS" +msgstr "" + +msgctxt "#32424" +msgid "HH:MM:SS" +msgstr "" + +# empty strings from id 32425 to 32499 +# Notifications + +msgctxt "#32500" +msgid "Failed to connect to LCDProc!" +msgstr "" + +msgctxt "#32501" +msgid "Connected to LCDProc!" +msgstr "" + +msgctxt "#32502" +msgid "Warning! Errors in LCD.xml or LCD.xml not found!" +msgstr "" diff --git a/resources/language/resource.language.fr_fr/strings.po b/resources/language/resource.language.fr_fr/strings.po new file mode 100644 index 00000000..d67442fa --- /dev/null +++ b/resources/language/resource.language.fr_fr/strings.po @@ -0,0 +1,185 @@ +# Kodi Media Center language file +# Addon Name: XBMC LCDproc +# Addon id: script.xbmc.lcdproc +# Addon Provider: Team Kodi: Memphiz, Daniel 'herrnst' Scheller +msgid "" +msgstr "" +"Project-Id-Version: script.xbmc.lcdproc\n" +"Report-Msgid-Bugs-To: https://github.com/herrnst/script.xbmc.lcdproc\n" +"POT-Creation-Date: 2018-06-02 15:55+0200\n" +"PO-Revision-Date: 2018-06-03 18:37+0200\n" +"Last-Translator: François Laignel \n" +"Language-Team: Français\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: fr\n" +"Plural-Forms: nplurals=2; plural=(n > 1)\n" + +# Settings +# Behaviour +msgctxt "#32100" +msgid "Behaviour" +msgstr "Comportement" + +msgctxt "#32101" +msgid "Delay for scrolling text" +msgstr "Délai avant défilement du texte" + +msgctxt "#32102" +msgid "Scroll mode" +msgstr "Mode de défilement" + +msgctxt "#32103" +msgid "Navigation display duration (s)" +msgstr "Rémanence de l'écran de navigation (s)" + +msgctxt "#32104" +msgid "Display refresh rate (Hz)" +msgstr "Taux de rafraichissement (Hz)" + +msgctxt "#32105" +msgid "Use alternate charset" +msgstr "Utiliser un jeu de caractères alternatif" + +msgctxt "#32106" +msgid "Charset" +msgstr "Jeu de caractères" + +msgctxt "#32107" +msgid "Support for extra display elements (e.g. icons)" +msgstr "Gestion des éléments d'affichage supplémentaires (ex. icônes)" + +msgctxt "#32108" +msgid "System time format" +msgstr "Format de l'heure système" + +# empty strings from id 32109 to 32199 +# Backlight +msgctxt "#32200" +msgid "Backlight" +msgstr "Rétro-éclairage" + +msgctxt "#32201" +msgid "on screensaver" +msgstr "en mode économie d'écran" + +msgctxt "#32202" +msgid "Dim on shutdown" +msgstr "Diminuer lors de l'arrêt" + +msgctxt "#32203" +msgid "on video/LiveTV playback" +msgstr "lors de la lecture de vidéo ou en mode TV" + +msgctxt "#32204" +msgid "on music/radio playback" +msgstr "lors de la lecture de musique ou en mode radio" + +msgctxt "#32205" +msgid "Delay (s)" +msgstr "Délai (s)" + +msgctxt "#32206" +msgid "Dim/turn off..." +msgstr "Diminuer/éteindre…" + +# empty strings from id 32207 to 32299 +# Connection +msgctxt "#32300" +msgid "Connection" +msgstr "Connexion" + +msgctxt "#32301" +msgid "Use remote LCDProc" +msgstr "Utiliser un démon LCDProc distant" + +msgctxt "#32302" +msgid "LCDd IP" +msgstr "Adresse IP de LCDd" + +msgctxt "#32303" +msgid "LCDd port" +msgstr "Port de LCDd" + +msgctxt "#32304" +msgid "Show heartbeat symbol" +msgstr "Afficher le symbole de pulsation" + +msgctxt "#32305" +msgid "Hide connection error notifications" +msgstr "Cacher les notifications d'erreurs de connexion" + +# empty strings from id 32306 to 32400 +# Enum values: Scroll mode +msgctxt "#32401" +msgid "Marquee" +msgstr "En boucle" + +msgctxt "#32402" +msgid "Left/Right" +msgstr "Gauche/Droite" + +# empty strings from id 32403 to 32410 +# Enum values: Charsets +msgctxt "#32411" +msgid "ISO8859-1 (default)" +msgstr "ISO8859-1 (valeur d'origine)" + +msgctxt "#32412" +msgid "ISO8859-15" +msgstr "ISO8859-15" + +msgctxt "#32413" +msgid "KOI8-R" +msgstr "KOI8-R" + +msgctxt "#32414" +msgid "CP1251" +msgstr "CP1251" + +msgctxt "#32415" +msgid "ISO8859-5" +msgstr "ISO8859-5" + +msgctxt "#32416" +msgid "HD44780-ROM A00" +msgstr "HD44780-ROM A00" + +msgctxt "#32417" +msgid "HD44780-ROM A02" +msgstr "HD44780-ROM A02" + +# empty strings from id 32418 to 32420 +# Enum values: System time format + +msgctxt "#32421" +msgid "H:MM" +msgstr "" + +msgctxt "#32422" +msgid "HH:MM" +msgstr "" + +msgctxt "#32423" +msgid "H:MM:SS" +msgstr "" + +msgctxt "#32424" +msgid "HH:MM:SS" +msgstr "" + +# empty strings from id 32425 to 32499 +# Notifications + +msgctxt "#32500" +msgid "Failed to connect to LCDProc!" +msgstr "Échec lors de la connexion à LCDProc !" + +msgctxt "#32501" +msgid "Connected to LCDProc!" +msgstr "Connecté à LCDProc !" + +msgctxt "#32502" +msgid "Warning! Errors in LCD.xml or LCD.xml not found!" +msgstr "Attention ! LCD.xml comporte des erreurs ou est introuvable !" diff --git a/resources/language/resource.language.pl_pl/strings.po b/resources/language/resource.language.pl_pl/strings.po new file mode 100644 index 00000000..62b2fe8c --- /dev/null +++ b/resources/language/resource.language.pl_pl/strings.po @@ -0,0 +1,190 @@ +# Kodi Media Center language file +# Addon Name: XBMC LCDproc +# Addon id: script.xbmc.lcdproc +# Addon Provider: Team Kodi: Memphiz, Daniel 'herrnst' Scheller +msgid "" +msgstr "" +"Project-Id-Version: script.xbmc.lcdproc\n" +"Report-Msgid-Bugs-To: https://github.com/herrnst/script.xbmc.lcdproc\n" +"POT-Creation-Date: 2018-06-02 15:55+0200\n" +"PO-Revision-Date: 2018-06-02 15:55+0200\n" +"Last-Translator: Michał Skalski \n" +"Language-Team: Polish\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: pl\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n" + +# Settings +# Behaviour + +msgctxt "#32100" +msgid "Behaviour" +msgstr "Zachowanie" + +msgctxt "#32101" +msgid "Delay for scrolling text" +msgstr "Opóźnienie dla przewijania tekstu" + +msgctxt "#32102" +msgid "Scroll mode" +msgstr "Tryb przewijania" + +msgctxt "#32103" +msgid "Navigation display duration (s)" +msgstr "Czas wyświetlania informacji nawigacyjnych (s)" + +msgctxt "#32104" +msgid "Display refresh rate (Hz)" +msgstr "Częstotliwość odświeżania (Hz)" + +msgctxt "#32105" +msgid "Use alternate charset" +msgstr "Użyj alternatywnego zestawu znaków" + +msgctxt "#32106" +msgid "Charset" +msgstr "Zestaw znaków" + +msgctxt "#32107" +msgid "Support for extra display elements (e.g. icons)" +msgstr "Wsparcie dla dodatkowych elementów wyświetlających (np. ikon)" + +msgctxt "#32108" +msgid "System time format" +msgstr "Format czasu systemowego" + +# empty strings from id 32109 to 32199 +# Backlight + +msgctxt "#32200" +msgid "Backlight" +msgstr "Podświetlenie" + +msgctxt "#32201" +msgid "on screensaver" +msgstr "podczas działania wygaszacza ekranu" + +msgctxt "#32202" +msgid "Dim on shutdown" +msgstr "Przyciemnij przed wyłączeniem" + +msgctxt "#32203" +msgid "on video/LiveTV playback" +msgstr "podczas odtwarzania filmów wideo/TV" + +msgctxt "#32204" +msgid "on music/radio playback" +msgstr "podczas odtwarzania muzyki/radia" + +msgctxt "#32205" +msgid "Delay (s)" +msgstr "Opóźnienie (s)" + +msgctxt "#32206" +msgid "Dim/turn off..." +msgstr "Przyciemnij/wyłącz podświetlenie:" + +# empty strings from id 32207 to 32299 +# Connection + +msgctxt "#32300" +msgid "Connection" +msgstr "Połączenie" + +msgctxt "#32301" +msgid "Use remote LCDProc" +msgstr "Podłącz do zdalnego serwera LCDProc" + +msgctxt "#32302" +msgid "LCDd IP" +msgstr "Adres IP serwera LCDd" + +msgctxt "#32303" +msgid "LCDd port" +msgstr "Port serwera LCDd" + +msgctxt "#32304" +msgid "Show heartbeat symbol" +msgstr "Włącz tętno (heartbeat)" + +msgctxt "#32305" +msgid "Hide connection error notifications" +msgstr "Nie pokazuj powiadomień o błędach połączenia" + +# empty strings from id 32306 to 32400 +# Enum values: Scroll mode + +msgctxt "#32401" +msgid "Marquee" +msgstr "Marquee" + +msgctxt "#32402" +msgid "Left/Right" +msgstr "Lewo/Prawo" + +# empty strings from id 32403 to 32410 +# Enum values: Charsets + +msgctxt "#32411" +msgid "ISO8859-1 (default)" +msgstr "ISO8859-1 (default)" + +msgctxt "#32412" +msgid "ISO8859-15" +msgstr "ISO8859-15" + +msgctxt "#32413" +msgid "KOI8-R" +msgstr "KOI8-R" + +msgctxt "#32414" +msgid "CP1251" +msgstr "CP1251" + +msgctxt "#32415" +msgid "ISO8859-5" +msgstr "ISO8859-5" + +msgctxt "#32416" +msgid "HD44780-ROM A00" +msgstr "HD44780-ROM A00" + +msgctxt "#32417" +msgid "HD44780-ROM A02" +msgstr "HD44780-ROM A02" + +# empty strings from id 32418 to 32420 +# Enum values: System time format + +msgctxt "#32421" +msgid "H:MM" +msgstr "" + +msgctxt "#32422" +msgid "HH:MM" +msgstr "" + +msgctxt "#32423" +msgid "H:MM:SS" +msgstr "" + +msgctxt "#32424" +msgid "HH:MM:SS" +msgstr "" + +# empty strings from id 32425 to 32499 +# Notifications + +msgctxt "#32500" +msgid "Failed to connect to LCDProc!" +msgstr "Błąd połączenia z serwerem LCDProc!" + +msgctxt "#32501" +msgid "Connected to LCDProc!" +msgstr "Połączony z serwerem LCDProc!" + +msgctxt "#32502" +msgid "Warning! Errors in LCD.xml or LCD.xml not found!" +msgstr "Uwaga! Błędy w konfiguracji w pliku LCD.xml lub plik LCD.xml nie znaleziony!" diff --git a/resources/language/resource.language.sv_se/strings.po b/resources/language/resource.language.sv_se/strings.po new file mode 100644 index 00000000..5da9dfd9 --- /dev/null +++ b/resources/language/resource.language.sv_se/strings.po @@ -0,0 +1,184 @@ +# Kodi Media Center Swedish language file +# Addon Name: XBMC LCDproc +# Addon id: script.xbmc.lcdproc +# Addon Provider: Team Kodi: Memphiz, Daniel 'herrnst' Scheller +msgid "" +msgstr "" +"Project-Id-Version: script.xbmc.lcdproc\n" +"Report-Msgid-Bugs-To: https://github.com/herrnst/script.xbmc.lcdproc\n" +"POT-Creation-Date: 2018-06-02 15:55+0200\n" +"PO-Revision-Date: 2025-05-06 07:37+0200\n" +"Last-Translator: Daniel Nylander \n" +"Language-Team: Swedish\n" +"Language: sv\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 3.6\n" + +# Settings +# Behaviour +msgctxt "#32100" +msgid "Behaviour" +msgstr "Beteende" + +msgctxt "#32101" +msgid "Delay for scrolling text" +msgstr "Fördröjning för rullning av text" + +msgctxt "#32102" +msgid "Scroll mode" +msgstr "Rullningsläge" + +msgctxt "#32103" +msgid "Navigation display duration (s)" +msgstr "Navigationsskärmens varaktighet (s)" + +msgctxt "#32104" +msgid "Display refresh rate (Hz)" +msgstr "Skärmens uppdateringsfrekvens (Hz)" + +msgctxt "#32105" +msgid "Use alternate charset" +msgstr "Använd alternativ teckenuppsättning" + +msgctxt "#32106" +msgid "Charset" +msgstr "Teckenuppsättning" + +msgctxt "#32107" +msgid "Support for extra display elements (e.g. icons)" +msgstr "Stöd för extra visningselement (t.ex. ikoner)" + +msgctxt "#32108" +msgid "System time format" +msgstr "Systemets tidsformat" + +# empty strings from id 32109 to 32199 +# Backlight +msgctxt "#32200" +msgid "Backlight" +msgstr "Bakgrundsbelysning" + +msgctxt "#32201" +msgid "on screensaver" +msgstr "vid skärmsläckare" + +msgctxt "#32202" +msgid "Dim on shutdown" +msgstr "Dimma vid avstängning" + +msgctxt "#32203" +msgid "on video/LiveTV playback" +msgstr "vid uppspelning av video/direktsänd TV" + +msgctxt "#32204" +msgid "on music/radio playback" +msgstr "vid uppspelning av musik/radio" + +msgctxt "#32205" +msgid "Delay (s)" +msgstr "Fördröjning (s)" + +msgctxt "#32206" +msgid "Dim/turn off..." +msgstr "Dimma/slå av..." + +# empty strings from id 32207 to 32299 +# Connection +msgctxt "#32300" +msgid "Connection" +msgstr "Anslutning" + +msgctxt "#32301" +msgid "Use remote LCDProc" +msgstr "Använd fjärr-LCDProc" + +msgctxt "#32302" +msgid "LCDd IP" +msgstr "LCDd IP" + +msgctxt "#32303" +msgid "LCDd port" +msgstr "LCDd-port" + +msgctxt "#32304" +msgid "Show heartbeat symbol" +msgstr "Visa symbol för hjärtslag" + +msgctxt "#32305" +msgid "Hide connection error notifications" +msgstr "Dölj meddelanden om anslutningsfel" + +# empty strings from id 32306 to 32400 +# Enum values: Scroll mode +msgctxt "#32401" +msgid "Marquee" +msgstr "Draperi" + +msgctxt "#32402" +msgid "Left/Right" +msgstr "Vänster/Höger" + +# empty strings from id 32403 to 32410 +# Enum values: Charsets +msgctxt "#32411" +msgid "ISO8859-1 (default)" +msgstr "ISO8859-1 (standard)" + +msgctxt "#32412" +msgid "ISO8859-15" +msgstr "ISO8859-15" + +msgctxt "#32413" +msgid "KOI8-R" +msgstr "KOI8-R" + +msgctxt "#32414" +msgid "CP1251" +msgstr "CP1251" + +msgctxt "#32415" +msgid "ISO8859-5" +msgstr "ISO8859-5" + +msgctxt "#32416" +msgid "HD44780-ROM A00" +msgstr "HD44780-ROM A00" + +msgctxt "#32417" +msgid "HD44780-ROM A02" +msgstr "HD44780-ROM A02" + +# empty strings from id 32418 to 32420 +# Enum values: System time format +msgctxt "#32421" +msgid "H:MM" +msgstr "H:MM" + +msgctxt "#32422" +msgid "HH:MM" +msgstr "HH:MM" + +msgctxt "#32423" +msgid "H:MM:SS" +msgstr "H:MM:SS" + +msgctxt "#32424" +msgid "HH:MM:SS" +msgstr "HH:MM:SS" + +# empty strings from id 32425 to 32499 +# Notifications +msgctxt "#32500" +msgid "Failed to connect to LCDProc!" +msgstr "Misslyckades med att ansluta till LCDProc!" + +msgctxt "#32501" +msgid "Connected to LCDProc!" +msgstr "Ansluten till LCDProc!" + +msgctxt "#32502" +msgid "Warning! Errors in LCD.xml or LCD.xml not found!" +msgstr "Varning! Fel i LCD.xml eller LCD.xml hittades inte!" diff --git a/resources/lib/__init__.py b/resources/lib/__init__.py new file mode 100644 index 00000000..facd9397 --- /dev/null +++ b/resources/lib/__init__.py @@ -0,0 +1 @@ +# dummy file for Python package directory labeling diff --git a/resources/lib/charset_hd44780.py b/resources/lib/charset_hd44780.py new file mode 100644 index 00000000..a81cd18d --- /dev/null +++ b/resources/lib/charset_hd44780.py @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# XBMC LCDproc addon +# Copyright (C) 2012-2024 Team Kodi +# Copyright (C) 2012-2024 Daniel 'herrnst' Scheller +# +# HD44780 charset codec +# + +import codecs +from .charset_map_hd44780_a00 import * +from .charset_map_hd44780_a02 import * + +class HD44780_Codec(codecs.Codec): + + def encode_a00(self,input,errors='strict'): + return codecs.charmap_encode(input,errors,encmap_hd44780_a00) + + def encode_a02(self,input,errors='strict'): + return codecs.charmap_encode(input,errors,encmap_hd44780_a02) + + def decode(self,input,errors='strict'): + pass + +class HD44780_IncrementalEncoder_a00(codecs.IncrementalEncoder): + def encode(self, input, final=False): + return codecs.charmap_encode(input,self.errors,encmap_hd44780_a00)[0] + +class HD44780_IncrementalEncoder_a02(codecs.IncrementalEncoder): + def encode(self, input, final=False): + return codecs.charmap_encode(input,self.errors,encmap_hd44780_a02)[0] + +class HD44780_IncrementalDecoder(codecs.IncrementalDecoder): + pass + +class HD44780_StreamWriter(HD44780_Codec,codecs.StreamWriter): + pass + +class HD44780_StreamReader(HD44780_Codec,codecs.StreamReader): + pass + +def charset_hd44780(mapname): + if mapname == "hd44780_a00": + return codecs.CodecInfo( + name = mapname, + encode = HD44780_Codec().encode_a00, + decode = HD44780_Codec().decode, + incrementalencoder = HD44780_IncrementalEncoder_a00, + incrementaldecoder = HD44780_IncrementalDecoder, + streamreader = HD44780_StreamReader, + streamwriter = HD44780_StreamWriter, + ) + elif mapname == "hd44780_a02": + return codecs.CodecInfo( + name = mapname, + encode = HD44780_Codec().encode_a02, + decode = HD44780_Codec().decode, + incrementalencoder = HD44780_IncrementalEncoder_a02, + incrementaldecoder = HD44780_IncrementalDecoder, + streamreader = HD44780_StreamReader, + streamwriter = HD44780_StreamWriter, + ) + else: + return None diff --git a/resources/lib/charset_map_hd44780_a00.py b/resources/lib/charset_map_hd44780_a00.py new file mode 100644 index 00000000..76b9afc8 --- /dev/null +++ b/resources/lib/charset_map_hd44780_a00.py @@ -0,0 +1,288 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# XBMC LCDproc addon +# Copyright (C) 2012-2024 Team Kodi +# Copyright (C) 2012-2024 Daniel 'herrnst' Scheller +# +# HD44780-A00 char map +# + +encmap_hd44780_a00 = { + 0x0000: 0x0000, # NULL + # 0x0001: 0x0001, # START OF HEADING + # 0x0002: 0x0002, # START OF TEXT + # 0x0003: 0x0003, # END OF TEXT + # 0x0004: 0x0004, # END OF TRANSMISSION + # 0x0005: 0x0005, # ENQUIRY + # 0x0006: 0x0006, # ACKNOWLEDGE + # 0x0007: 0x0007, # BELL + # 0x0008: 0x0008, # BACKSPACE + # 0x0009: 0x0009, # HORIZONTAL TABULATION + # 0x000a: 0x000a, # LINE FEED + # 0x000b: 0x000b, # VERTICAL TABULATION + # 0x000c: 0x000c, # FORM FEED + # 0x000d: 0x000d, # CARRIAGE RETURN + # 0x000e: 0x000e, # SHIFT OUT + # 0x000f: 0x000f, # SHIFT IN + # 0x0010: 0x0010, # DATA LINK ESCAPE + # 0x0011: 0x0011, # DEVICE CONTROL ONE + # 0x0012: 0x0012, # DEVICE CONTROL TWO + # 0x0013: 0x0013, # DEVICE CONTROL THREE + # 0x0014: 0x0014, # DEVICE CONTROL FOUR + # 0x0015: 0x0015, # NEGATIVE ACKNOWLEDGE + # 0x0016: 0x0016, # SYNCHRONOUS IDLE + # 0x0017: 0x0017, # END OF TRANSMISSION BLOCK + # 0x0018: 0x0018, # CANCEL + # 0x0019: 0x0019, # END OF MEDIUM + # 0x001a: 0x001a, # SUBSTITUTE + # 0x001b: 0x001b, # ESCAPE + # 0x001c: 0x001c, # INFORMATION SEPARATOR FOUR + # 0x001d: 0x001d, # INFORMATION SEPARATOR THREE + # 0x001e: 0x001e, # INFORMATION SEPARATOR TWO + # 0x001f: 0x001f, # INFORMATION SEPARATOR ONE + 0x0020: 0x0020, # SPACE + 0x0021: 0x0021, # EXCLAMATION MARK + 0x0022: 0x0022, # QUOTATION MARK + 0x0023: 0x0023, # NUMBER SIGN + 0x0024: 0x0024, # DOLLAR SIGN + 0x0025: 0x0025, # PERCENT SIGN + 0x0026: 0x0026, # AMPERSAND + 0x0027: 0x0027, # APOSTROPHE + 0x0028: 0x0028, # LEFT PARENTHESIS + 0x0029: 0x0029, # RIGHT PARENTHESIS + 0x002a: 0x002a, # ASTERISK + 0x002b: 0x002b, # PLUS SIGN + 0x002c: 0x002c, # COMMA + 0x002d: 0x002d, # HYPHEN-MINUS + 0x002e: 0x002e, # FULL STOP + 0x002f: 0x002f, # SOLIDUS + 0x0030: 0x0030, # DIGIT ZERO + 0x0031: 0x0031, # DIGIT ONE + 0x0032: 0x0032, # DIGIT TWO + 0x0033: 0x0033, # DIGIT THREE + 0x0034: 0x0034, # DIGIT FOUR + 0x0035: 0x0035, # DIGIT FIVE + 0x0036: 0x0036, # DIGIT SIX + 0x0037: 0x0037, # DIGIT SEVEN + 0x0038: 0x0038, # DIGIT EIGHT + 0x0039: 0x0039, # DIGIT NINE + 0x003a: 0x003a, # COLON + 0x003b: 0x003b, # SEMICOLON + 0x003c: 0x003c, # LESS-THAN SIGN + 0x003d: 0x003d, # EQUALS SIGN + 0x003e: 0x003e, # GREATER-THAN SIGN + 0x003f: 0x003f, # QUESTION MARK + 0x0040: 0x0040, # COMMERCIAL AT + 0x0041: 0x0041, # LATIN CAPITAL LETTER A + 0x0042: 0x0042, # LATIN CAPITAL LETTER B + 0x0043: 0x0043, # LATIN CAPITAL LETTER C + 0x0044: 0x0044, # LATIN CAPITAL LETTER D + 0x0045: 0x0045, # LATIN CAPITAL LETTER E + 0x0046: 0x0046, # LATIN CAPITAL LETTER F + 0x0047: 0x0047, # LATIN CAPITAL LETTER G + 0x0048: 0x0048, # LATIN CAPITAL LETTER H + 0x0049: 0x0049, # LATIN CAPITAL LETTER I + 0x004a: 0x004a, # LATIN CAPITAL LETTER J + 0x004b: 0x004b, # LATIN CAPITAL LETTER K + 0x004c: 0x004c, # LATIN CAPITAL LETTER L + 0x004d: 0x004d, # LATIN CAPITAL LETTER M + 0x004e: 0x004e, # LATIN CAPITAL LETTER N + 0x004f: 0x004f, # LATIN CAPITAL LETTER O + 0x0050: 0x0050, # LATIN CAPITAL LETTER P + 0x0051: 0x0051, # LATIN CAPITAL LETTER Q + 0x0052: 0x0052, # LATIN CAPITAL LETTER R + 0x0053: 0x0053, # LATIN CAPITAL LETTER S + 0x0054: 0x0054, # LATIN CAPITAL LETTER T + 0x0055: 0x0055, # LATIN CAPITAL LETTER U + 0x0056: 0x0056, # LATIN CAPITAL LETTER V + 0x0057: 0x0057, # LATIN CAPITAL LETTER W + 0x0058: 0x0058, # LATIN CAPITAL LETTER X + 0x0059: 0x0059, # LATIN CAPITAL LETTER Y + 0x005a: 0x005a, # LATIN CAPITAL LETTER Z + 0x005b: 0x005b, # LEFT SQUARE BRACKET + 0x005c: 0x00a4, # REVERSE SOLIDUS + 0x005d: 0x005d, # RIGHT SQUARE BRACKET + 0x005e: 0x005e, # CIRCUMFLEX ACCENT + 0x005f: 0x005f, # LOW LINE + 0x0060: 0x0060, # GRAVE ACCENT + 0x0061: 0x0061, # LATIN SMALL LETTER A + 0x0062: 0x0062, # LATIN SMALL LETTER B + 0x0063: 0x0063, # LATIN SMALL LETTER C + 0x0064: 0x0064, # LATIN SMALL LETTER D + 0x0065: 0x0065, # LATIN SMALL LETTER E + 0x0066: 0x0066, # LATIN SMALL LETTER F + 0x0067: 0x0067, # LATIN SMALL LETTER G + 0x0068: 0x0068, # LATIN SMALL LETTER H + 0x0069: 0x0069, # LATIN SMALL LETTER I + 0x006a: 0x006a, # LATIN SMALL LETTER J + 0x006b: 0x006b, # LATIN SMALL LETTER K + 0x006c: 0x006c, # LATIN SMALL LETTER L + 0x006d: 0x006d, # LATIN SMALL LETTER M + 0x006e: 0x006e, # LATIN SMALL LETTER N + 0x006f: 0x006f, # LATIN SMALL LETTER O + 0x0070: 0x0070, # LATIN SMALL LETTER P + 0x0071: 0x0071, # LATIN SMALL LETTER Q + 0x0072: 0x0072, # LATIN SMALL LETTER R + 0x0073: 0x0073, # LATIN SMALL LETTER S + 0x0074: 0x0074, # LATIN SMALL LETTER T + 0x0075: 0x0075, # LATIN SMALL LETTER U + 0x0076: 0x0076, # LATIN SMALL LETTER V + 0x0077: 0x0077, # LATIN SMALL LETTER W + 0x0078: 0x0078, # LATIN SMALL LETTER X + 0x0079: 0x0079, # LATIN SMALL LETTER Y + 0x007a: 0x007a, # LATIN SMALL LETTER Z + 0x007b: 0x007b, # LEFT CURLY BRACKET + 0x007c: 0x007c, # VERTICAL LINE + 0x007d: 0x007d, # RIGHT CURLY BRACKET + 0x007e: 0x00b0, # TILDE + 0x007f: 0x0020, # DELETE + 0x0080: 0x0020, + 0x0081: 0x0020, + 0x0082: 0x002c, + 0x0083: 0x0020, + 0x0084: 0x0022, + 0x0085: 0x0020, + 0x0086: 0x0020, + 0x0087: 0x0020, + 0x0088: 0x005e, + 0x0089: 0x0020, + 0x008a: 0x0053, + 0x008b: 0x003c, + 0x008c: 0x0020, + 0x008d: 0x0020, + 0x008e: 0x005a, + 0x008f: 0x0020, + 0x0090: 0x0020, + 0x0091: 0x0027, + 0x0092: 0x0027, + 0x0093: 0x0022, + 0x0094: 0x0022, + 0x0095: 0x00a5, + 0x0096: 0x00b0, + 0x0097: 0x00b0, + 0x0098: 0x00b0, + 0x0099: 0x0020, + 0x009a: 0x0073, + 0x009b: 0x003e, + 0x009c: 0x0020, + 0x009d: 0x0020, + 0x009e: 0x007a, + 0x009f: 0x0059, + 0x00a0: 0x00ff, # NO-BREAK SPACE + 0x00a1: 0x0021, # INVERTED EXCLAMATION MARK + 0x00a2: 0x0020, # CENT SIGN + 0x00a3: 0x0020, # POUND SIGN + 0x00a4: 0x0020, # CURRENCY SIGN + 0x00a5: 0x005c, # YEN SIGN + 0x00a6: 0x007c, # BROKEN BAR + 0x00a7: 0x0020, # SECTION SIGN + 0x00a8: 0x0022, # DIAERESIS + 0x00a9: 0x0020, # COPYRIGHT SIGN + 0x00aa: 0x0020, # FEMININE ORDINAL INDICATOR + 0x00ab: 0x00ff, # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00ac: 0x000e, # NOT SIGN -- FIXME? + 0x00ad: 0x000a, # SOFT HYPHEN -- FIXME? + 0x00ae: 0x0009, # REGISTERED SIGN -- FIXME? + 0x00af: 0x0008, # MACRON -- FIXME? + 0x00b0: 0x00df, # DEGREE SIGN + 0x00b1: 0x0020, # PLUS-MINUS SIGN + 0x00b2: 0x0020, # SUPERSCRIPT TWO + 0x00b3: 0x0020, # SUPERSCRIPT THREE + 0x00b4: 0x0027, # ACUTE ACCENT + 0x00b5: 0x00e4, # MICRO SIGN + 0x00b6: 0x0020, # PILCROW SIGN + 0x00b7: 0x00a5, # MIDDLE DOT + 0x00b8: 0x0020, # CEDILLA + 0x00b9: 0x0020, # SUPERSCRIPT ONE + 0x00ba: 0x00df, # MASCULINE ORDINAL INDICATOR + 0x00bb: 0x003e, # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00bc: 0x0020, # VULGAR FRACTION ONE QUARTER + 0x00bd: 0x0020, # VULGAR FRACTION ONE HALF + 0x00be: 0x0020, # VULGAR FRACTION THREE QUARTERS + 0x00bf: 0x003f, # INVERTED QUESTION MARK + 0x00c0: 0x0041, # LATIN CAPITAL LETTER A WITH GRAVE + 0x00c1: 0x0041, # LATIN CAPITAL LETTER A WITH ACUTE + 0x00c2: 0x0041, # LATIN CAPITAL LETTER A WITH CIRCUMFLEX + 0x00c3: 0x0041, # LATIN CAPITAL LETTER A WITH TILDE + 0x00c4: 0x0041, # LATIN CAPITAL LETTER A WITH DIAERESIS + 0x00c5: 0x0041, # LATIN CAPITAL LETTER A WITH RING ABOVE + 0x00c6: 0x0020, # LATIN CAPITAL LETTER AE + 0x00c7: 0x0043, # LATIN CAPITAL LETTER C WITH CEDILLA + 0x00c8: 0x0045, # LATIN CAPITAL LETTER E WITH GRAVE + 0x00c9: 0x0045, # LATIN CAPITAL LETTER E WITH ACUTE + 0x00ca: 0x0045, # LATIN CAPITAL LETTER E WITH CIRCUMFLEX + 0x00cb: 0x0045, # LATIN CAPITAL LETTER E WITH DIAERESIS + 0x00cc: 0x0049, # LATIN CAPITAL LETTER I WITH GRAVE + 0x00cd: 0x0049, # LATIN CAPITAL LETTER I WITH ACUTE + 0x00ce: 0x0049, # LATIN CAPITAL LETTER I WITH CIRCUMFLEX + 0x00cf: 0x0049, # LATIN CAPITAL LETTER I WITH DIAERESIS + 0x00d0: 0x0044, # LATIN CAPITAL LETTER ETH + 0x00d1: 0x004e, # LATIN CAPITAL LETTER N WITH TILDE + 0x00d2: 0x004f, # LATIN CAPITAL LETTER O WITH GRAVE + 0x00d3: 0x004f, # LATIN CAPITAL LETTER O WITH ACUTE + 0x00d4: 0x004f, # LATIN CAPITAL LETTER O WITH CIRCUMFLEX + 0x00d5: 0x004f, # LATIN CAPITAL LETTER O WITH TILDE + 0x00d6: 0x004f, # LATIN CAPITAL LETTER O WITH DIAERESIS + 0x00d7: 0x0078, # MULTIPLICATION SIGN + 0x00d8: 0x0030, # LATIN CAPITAL LETTER O WITH STROKE + 0x00d9: 0x0055, # LATIN CAPITAL LETTER U WITH GRAVE + 0x00da: 0x0055, # LATIN CAPITAL LETTER U WITH ACUTE + 0x00db: 0x0055, # LATIN CAPITAL LETTER U WITH CIRCUMFLEX + 0x00dc: 0x0055, # LATIN CAPITAL LETTER U WITH DIAERESIS + 0x00dd: 0x0059, # LATIN CAPITAL LETTER Y WITH ACUTE + 0x00de: 0x0020, # LATIN CAPITAL LETTER THORN + 0x00df: 0x00e2, # LATIN SMALL LETTER SHARP + 0x00e0: 0x0061, # LATIN SMALL LETTER A WITH GRAVE + 0x00e1: 0x0061, # LATIN SMALL LETTER A WITH ACUTE + 0x00e2: 0x0061, # LATIN SMALL LETTER A WITH CIRCUMFLEX + 0x00e3: 0x0061, # LATIN SMALL LETTER A WITH TILDE + 0x00e4: 0x00e1, # LATIN SMALL LETTER A WITH DIAERESIS + 0x00e5: 0x0061, # LATIN SMALL LETTER A WITH RING ABOVE + 0x00e6: 0x0020, # LATIN SMALL LETTER AE + 0x00e7: 0x0063, # LATIN SMALL LETTER C WITH CEDILLA + 0x00e8: 0x0065, # LATIN SMALL LETTER E WITH GRAVE + 0x00e9: 0x0065, # LATIN SMALL LETTER E WITH ACUTE + 0x00ea: 0x0065, # LATIN SMALL LETTER E WITH CIRCUMFLEX + 0x00eb: 0x0065, # LATIN SMALL LETTER E WITH DIAERESIS + 0x00ec: 0x0069, # LATIN SMALL LETTER I WITH GRAVE + 0x00ed: 0x0069, # LATIN SMALL LETTER I WITH ACUTE + 0x00ee: 0x0069, # LATIN SMALL LETTER I WITH CIRCUMFLEX + 0x00ef: 0x0069, # LATIN SMALL LETTER I WITH DIAERESIS + 0x00f0: 0x006f, # LATIN SMALL LETTER ETH + 0x00f1: 0x006e, # LATIN SMALL LETTER N WITH TILDE + 0x00f2: 0x006f, # LATIN SMALL LETTER O WITH GRAVE + 0x00f3: 0x006f, # LATIN SMALL LETTER O WITH ACUTE + 0x00f4: 0x006f, # LATIN SMALL LETTER O WITH CIRCUMFLEX + 0x00f5: 0x006f, # LATIN SMALL LETTER O WITH TILDE + 0x00f6: 0x00ef, # LATIN SMALL LETTER O WITH DIAERESIS + 0x00f7: 0x00fd, # DIVISION SIGN + 0x00f8: 0x006f, # LATIN SMALL LETTER O WITH STROKE + 0x00f9: 0x0075, # LATIN SMALL LETTER U WITH GRAVE + 0x00fa: 0x0075, # LATIN SMALL LETTER U WITH ACUTE + 0x00fb: 0x0075, # LATIN SMALL LETTER U WITH CIRCUMFLEX + 0x00fc: 0x00f5, # LATIN SMALL LETTER U WITH DIAERESIS + 0x00fd: 0x0079, # LATIN SMALL LETTER Y WITH ACUTE + 0x00fe: 0x0020, # LATIN SMALL LETTER THORN + 0x00ff: 0x0079, # LATIN SMALL LETTER Y WITH DIAERESIS +# Polish letters mapping replacements + 0x0104: 0x0041, # LATIN CAPITAL LETTER A WITH OGONEK + 0x0105: 0x0061, # LATIN SMALL LETTER A WITH OGONEK + 0x0106: 0x0043, # LATIN CAPITAL LETTER C WITH ACUTE + 0x0107: 0x0063, # LATIN SMALL LETTER C WITH ACUTE + 0x0118: 0x0045, # LATIN CAPITAL LETTER E WITH OGONEK + 0x0119: 0x0065, # LATIN SMALL LETTER E WITH OGONEK + 0x0141: 0x004c, # LATIN CAPITAL LETTER L WITH STROKE + 0x0142: 0x006c, # LATIN SMALL LETTER L WITH STROKE + 0x0143: 0x004e, # LATIN CAPITAL LETTER N WITH ACUTE + 0x0144: 0x006e, # LATIN SMALL LETTER N WITH ACUTE + 0x015a: 0x0053, # LATIN CAPITAL LETTER S WITH ACUTE + 0x015b: 0x0073, # LATIN SMALL LETTER S WITH ACUTE + 0x0179: 0x005a, # LATIN CAPITAL LETTER Z WITH ACUTE + 0x017a: 0x007a, # LATIN SMALL LETTER Z WITH ACUTE + 0x017b: 0x005a, # LATIN CAPITAL LETTER Z WITH DOT ABOVE + 0x017c: 0x007a, # LATIN SMALL LETTER Z WITH DOT ABOVE + 0x0230: 0x004f, # LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON +# Greek letters, technical symbols and misc + 0x2190: 0x007f, # LEFTWARDS ARROW + 0x2192: 0x007e, # RIGHTWARDS ARROW +} diff --git a/resources/lib/charset_map_hd44780_a02.py b/resources/lib/charset_map_hd44780_a02.py new file mode 100644 index 00000000..8886d8bc --- /dev/null +++ b/resources/lib/charset_map_hd44780_a02.py @@ -0,0 +1,390 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# XBMC LCDproc addon +# Copyright (C) 2012-2024 Team Kodi +# Copyright (C) 2012-2024 Daniel 'herrnst' Scheller +# +# HD44780-A02 char map +# + +encmap_hd44780_a02 = { + 0x0000: 0x0000, # NULL + # 0x0001: 0x0001, # START OF HEADING + # 0x0002: 0x0002, # START OF TEXT + # 0x0003: 0x0003, # END OF TEXT + # 0x0004: 0x0004, # END OF TRANSMISSION + # 0x0005: 0x0005, # ENQUIRY + # 0x0006: 0x0006, # ACKNOWLEDGE + # 0x0007: 0x0007, # BELL + # 0x0008: 0x0008, # BACKSPACE + # 0x0009: 0x0009, # HORIZONTAL TABULATION + # 0x000a: 0x000a, # LINE FEED + # 0x000b: 0x000b, # VERTICAL TABULATION + # 0x000c: 0x000c, # FORM FEED + # 0x000d: 0x000d, # CARRIAGE RETURN + # 0x000e: 0x000e, # SHIFT OUT + # 0x000f: 0x000f, # SHIFT IN + # 0x0010: 0x0010, # DATA LINK ESCAPE + # 0x0011: 0x0011, # DEVICE CONTROL ONE + # 0x0012: 0x0012, # DEVICE CONTROL TWO + # 0x0013: 0x0013, # DEVICE CONTROL THREE + # 0x0014: 0x0014, # DEVICE CONTROL FOUR + # 0x0015: 0x0015, # NEGATIVE ACKNOWLEDGE + # 0x0016: 0x0016, # SYNCHRONOUS IDLE + # 0x0017: 0x0017, # END OF TRANSMISSION BLOCK + # 0x0018: 0x0018, # CANCEL + # 0x0019: 0x0019, # END OF MEDIUM + # 0x001a: 0x001a, # SUBSTITUTE + # 0x001b: 0x001b, # ESCAPE + # 0x001c: 0x001c, # INFORMATION SEPARATOR FOUR + # 0x001d: 0x001d, # INFORMATION SEPARATOR THREE + # 0x001e: 0x001e, # INFORMATION SEPARATOR TWO + # 0x001f: 0x001f, # INFORMATION SEPARATOR ONE + 0x0020: 0x0020, # SPACE + 0x0021: 0x0021, # EXCLAMATION MARK + 0x0022: 0x0022, # QUOTATION MARK + 0x0023: 0x0023, # NUMBER SIGN + 0x0024: 0x0024, # DOLLAR SIGN + 0x0025: 0x0025, # PERCENT SIGN + 0x0026: 0x0026, # AMPERSAND + 0x0027: 0x0027, # APOSTROPHE + 0x0028: 0x0028, # LEFT PARENTHESIS + 0x0029: 0x0029, # RIGHT PARENTHESIS + 0x002a: 0x002a, # ASTERISK + 0x002b: 0x002b, # PLUS SIGN + 0x002c: 0x002c, # COMMA + 0x002d: 0x002d, # HYPHEN-MINUS + 0x002e: 0x002e, # FULL STOP + 0x002f: 0x002f, # SOLIDUS + 0x0030: 0x0030, # DIGIT ZERO + 0x0031: 0x0031, # DIGIT ONE + 0x0032: 0x0032, # DIGIT TWO + 0x0033: 0x0033, # DIGIT THREE + 0x0034: 0x0034, # DIGIT FOUR + 0x0035: 0x0035, # DIGIT FIVE + 0x0036: 0x0036, # DIGIT SIX + 0x0037: 0x0037, # DIGIT SEVEN + 0x0038: 0x0038, # DIGIT EIGHT + 0x0039: 0x0039, # DIGIT NINE + 0x003a: 0x003a, # COLON + 0x003b: 0x003b, # SEMICOLON + 0x003c: 0x003c, # LESS-THAN SIGN + 0x003d: 0x003d, # EQUALS SIGN + 0x003e: 0x003e, # GREATER-THAN SIGN + 0x003f: 0x003f, # QUESTION MARK + 0x0040: 0x0040, # COMMERCIAL AT + 0x0041: 0x0041, # LATIN CAPITAL LETTER A + 0x0042: 0x0042, # LATIN CAPITAL LETTER B + 0x0043: 0x0043, # LATIN CAPITAL LETTER C + 0x0044: 0x0044, # LATIN CAPITAL LETTER D + 0x0045: 0x0045, # LATIN CAPITAL LETTER E + 0x0046: 0x0046, # LATIN CAPITAL LETTER F + 0x0047: 0x0047, # LATIN CAPITAL LETTER G + 0x0048: 0x0048, # LATIN CAPITAL LETTER H + 0x0049: 0x0049, # LATIN CAPITAL LETTER I + 0x004a: 0x004a, # LATIN CAPITAL LETTER J + 0x004b: 0x004b, # LATIN CAPITAL LETTER K + 0x004c: 0x004c, # LATIN CAPITAL LETTER L + 0x004d: 0x004d, # LATIN CAPITAL LETTER M + 0x004e: 0x004e, # LATIN CAPITAL LETTER N + 0x004f: 0x004f, # LATIN CAPITAL LETTER O + 0x0050: 0x0050, # LATIN CAPITAL LETTER P + 0x0051: 0x0051, # LATIN CAPITAL LETTER Q + 0x0052: 0x0052, # LATIN CAPITAL LETTER R + 0x0053: 0x0053, # LATIN CAPITAL LETTER S + 0x0054: 0x0054, # LATIN CAPITAL LETTER T + 0x0055: 0x0055, # LATIN CAPITAL LETTER U + 0x0056: 0x0056, # LATIN CAPITAL LETTER V + 0x0057: 0x0057, # LATIN CAPITAL LETTER W + 0x0058: 0x0058, # LATIN CAPITAL LETTER X + 0x0059: 0x0059, # LATIN CAPITAL LETTER Y + 0x005a: 0x005a, # LATIN CAPITAL LETTER Z + 0x005b: 0x005b, # LEFT SQUARE BRACKET + 0x005c: 0x005c, # REVERSE SOLIDUS + 0x005d: 0x005d, # RIGHT SQUARE BRACKET + 0x005e: 0x005e, # CIRCUMFLEX ACCENT + 0x005f: 0x005f, # LOW LINE + 0x0060: 0x0060, # GRAVE ACCENT + 0x0061: 0x0061, # LATIN SMALL LETTER A + 0x0062: 0x0062, # LATIN SMALL LETTER B + 0x0063: 0x0063, # LATIN SMALL LETTER C + 0x0064: 0x0064, # LATIN SMALL LETTER D + 0x0065: 0x0065, # LATIN SMALL LETTER E + 0x0066: 0x0066, # LATIN SMALL LETTER F + 0x0067: 0x0067, # LATIN SMALL LETTER G + 0x0068: 0x0068, # LATIN SMALL LETTER H + 0x0069: 0x0069, # LATIN SMALL LETTER I + 0x006a: 0x006a, # LATIN SMALL LETTER J + 0x006b: 0x006b, # LATIN SMALL LETTER K + 0x006c: 0x006c, # LATIN SMALL LETTER L + 0x006d: 0x006d, # LATIN SMALL LETTER M + 0x006e: 0x006e, # LATIN SMALL LETTER N + 0x006f: 0x006f, # LATIN SMALL LETTER O + 0x0070: 0x0070, # LATIN SMALL LETTER P + 0x0071: 0x0071, # LATIN SMALL LETTER Q + 0x0072: 0x0072, # LATIN SMALL LETTER R + 0x0073: 0x0073, # LATIN SMALL LETTER S + 0x0074: 0x0074, # LATIN SMALL LETTER T + 0x0075: 0x0075, # LATIN SMALL LETTER U + 0x0076: 0x0076, # LATIN SMALL LETTER V + 0x0077: 0x0077, # LATIN SMALL LETTER W + 0x0078: 0x0078, # LATIN SMALL LETTER X + 0x0079: 0x0079, # LATIN SMALL LETTER Y + 0x007a: 0x007a, # LATIN SMALL LETTER Z + 0x007b: 0x007b, # LEFT CURLY BRACKET + 0x007c: 0x007c, # VERTICAL LINE + 0x007d: 0x007d, # RIGHT CURLY BRACKET + 0x007e: 0x007e, # TILDE + 0x007f: 0x0020, # DELETE + # 0x0080: + # 0x0081: + # 0x0082: + # 0x0083: + # 0x0084: + # 0x0085: + # 0x0086: + # 0x0087: + # 0x0088: + # 0x0089: + # 0x008a: + # 0x008b: + # 0x008c: + # 0x008d: + # 0x008e: + # 0x008f: + # 0x0090: + # 0x0091: + # 0x0092: + # 0x0093: + # 0x0094: + # 0x0095: + # 0x0096: + # 0x0097: + # 0x0098: + # 0x0099: + # 0x009a: + # 0x009b: + # 0x009c: + # 0x009d: + # 0x009e: + # 0x009f: + 0x00a0: 0x0020, # NO-BREAK SPACE + 0x00a1: 0x00a1, # INVERTED EXCLAMATION MARK + 0x00a2: 0x00a2, # CENT SIGN + 0x00a3: 0x00a3, # POUND SIGN + 0x00a4: 0x00a4, # CURRENCY SIGN + 0x00a5: 0x00a5, # YEN SIGN + 0x00a6: 0x00a6, # BROKEN BAR + 0x00a7: 0x00a7, # SECTION SIGN + # 0x00a8: # DIAERESIS + 0x00a9: 0x00a9, # COPYRIGHT SIGN + 0x00aa: 0x00aa, # FEMININE ORDINAL INDICATOR + 0x00ab: 0x00ab, # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK + # 0x00ac: # NOT SIGN + # 0x00ad: # SOFT HYPHEN + 0x00ae: 0x00ae, # REGISTERED SIGN + # 0x00af: # MACRON + 0x00b0: 0x00b0, # DEGREE SIGN + 0x00b1: 0x00b1, # PLUS-MINUS SIGN + 0x00b2: 0x00b2, # SUPERSCRIPT TWO + 0x00b3: 0x00b3, # SUPERSCRIPT THREE + # 0x00b4: # ACUTE ACCENT + 0x00b5: 0x00b5, # MICRO SIGN + 0x00b6: 0x00b6, # PILCROW SIGN + 0x00b7: 0x00b7, # MIDDLE DOT + # 0x00b8: # CEDILLA + 0x00b9: 0x00b9, # SUPERSCRIPT ONE + 0x00ba: 0x00ba, # MASCULINE ORDINAL INDICATOR + 0x00bb: 0x00bb, # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK + 0x00bc: 0x00bc, # VULGAR FRACTION ONE QUARTER + 0x00bd: 0x00bd, # VULGAR FRACTION ONE HALF + 0x00be: 0x00be, # VULGAR FRACTION THREE QUARTERS + 0x00bf: 0x00bf, # INVERTED QUESTION MARK + 0x00c0: 0x00c0, # LATIN CAPITAL LETTER A WITH GRAVE + 0x00c1: 0x00c1, # LATIN CAPITAL LETTER A WITH ACUTE + 0x00c2: 0x00c2, # LATIN CAPITAL LETTER A WITH CIRCUMFLEX + 0x00c3: 0x00c3, # LATIN CAPITAL LETTER A WITH TILDE + 0x00c4: 0x00c4, # LATIN CAPITAL LETTER A WITH DIAERESIS + 0x00c5: 0x00c5, # LATIN CAPITAL LETTER A WITH RING ABOVE + 0x00c6: 0x00c6, # LATIN CAPITAL LETTER AE + 0x00c7: 0x00c7, # LATIN CAPITAL LETTER C WITH CEDILLA + 0x010c: 0x0043, # LATIN CAPITAL LETTER C WITH CARON + 0x010e: 0x0044, # LATIN CAPITAL LETTER D WITH CARON + 0x00c8: 0x00c8, # LATIN CAPITAL LETTER E WITH GRAVE + 0x00c9: 0x00c9, # LATIN CAPITAL LETTER E WITH ACUTE + 0x00ca: 0x00ca, # LATIN CAPITAL LETTER E WITH CIRCUMFLEX + 0x00cb: 0x00cb, # LATIN CAPITAL LETTER E WITH DIAERESIS + 0x011a: 0x0045, # LATIN CAPITAL LETTER E WITH CARON + 0x00cc: 0x00cc, # LATIN CAPITAL LETTER I WITH GRAVE + 0x00cd: 0x00cd, # LATIN CAPITAL LETTER I WITH ACUTE + 0x00ce: 0x00ce, # LATIN CAPITAL LETTER I WITH CIRCUMFLEX + 0x00cf: 0x00cf, # LATIN CAPITAL LETTER I WITH DIAERESIS + 0x00d0: 0x00d0, # LATIN CAPITAL LETTER ETH + 0x00d1: 0x00d1, # LATIN CAPITAL LETTER N WITH TILDE + 0x0147: 0x004e, # LATIN CAPITAL LETTER N WITH CARON + 0x00d2: 0x00d2, # LATIN CAPITAL LETTER O WITH GRAVE + 0x00d3: 0x00d3, # LATIN CAPITAL LETTER O WITH ACUTE + 0x00d4: 0x00d4, # LATIN CAPITAL LETTER O WITH CIRCUMFLEX + 0x00d5: 0x00d5, # LATIN CAPITAL LETTER O WITH TILDE + 0x00d6: 0x00d6, # LATIN CAPITAL LETTER O WITH DIAERESIS + 0x00d7: 0x00d7, # MULTIPLICATION SIGN + # 0x00d8: # LATIN CAPITAL LETTER O WITH STROKE + 0x0158: 0x0052, # LATIN CAPITAL LETTER R WITH CARON + 0x0160: 0x0053, # LATIN CAPITAL LETTER S WITH CARON + 0x0164: 0x0054, # LATIN CAPITAL LETTER T WITH CARON + 0x00d9: 0x00d9, # LATIN CAPITAL LETTER U WITH GRAVE + 0x00da: 0x00da, # LATIN CAPITAL LETTER U WITH ACUTE + 0x00db: 0x00db, # LATIN CAPITAL LETTER U WITH CIRCUMFLEX + 0x00dc: 0x00dc, # LATIN CAPITAL LETTER U WITH DIAERESIS + 0x00dd: 0x00dd, # LATIN CAPITAL LETTER Y WITH ACUTE + 0x016e: 0x0055, # LATIN CAPITAL LETTER U WITH RING ABOVE + 0x017d: 0x005a, # LATIN CAPITAL LETTER Z WITH CARON + 0x00de: 0x00de, # LATIN CAPITAL LETTER THORN + 0x00df: 0x00df, # LATIN SMALL LETTER SHARP + 0x00e0: 0x00e0, # LATIN SMALL LETTER A WITH GRAVE + 0x00e1: 0x00e1, # LATIN SMALL LETTER A WITH ACUTE + 0x00e2: 0x00e2, # LATIN SMALL LETTER A WITH CIRCUMFLEX + 0x00e3: 0x00e3, # LATIN SMALL LETTER A WITH TILDE + 0x00e4: 0x00e4, # LATIN SMALL LETTER A WITH DIAERESIS + 0x00e5: 0x00e5, # LATIN SMALL LETTER A WITH RING ABOVE + 0x00e6: 0x00e6, # LATIN SMALL LETTER AE + 0x00e7: 0x00e7, # LATIN SMALL LETTER C WITH CEDILLA + 0x010d: 0x0063, # LATIN SMALL LETTER C WITH CARON + 0x010f: 0x0064, # LATIN SMALL LETTER D WITH CARON + 0x00e8: 0x00e8, # LATIN SMALL LETTER E WITH GRAVE + 0x00e9: 0x00e9, # LATIN SMALL LETTER E WITH ACUTE + 0x00ea: 0x00ea, # LATIN SMALL LETTER E WITH CIRCUMFLEX + 0x00eb: 0x00eb, # LATIN SMALL LETTER E WITH DIAERESIS + 0x011b: 0x0065, # LATIN SMALL LETTER E WITH CARON + 0x00ec: 0x00ec, # LATIN SMALL LETTER I WITH GRAVE + 0x00ed: 0x00ed, # LATIN SMALL LETTER I WITH ACUTE + 0x00ee: 0x00ee, # LATIN SMALL LETTER I WITH CIRCUMFLEX + 0x00ef: 0x00ef, # LATIN SMALL LETTER I WITH DIAERESIS + 0x00f0: 0x00f0, # LATIN SMALL LETTER ETH + 0x00f1: 0x00f1, # LATIN SMALL LETTER N WITH TILDE + 0x0148: 0x006e, # LATIN SMALL LETTER N WITH CARON + 0x00f2: 0x00f2, # LATIN SMALL LETTER O WITH GRAVE + 0x00f3: 0x00f3, # LATIN SMALL LETTER O WITH ACUTE + 0x00f4: 0x00f4, # LATIN SMALL LETTER O WITH CIRCUMFLEX + 0x00f5: 0x00f5, # LATIN SMALL LETTER O WITH TILDE + 0x00f6: 0x00f6, # LATIN SMALL LETTER O WITH DIAERESIS + 0x00f7: 0x00f7, # DIVISION SIGN + 0x00f8: 0x00f8, # LATIN SMALL LETTER O WITH STROKE + 0x0159: 0x0072, # LATIN SMALL LETTER R WITH CARON + 0x0161: 0x0073, # LATIN SMALL LETTER S WITH CARON + 0x0165: 0x0074, # LATIN SMALL LETTER T WITH CARON + 0x00f9: 0x00f9, # LATIN SMALL LETTER U WITH GRAVE + 0x00fa: 0x00fa, # LATIN SMALL LETTER U WITH ACUTE + 0x00fb: 0x00fb, # LATIN SMALL LETTER U WITH CIRCUMFLEX + 0x00fc: 0x00fc, # LATIN SMALL LETTER U WITH DIAERESIS + 0x016f: 0x0075, # LATIN SMALL LETTER U WITH RING ABOVE + 0x00fd: 0x00fd, # LATIN SMALL LETTER Y WITH ACUTE + 0x00fe: 0x00fe, # LATIN SMALL LETTER THORN + 0x00ff: 0x00ff, # LATIN SMALL LETTER Y WITH DIAERESIS + 0x017e: 0x007a, # LATIN SMALL LETTER Z WITH CARON +# Capital cyrillic letters + 0x0401: 0x00cb, # CYRILLIC CAPITAL LETTER IO + 0x0410: 0x0041, # CYRILLIC CAPITAL LETTER A + 0x0411: 0x0080, # CYRILLIC CAPITAL LETTER BE + 0x0412: 0x0042, # CYRILLIC CAPITAL LETTER VE + 0x0413: 0x0092, # CYRILLIC CAPITAL LETTER GHE + 0x0414: 0x0081, # CYRILLIC CAPITAL LETTER DE + 0x0415: 0x0045, # CYRILLIC CAPITAL LETTER IE + 0x0416: 0x0082, # CYRILLIC CAPITAL LETTER GJE + 0x0417: 0x0083, # CYRILLIC CAPITAL LETTER ZE + 0x0418: 0x0084, # CYRILLIC CAPITAL LETTER I + 0x0419: 0x0085, # CYRILLIC CAPITAL LETTER SHORT I + 0x041a: 0x004b, # CYRILLIC CAPITAL LETTER KA + 0x041b: 0x0086, # CYRILLIC CAPITAL LETTER EL + 0x041c: 0x004d, # CYRILLIC CAPITAL LETTER EM + 0x041d: 0x0048, # CYRILLIC CAPITAL LETTER EN + 0x041e: 0x004f, # CYRILLIC CAPITAL LETTER O + 0x041f: 0x0087, # CYRILLIC CAPITAL LETTER PE + 0x0420: 0x0050, # CYRILLIC CAPITAL LETTER ER + 0x0421: 0x0043, # CYRILLIC CAPITAL LETTER ES + 0x0422: 0x0054, # CYRILLIC CAPITAL LETTER TE + 0x0423: 0x0088, # CYRILLIC CAPITAL LETTER U + 0x0424: 0x00d8, # CYRILLIC CAPITAL LETTER EF + 0x0425: 0x0058, # CYRILLIC CAPITAL LETTER HA + 0x0426: 0x0089, # CYRILLIC CAPITAL LETTER TSE + 0x0427: 0x008a, # CYRILLIC CAPITAL LETTER CHE + 0x0428: 0x008b, # CYRILLIC CAPITAL LETTER SHA + 0x0429: 0x008c, # CYRILLIC CAPITAL LETTER SHCHA + 0x042a: 0x008d, # CYRILLIC CAPITAL LETTER HARD SIGN + 0x042b: 0x008e, # CYRILLIC CAPITAL LETTER YERU + 0x042c: 0x0062, # CYRILLIC CAPITAL LETTER SOFT SIGN + 0x042d: 0x008f, # CYRILLIC CAPITAL LETTER E + 0x042e: 0x00ac, # CYRILLIC CAPITAL LETTER YU + 0x042f: 0x00ad, # CYRILLIC CAPITAL LETTER YA +# Small Cyrillc letters + 0x0430: 0x0041, # CYRILLIC SMALL LETTER A + 0x0431: 0x0080, # CYRILLIC SMALL LETTER BE + 0x0432: 0x0042, # CYRILLIC SMALL LETTER VE + 0x0433: 0x0092, # CYRILLIC SMALL LETTER GHE + 0x0434: 0x0081, # CYRILLIC SMALL LETTER DE + 0x0435: 0x0045, # CYRILLIC SMALL LETTER IE + 0x0436: 0x0082, # CYRILLIC SMALL LETTER ZHE + 0x0437: 0x0083, # CYRILLIC SMALL LETTER ZE + 0x0438: 0x0084, # CYRILLIC SMALL LETTER I + 0x0439: 0x0085, # CYRILLIC SMALL LETTER SHORT I + 0x043a: 0x004b, # CYRILLIC SMALL LETTER KA + 0x043b: 0x0086, # CYRILLIC SMALL LETTER EL + 0x043c: 0x004d, # CYRILLIC SMALL LETTER EM + 0x043d: 0x0048, # CYRILLIC SMALL LETTER EN + 0x043e: 0x004f, # CYRILLIC SMALL LETTER O + 0x043f: 0x0087, # CYRILLIC SMALL LETTER PE + 0x0440: 0x0050, # CYRILLIC SMALL LETTER ER + 0x0441: 0x0043, # CYRILLIC SMALL LETTER ES + 0x0442: 0x0054, # CYRILLIC SMALL LETTER TE + 0x0443: 0x0088, # CYRILLIC SMALL LETTER U + 0x0444: 0x00d8, # CYRILLIC SMALL LETTER EF + 0x0445: 0x0058, # CYRILLIC SMALL LETTER HA + 0x0446: 0x0089, # CYRILLIC SMALL LETTER TSE + 0x0447: 0x008a, # CYRILLIC SMALL LETTER CHE + 0x0448: 0x008b, # CYRILLIC SMALL LETTER SHA + 0x0449: 0x008c, # CYRILLIC SMALL LETTER SHCHA + 0x044a: 0x008d, # CYRILLIC SMALL LETTER HARD SIGN + 0x044b: 0x008e, # CYRILLIC SMALL LETTER YERU + 0x044c: 0x0062, # CYRILLIC SMALL LETTER SOFT SIGN + 0x044d: 0x008f, # CYRILLIC SMALL LETTER E + 0x044e: 0x00ac, # CYRILLIC SMALL LETTER YU + 0x044f: 0x00ad, # CYRILLIC SMALL LETTER YA + 0x0451: 0x00cb, # CYRILLIC SMALL LETTER IO +# Greek letters, technical symbols and misc + 0x0192: 0x00a8, # LATIN SMALL LETTER F WITH HOOK + 0x0398: 0x0099, # GREEK CAPITAL LETTER THETA + 0x03a3: 0x0094, # GREEK CAPITAL LETTER SIGMA + 0x03a9: 0x009a, # GREEK CAPITAL LETTER OMEGA + 0x03b1: 0x0090, # GREEK SMALL LETTER ALPHA + 0x03b4: 0x009b, # GREEK SMALL LETTER DELTA + 0x03b5: 0x009e, # GREEK SMALL LETTER EPSILON + 0x03c0: 0x0093, # GREEK SMALL LETTER PI + 0x03c3: 0x0095, # GREEK SMALL LETTER SIGMA + 0x03c4: 0x0097, # GREEK SMALL LETTER TAU + 0x03c9: 0x00b8, # GREEK SMALL LETTER OMEGA + 0x2016: 0x00a0, # DOUBLE VERTICAL LINE + 0x2018: 0x00af, # LEFT SINGLE QUOTATION MARK + 0x201c: 0x0012, # LEFT DOUBLE QUOTATION MARK + 0x201d: 0x0013, # RIGHT DOUBLE QUOTATION MARK + 0x2109: 0x00b4, # DEGREE FAHRENHEIT + 0x2190: 0x001b, # LEFTWARDS ARROW + 0x2191: 0x0018, # UPWARDS ARROW + 0x2192: 0x001a, # RIGHTWARDS ARROW + 0x2193: 0x0019, # DOWNWARDS ARROW + 0x21b2: 0x0017, # DOWNWARDS ARROW WITH TIP LEFTWARDS + 0x221e: 0x009c, # INFINITY + 0x2229: 0x009f, # INTERSECTION + 0x2264: 0x001c, # LESS-THAN OR EQUAL TO + 0x2265: 0x001d, # GREATER-THAN OR EQUAL TO + 0x23eb: 0x0014, # BLACK UP-POINTING DOUBLE TRIANGLE + 0x23ec: 0x0015, # BLACK DOWN-POINTING DOUBLE TRIANGLE + 0x25b2: 0x001e, # BLACK UP-POINTING TRIANGLE + 0x25b6: 0x0010, # BLACK RIGHT-POINTING TRIANGLE + 0x25bc: 0x001f, # BLACK DOWN-POINTING TRIANGLE + 0x25c0: 0x0011, # BLACK LEFT-POINTING TRIANGLE + 0x2664: 0x009d, # HEAVY BLACK HEART + 0x266a: 0x0091, # EIGHTH NOTE + 0x266c: 0x0096, # BEAMED SIXTEENTH NOTES + 0x2b24: 0x0016, # BLACK LARGE CIRCLE + 0xf0f3: 0x0098 # BELL ICON (not sure) +} diff --git a/resources/lib/common.py b/resources/lib/common.py new file mode 100644 index 00000000..b96145af --- /dev/null +++ b/resources/lib/common.py @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# XBMC LCDproc addon +# Copyright (C) 2012-2024 Team Kodi +# Copyright (C) 2012-2024 Daniel 'herrnst' Scheller +# +# Common defines and functionality used throughout the whole addon +# + +import os + +import xbmc +import xbmcaddon + +KODI_ADDON_ID = "script.xbmc.lcdproc" +KODI_ADDON_NAME = "XBMC LCDproc" +KODI_ADDON_SETTINGS = xbmcaddon.Addon(id=KODI_ADDON_ID) +KODI_ADDON_ROOTPATH = KODI_ADDON_SETTINGS.getAddonInfo("path") +KODI_ADDON_ICON = os.path.join(KODI_ADDON_ROOTPATH, "resources", "icon.png") + +# copy loglevel defines to the global scope +LOGDEBUG = xbmc.LOGDEBUG +LOGERROR = xbmc.LOGERROR +LOGFATAL = xbmc.LOGFATAL +LOGINFO = xbmc.LOGINFO +LOGNONE = xbmc.LOGNONE +LOGWARNING = xbmc.LOGWARNING + +# interesting Kodi GUI Window IDs (no defines seem to exist for this) +class WINDOW_IDS: + WINDOW_WEATHER = 12600 + WINDOW_PVR = 10601 + WINDOW_PVR_MAX = 10799 + WINDOW_VIDEO_NAV = 10025 + WINDOW_VIDEO_PLAYLIST = 10028 + WINDOW_MUSIC_PLAYLIST = 10500 + WINDOW_MUSIC_NAV = 10502 + WINDOW_MUSIC_PLAYLIST_EDITOR = 10503 + WINDOW_PICTURES = 10002 + WINDOW_DIALOG_VOLUME_BAR = 10104 + WINDOW_DIALOG_KAI_TOAST = 10107 + +# log wrapper +def log(loglevel, msg): + xbmc.log("### [%s] - %s" % (KODI_ADDON_NAME, msg), level=loglevel) diff --git a/resources/lib/extraicons.py b/resources/lib/extraicons.py new file mode 100644 index 00000000..4584f943 --- /dev/null +++ b/resources/lib/extraicons.py @@ -0,0 +1,60 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# XBMC LCDproc addon +# Copyright (C) 2012-2024 Team Kodi +# Copyright (C) 2012-2024 Daniel 'herrnst' Scheller +# +# Extra icon defines/enums +# + +LCD_EXTRABARS_MAX = 4 + +class LCD_EXTRAICONS: + LCD_EXTRAICON_NONE = 0 + LCD_EXTRAICON_PLAYING = 1 + LCD_EXTRAICON_PAUSE = 2 + LCD_EXTRAICON_MOVIE = 3 + LCD_EXTRAICON_MUSIC = 4 + LCD_EXTRAICON_WEATHER = 5 + LCD_EXTRAICON_TV = 6 + LCD_EXTRAICON_PHOTO = 7 + LCD_EXTRAICON_WEBCASTING = 8 + LCD_EXTRAICON_MUTE = 9 + LCD_EXTRAICON_REPEAT = 10 + LCD_EXTRAICON_SHUFFLE = 11 + LCD_EXTRAICON_ALARM = 12 + LCD_EXTRAICON_RECORD = 13 + LCD_EXTRAICON_VOLUME = 14 + LCD_EXTRAICON_TIME = 15 + LCD_EXTRAICON_SPDIF = 16 + LCD_EXTRAICON_DISC_IN = 17 + LCD_EXTRAICON_SCR1 = 18 + LCD_EXTRAICON_SCR2 = 19 + LCD_EXTRAICON_RESOLUTION_SD = 20 + LCD_EXTRAICON_RESOLUTION_HD = 21 + LCD_EXTRAICON_VCODEC_MPEG = 22 + LCD_EXTRAICON_VCODEC_DIVX = 23 + LCD_EXTRAICON_VCODEC_XVID = 24 + LCD_EXTRAICON_VCODEC_WMV = 25 + LCD_EXTRAICON_ACODEC_MPEG = 26 + LCD_EXTRAICON_ACODEC_AC3 = 27 + LCD_EXTRAICON_ACODEC_DTS = 28 + LCD_EXTRAICON_ACODEC_VWMA = 29 # e.g. iMON has video-WMA AND audio-WMA... + LCD_EXTRAICON_ACODEC_MP3 = 30 + LCD_EXTRAICON_ACODEC_OGG = 31 + LCD_EXTRAICON_ACODEC_AWMA = 32 # see ACODEC_VWMA + LCD_EXTRAICON_ACODEC_WAV = 33 + LCD_EXTRAICON_OUTSOURCE = 34 + LCD_EXTRAICON_OUTFIT = 35 + LCD_EXTRAICON_OUT_2_0 = 36 + LCD_EXTRAICON_OUT_5_1 = 37 + LCD_EXTRAICON_OUT_7_1 = 38 + LCD_EXTRAICON_MAX = 39 + +class LCD_EXTRAICONCATEGORIES: + LCD_ICONCAT_MODES = 1 + LCD_ICONCAT_OUTSCALE = 2 + LCD_ICONCAT_CODECS = 3 + LCD_ICONCAT_VIDEOCODECS = 4 + LCD_ICONCAT_AUDIOCODECS = 5 + LCD_ICONCAT_AUDIOCHANNELS = 6 diff --git a/resources/lib/infolabels.py b/resources/lib/infolabels.py new file mode 100644 index 00000000..ab113703 --- /dev/null +++ b/resources/lib/infolabels.py @@ -0,0 +1,209 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# XBMC LCDproc addon +# Copyright (C) 2012-2024 Team Kodi +# Copyright (C) 2012-2024 Daniel 'herrnst' Scheller +# +# InfoLabel handling +# + +import sys +import time + +import xbmc +import xbmcgui + +from .common import WINDOW_IDS +from .settings import * + +class InfoLabels(): + + ######## + # ctor + def __init__(self, settings): + # take note of Settings instance + self._settings = settings + + # init members + self._nav_oldmenu = "" + self._nav_oldsubmenu = "" + self._navtimer = time.time() + + def GetInfoLabel(self, strLabel): + return xbmc.getInfoLabel(strLabel) + + def GetBool(self, strBool): + return xbmc.getCondVisibility(strBool) + + def GetActiveWindowID(self): + return int(xbmcgui.getCurrentWindowId()) + + def timeToSecs(self, timeAr): + # initialise return + currentSecs = 0 + + arLen = len(timeAr) + if arLen == 1: + currentSecs = int(timeAr[0]) + elif arLen == 2: + currentSecs = int(timeAr[0]) * 60 + int(timeAr[1]) + elif arLen == 3: + currentSecs = int(timeAr[0]) * 60 * 60 + int(timeAr[1]) * 60 + int(timeAr[2]) + + return currentSecs + + def WindowIsActive(self, WindowID): + return self.GetBool("Window.IsActive(" + str(WindowID) + ")") + + def PlayingVideo(self): + return self.GetBool("Player.HasVideo") + + def PlayingTVShow(self): + if self.PlayingVideo() and len(self.GetInfoLabel("VideoPlayer.TVShowTitle")): + return True + + return False + + def PlayingAudio(self): + return self.GetBool("Player.HasAudio") + + def PlayingLiveTV(self): + return self.GetBool("PVR.IsPlayingTV") + + def PlayingLiveRadio(self): + return self.GetBool("PVR.IsPlayingRadio") + + def GetSystemTime(self): + # apply some split magic for 12h format here, as "hh:mm:ss" + # makes up for format guessing inside XBMC - fix for post-frodo at + # https://github.com/xbmc/xbmc/pull/2321 + ret = self.GetInfoLabel("System.Time(%s)" % self._settings.getSysTimeFormat()).split(" ")[0] + return ret[-8:] + + def GetPlayerTime(self): + if self.PlayingLiveTV() or self.PlayingLiveRadio(): + return self.GetInfoLabel("PVR.EpgEventElapsedTime") + + return self.GetInfoLabel("Player.Time") + + def GetPlayerDuration(self): + if self.PlayingLiveTV() or self.PlayingLiveRadio(): + return self.GetInfoLabel("PVR.EpgEventDuration") + + return self.GetInfoLabel("Player.Duration") + + def IsPlayerPlaying(self): + return self.GetBool("Player.HasMedia") + + def IsPlayerPaused(self): + return self.GetBool("Player.Paused") + + def IsPlayerForwarding(self): + return self.GetBool("Player.Forwarding") + + def IsPlayerRewinding(self): + return self.GetBool("Player.Rewinding") + + def IsInternetStream(self): + return self.GetBool("Player.IsInternetStream") + + def IsPassthroughAudio(self): + return self.GetBool("Player.Passthrough") + + def IsPVRRecording(self): + return self.GetBool("PVR.IsRecording") + + def IsPlaylistRandom(self): + return self.GetBool("Playlist.IsRandom") + + def IsPlaylistRepeatAll(self): + return self.GetBool("Playlist.IsRepeat") + + def IsPlaylistRepeatOne(self): + return self.GetBool("Playlist.IsRepeatOne") + + def IsPlaylistRepeatAny(self): + return (self.IsPlaylistRepeatAll() | self.IsPlaylistRepeatOne()) + + def IsDiscInDrive(self): + return self.GetBool("System.HasMediaDVD") + + def IsScreenSaverActive(self): + return self.GetBool("System.ScreenSaverActive") + + def IsMuted(self): + return self.GetBool("Player.Muted") + + def GetVolumePercent(self): + volumedb = float(self.GetInfoLabel("Player.Volume").replace(",", ".").replace(" dB", "")) + return (100 * (60.0 + volumedb) / 60) + + def GetPlayerTimeSecs(self): + currentTimeAr = self.GetPlayerTime().split(":") + if currentTimeAr[0] == "": + return 0 + + return self.timeToSecs(currentTimeAr) + + def GetPlayerDurationSecs(self): + currentDurationAr = self.GetPlayerDuration().split(":") + if currentDurationAr[0] == "": + return 0 + + return self.timeToSecs(currentDurationAr) + + def GetProgressPercent(self): + tCurrent = self.GetPlayerTimeSecs() + tTotal = self.GetPlayerDurationSecs() + + if float(tTotal) == 0.0: + return 0 + + return float(tCurrent)/float(tTotal) + + def IsNavigationActive(self): + ret = False + + navtimeout = self._settings.getNavTimeout() + menu = self.GetInfoLabel("$INFO[System.CurrentWindow]") + subMenu = self.GetInfoLabel("$INFO[System.CurrentControl]") + + if menu != self._nav_oldmenu or subMenu != self._nav_oldsubmenu or (self._navtimer + navtimeout) > time.time(): + ret = True + if menu != self._nav_oldmenu or subMenu != self._nav_oldsubmenu: + self._navtimer = time.time() + self._nav_oldmenu = menu + self._nav_oldsubmenu = subMenu + + return ret + + def IsWindowIDPVR(self, iWindowID): + if iWindowID >= WINDOW_IDS.WINDOW_PVR and iWindowID <= WINDOW_IDS.WINDOW_PVR_MAX: + return True + + return False + + def IsWindowIDVideo(self, iWindowID): + if iWindowID in [WINDOW_IDS.WINDOW_VIDEO_NAV, WINDOW_IDS.WINDOW_VIDEO_PLAYLIST]: + return True + + return False + + def IsWindowIDMusic(self, iWindowID): + if iWindowID in [WINDOW_IDS.WINDOW_MUSIC_PLAYLIST, WINDOW_IDS.WINDOW_MUSIC_NAV, + WINDOW_IDS.WINDOW_MUSIC_PLAYLIST_EDITOR]: + return True + + return False + + def IsWindowIDPictures(self, iWindowID): + if iWindowID == WINDOW_IDS.WINDOW_PICTURES: + return True + + return False + + def IsWindowIDWeather(self, iWindowID): + if iWindowID == WINDOW_IDS.WINDOW_WEATHER: + return True + + return False diff --git a/resources/lib/lcdbase.py b/resources/lib/lcdbase.py new file mode 100644 index 00000000..9b615702 --- /dev/null +++ b/resources/lib/lcdbase.py @@ -0,0 +1,848 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# XBMC LCDproc addon +# Copyright (C) 2012-2024 Team Kodi +# Copyright (C) 2012-2024 Daniel 'herrnst' Scheller +# + +import os +import re +import shutil +import time + +from xml.etree import ElementTree as xmltree +from array import array + +import xbmcvfs +import xbmcgui + +from .common import * +from .settings import * +from .extraicons import * +from .infolabels import * +from .charset_hd44780 import * + +__lcdxml__ = xbmcvfs.translatePath(os.path.join("special://masterprofile", "LCD.xml")) +__lcddefaultxml__ = xbmcvfs.translatePath(os.path.join(KODI_ADDON_ROOTPATH, "resources", "LCD.xml.defaults")) + +class LCD_MODE: + LCD_MODE_GENERAL = 0 + LCD_MODE_MUSIC = 1 + LCD_MODE_VIDEO = 2 + LCD_MODE_TVSHOW = 3 + LCD_MODE_NAVIGATION = 4 + LCD_MODE_SCREENSAVER = 5 + LCD_MODE_XBE_LAUNCH = 6 + LCD_MODE_PVRTV = 7 + LCD_MODE_PVRRADIO = 8 + LCD_MODE_MAX = 9 + +class LCD_LINETYPE: + LCD_LINETYPE_TEXT = "text" + LCD_LINETYPE_PROGRESS = "progressbar" + LCD_LINETYPE_PROGRESSTIME = "progresstime" + LCD_LINETYPE_ICONTEXT = "icontext" + LCD_LINETYPE_BIGSCREEN = "bigscreen" + +class LCD_LINEALIGN: + LCD_LINEALIGN_LEFT = 0 + LCD_LINEALIGN_CENTER = 1 + LCD_LINEALIGN_RIGHT = 2 + +g_dictEmptyLineDescriptor = {} +g_dictEmptyLineDescriptor['type'] = LCD_LINETYPE.LCD_LINETYPE_TEXT +g_dictEmptyLineDescriptor['startx'] = int(0) +g_dictEmptyLineDescriptor['text'] = str("") +g_dictEmptyLineDescriptor['endx'] = int(0) +g_dictEmptyLineDescriptor['align'] = LCD_LINEALIGN.LCD_LINEALIGN_LEFT + +class LcdBase(): + def __init__(self, settings): + # configuration vars (from LCD.xml) + self.m_lcdMode = [None] * LCD_MODE.LCD_MODE_MAX + self.m_extraBars = [None] * (LCD_EXTRABARS_MAX + 1) + self.m_bAllowEmptyLines = False + self.m_bCenterBigDigits = False + self.m_bDisablePlayIndicatorOnPause = False + self.m_bProgressbarSurroundings = False + self.m_iDimOnPlayDelay = 0 + self.m_iIconTextOffset = 2 + self.m_strLCDEncoding = "iso-8859-1" # LCDproc default is iso-8859-1! + self.m_strScrollSeparator = " " + + # runtime vars/state tracking + self.m_timeDisableOnPlayTimer = time.time() + self.m_bCurrentlyDimmed = False + self.m_bHaveHD44780Charmap = False + self.m_bVolumeChangeActive = False + self.m_bWasStopped = True + self.m_bXMLWarningDisplayed = False + self.m_iOldAudioChannelsVar = 0 + self.m_strOldAudioCodec = "" + self.m_strOldVideoCodec = "" + + # regex compile cache + self.m_reBBCode = None + + # class instances + self.m_Settings = settings + + # initialize InfoLabels + self.m_InfoLabels = InfoLabels(self.m_Settings) + +# @abstractmethod + def _concrete_method(self): + pass + +# @abstractmethod + def IsConnected(self): + pass + +# @abstractmethod + def Stop(self): + pass + +# @abstractmethod + def Suspend(self): + pass + +# @abstractmethod + def Resume(self): + pass + +# @abstractmethod + def SetBackLight(self, iLight): + pass + +# @abstractmethod + def SetContrast(self, iContrast): + pass + +# @abstractmethod + def SetBigDigits(self, strTimeString, bForceUpdate): + pass + +# @abstractmethod + def ClearLine(self, iLine): + pass + +# @abstractmethod + def SetLine(self, mode, iLine, strLine, dictDescriptor, bForce): + pass + +# @abstractmethod + def ClearDisplay(self): + pass + +# @abstractmethod + def FlushLines(self): + pass + +# @abstractmethod + def GetColumns(self): + pass + +# @abstractmethod + def GetRows(self): + pass + +# @abstractmethod + def SetPlayingStateIcon(self): + pass + +# @abstractmethod + def SetProgressBar(self, percent, lineIdx): + pass + + def ManageLCDXML(self): + ret = False + + if not os.path.isfile(__lcdxml__): + if not os.path.isfile(__lcddefaultxml__): + log(LOGERROR, "No LCD.xml found and LCD.xml.defaults missing, expect problems!") + else: + try: + shutil.copy2(__lcddefaultxml__, __lcdxml__) + log(LOGINFO, "Initialised LCD.xml from defaults") + ret = True + except: + log(LOGERROR, "Failed to copy LCD defaults!") + else: + ret = True + + return ret + + def Initialize(self): + bGotDefaultSkin = False + bSkinHandled = False + + try: + if not self.m_bHaveHD44780Charmap: + log(LOGDEBUG, "Registering HD44780-ROM pseudocodepages") + codecs.register(charset_hd44780) + self.m_bHaveHD44780Charmap = True + except: + log(LOGERROR, "Failed to register custom HD44780-ROM pseudocodepage, expect problems with alternative charsets!") + + # make sure we got reasonable defaults for users who didn't adapt to newest additions + bGotDefaultSkin = self.LoadSkin(__lcddefaultxml__, True) + + # check for user-LCD.xml, optionally create it + bSkinHandled = self.ManageLCDXML() + + # try to load user setup + if not self.LoadSkin(__lcdxml__, False) and not bGotDefaultSkin: + log(LOGERROR, "No usable mode configuration/skin could be loaded, check your addon installation!") + return False + + # force-update GUI settings + self.UpdateGUISettings() + + self.m_bCurrentlyDimmed = False + return True + + def UpdateGUISettings(self): + str_charset = self.m_Settings.getCharset() + if str_charset != self.m_strLCDEncoding: + if (str_charset == "hd44780_a00" or str_charset == "hd44780_a02") and not self.m_bHaveHD44780Charmap: + str_charset = "iso8859-1" + + self.m_strLCDEncoding = str_charset + log(LOGDEBUG, "Setting character encoding to %s" % (self.m_strLCDEncoding)) + + self.m_iDimOnPlayDelay = self.m_Settings.getDimDelay() + + def LoadSkin(self, xmlFile, doReset): + if doReset == True: + self.Reset() + + bHaveSkin = False + + log(LOGINFO, "Loading settings from %s" % (xmlFile)) + + try: + doc = xmltree.parse(xmlFile) + except: + if not self.m_bXMLWarningDisplayed: + self.m_bXMLWarningDisplayed = True + text = KODI_ADDON_SETTINGS.getLocalizedString(32502) + xbmcgui.Dialog().notification(KODI_ADDON_NAME, text, KODI_ADDON_ICON) + + log(LOGERROR, "Parsing of %s failed" % (xmlFile)) + return False + + for element in doc.iter(): + #PARSE LCD infos + if element.tag == "lcd": + # load our settings + + # apply scrollseparator + scrollSeparator = element.find("scrollseparator") + if scrollSeparator != None: + + if str(scrollSeparator.text).strip() != "": + self.m_strScrollSeparator = " " + scrollSeparator.text + " " + + # check for progressbarsurroundings setting + self.m_bProgressbarSurroundings = False + + progressbarSurroundings = element.find("progressbarsurroundings") + if progressbarSurroundings != None: + if str(progressbarSurroundings.text).lower() in ["on", "true"]: + self.m_bProgressbarSurroundings = True + + # apply progressbarblank + self.m_bProgressbarBlank = " " + + progressbarBlank = element.find("progressbarblank") + if progressbarBlank != None: + self.m_bProgressbarBlank = str(progressbarBlank.text)[0] + + # icontext offset setting + self.m_iIconTextOffset = 2 + + icontextoffset = element.find("icontextoffset") + if icontextoffset != None and icontextoffset.text != None: + try: + intoffset = int(icontextoffset.text) + except ValueError as TypeError: + log(LOGERROR, "Value for icontextoffset must be integer (got: %s)" % (icontextoffset.text)) + else: + if intoffset <= 0 or intoffset >= self.GetColumns(): + log(LOGERROR, "Value %d for icontextoffset out of range, ignoring" % (intoffset)) + else: + if intoffset < 2: + log(LOGWARNING, "Value %d for icontextoffset smaller than LCDproc's icon width" % (intoffset)) + self.m_iIconTextOffset = intoffset + + # check for allowemptylines setting + self.m_bAllowEmptyLines = False + + allowemptylines = element.find("allowemptylines") + if allowemptylines != None: + if str(allowemptylines.text).lower() in ["on", "true"]: + self.m_bAllowEmptyLines = True + + # check for centerbigdigits setting + self.m_bCenterBigDigits = False + + centerbigdigits = element.find("centerbigdigits") + if centerbigdigits != None: + if str(centerbigdigits.text).lower() in ["on", "true"]: + self.m_bCenterBigDigits = True + + # check for disableplayindicatoronpause setting + self.m_bDisablePlayIndicatorOnPause = False + + disableplayindicatoronpause = element.find("disableplayindicatoronpause") + if disableplayindicatoronpause != None: + if str(disableplayindicatoronpause.text).lower() in ["on", "true"]: + self.m_bDisablePlayIndicatorOnPause = True + + # extra progress bars + for i in range(1, LCD_EXTRABARS_MAX + 1): + extrabar = None + extrabar = element.find("extrabar%i" % (i)) + if extrabar != None: + if str(extrabar.text).strip() in ["progress", "volume", "volumehidden", "menu", "alwayson"]: + self.m_extraBars[i] = str(extrabar.text).strip() + else: + self.m_extraBars[i] = "" + + #load modes + tmpMode = element.find("music") + self.LoadMode(tmpMode, LCD_MODE.LCD_MODE_MUSIC) + + tmpMode = element.find("video") + self.LoadMode(tmpMode, LCD_MODE.LCD_MODE_VIDEO) + + tmpMode = element.find("tvshow") + self.LoadMode(tmpMode, LCD_MODE.LCD_MODE_TVSHOW) + + tmpMode = element.find("general") + self.LoadMode(tmpMode, LCD_MODE.LCD_MODE_GENERAL) + + tmpMode = element.find("navigation") + self.LoadMode(tmpMode, LCD_MODE.LCD_MODE_NAVIGATION) + + tmpMode = element.find("screensaver") + self.LoadMode(tmpMode, LCD_MODE.LCD_MODE_SCREENSAVER) + + tmpMode = element.find("xbelaunch") + self.LoadMode(tmpMode, LCD_MODE.LCD_MODE_XBE_LAUNCH) + + tmpMode = element.find("pvrtv") + self.LoadMode(tmpMode, LCD_MODE.LCD_MODE_PVRTV) + + tmpMode = element.find("pvrradio") + self.LoadMode(tmpMode, LCD_MODE.LCD_MODE_PVRRADIO) + + bHaveSkin = True + + # LCD.xml parsed successfully, so reset warning flag + self.m_bXMLWarningDisplayed = False + + return bHaveSkin + + def LoadMode(self, node, mode): + # clear mode (probably overriding defaults), assume the user knows what he wants if an empty node is given + self.m_lcdMode[mode] = [] + + if node == None: + log(LOGWARNING, "Empty Mode %d, consider checking LCD.xml" % (mode)) + + # if mode is empty, initialise with blank line + if len(self.m_lcdMode[mode]) <= 0: + self.m_lcdMode[mode].append(g_dictEmptyLineDescriptor) + + return + + if len(node.findall("line")) <= 0: + log(LOGWARNING, "Mode %d defined without lines, consider checking LCD.xml" % (mode)) + + if len(self.m_lcdMode[mode]) <= 0: + self.m_lcdMode[mode].append(g_dictEmptyLineDescriptor) + + return + + # regex to determine any of $INFO[LCD.Time(Wide)21-44] + timeregex = r'' + re.escape('$INFO[LCD.') + r'Time((Wide)?\d?\d?)' + re.escape(']') + + for line in node.findall("line"): + # initialize line with empty descriptor + linedescriptor = g_dictEmptyLineDescriptor.copy() + + linedescriptor['startx'] = int(1) + linedescriptor['endx'] = int(self.GetColumns()) + + if line.text == None: + linetext = "" + else: + # prepare text line for XBMC's expected encoding + linetext = line.text.strip() + + # make sure linetext has something so re.match won't fail + if linetext != "": + timematch = re.match(timeregex, linetext, flags=re.IGNORECASE) + + # if line matches, throw away mode, add BigDigit descriptor and end processing for this mode + if timematch != None: + linedescriptor['type'] = LCD_LINETYPE.LCD_LINETYPE_BIGSCREEN + linedescriptor['text'] = "Time" + + self.m_lcdMode[mode] = [] + self.m_lcdMode[mode].append(linedescriptor) + return + + # progressbar line if InfoLabel exists + if linetext.lower().find("$info[lcd.progressbar]") >= 0: + linedescriptor['type'] = LCD_LINETYPE.LCD_LINETYPE_PROGRESS + linedescriptor['text'] = self.m_bProgressbarBlank * int(self.m_iColumns) + linedescriptor['endx'] = int(self.m_iCellWidth) * int(self.m_iColumns) + + if self.m_bProgressbarSurroundings == True: + linedescriptor['startx'] = int(2) + linedescriptor['text'] = "[" + self.m_bProgressbarBlank * (self.m_iColumns - 2) + "]" + linedescriptor['endx'] = int(self.m_iCellWidth) * (int(self.GetColumns()) - 2) + + # progresstime line if InfoLabel exists + elif linetext.lower().find("$info[lcd.progresstime]") >= 0: + linedescriptor['type'] = LCD_LINETYPE.LCD_LINETYPE_PROGRESSTIME + linedescriptor['endx'] = int(self.m_iCellWidth) * int(self.m_iColumns) + + # textline with icon in front + elif linetext.lower().find("$info[lcd.playicon]") >= 0: + linedescriptor['type'] = LCD_LINETYPE.LCD_LINETYPE_ICONTEXT + linedescriptor['startx'] = int(1 + self.m_iIconTextOffset) # icon widgets take 2 chars, so shift text offset (default: 2) + linedescriptor['text'] = re.sub(r'\s?' + re.escape("$INFO[LCD.PlayIcon]") + r'\s?', ' ', linetext, flags=re.IGNORECASE).strip() + + # standard (scrolling) text line + else: + linedescriptor['type'] = LCD_LINETYPE.LCD_LINETYPE_TEXT + linedescriptor['text'] = linetext + + # check for alignment pseudo-labels + if linetext.lower().find("$info[lcd.aligncenter]") >= 0: + linedescriptor['align'] = LCD_LINEALIGN.LCD_LINEALIGN_CENTER + if linetext.lower().find("$info[lcd.alignright]") >= 0: + linedescriptor['align'] = LCD_LINEALIGN.LCD_LINEALIGN_RIGHT + + linedescriptor['text'] = re.sub(r'\s?' + re.escape("$INFO[LCD.AlignCenter]") + r'\s?', ' ', linedescriptor['text'], flags=re.IGNORECASE).strip() + linedescriptor['text'] = re.sub(r'\s?' + re.escape("$INFO[LCD.AlignRight]") + r'\s?', ' ', linedescriptor['text'], flags=re.IGNORECASE).strip() + + self.m_lcdMode[mode].append(linedescriptor) + + def Reset(self): + for i in range(0,LCD_MODE.LCD_MODE_MAX): + self.m_lcdMode[i] = [] #clear list + + def Shutdown(self): + log(LOGINFO, "Shutting down") + + if self.m_Settings.getDimOnShutdown(): + self.SetBackLight(0) + + self.CloseSocket() + + # GetLCDMode(): + # returns mode identifier based on currently playing media/active navigation + def GetLCDMode(self): + ret = LCD_MODE.LCD_MODE_GENERAL + + navActive = self.m_InfoLabels.IsNavigationActive() + screenSaver = self.m_InfoLabels.IsScreenSaverActive() + playingVideo = self.m_InfoLabels.PlayingVideo() + playingTVShow = self.m_InfoLabels.PlayingTVShow() + playingMusic = self.m_InfoLabels.PlayingAudio() + playingPVRTV = self.m_InfoLabels.PlayingLiveTV() + playingPVRRadio = self.m_InfoLabels.PlayingLiveRadio() + + if navActive: + ret = LCD_MODE.LCD_MODE_NAVIGATION + elif screenSaver: + ret = LCD_MODE.LCD_MODE_SCREENSAVER + elif playingPVRTV: + ret = LCD_MODE.LCD_MODE_PVRTV + elif playingPVRRadio: + ret = LCD_MODE.LCD_MODE_PVRRADIO + elif playingTVShow: + ret = LCD_MODE.LCD_MODE_TVSHOW + elif playingVideo: + ret = LCD_MODE.LCD_MODE_VIDEO + elif playingMusic: + ret = LCD_MODE.LCD_MODE_MUSIC + + return ret + + def StripBBCode(self, strtext): + regexbbcode = r"\[(?P[0-9a-zA-Z_\-]+?)[0-9a-zA-Z_\- ]*?\](?P.*?)\[\/(?P=tagname)\]" + # precompile and remember regex to make sure re's caching won't cause accidential recompilation + if not self.m_reBBCode: + self.m_reBBCode = re.compile(regexbbcode) + # catch+report failure + if not self.m_reBBCode: + log(LOGWARNING, "Precompilation of BBCode strip regex failed") + self.m_reBBCode = regexbbcode + + # loop to catch nested tags + loopcount = 5 + + # start with passed string + mangledline = strtext + + # do regex multiple times to catch nested tags + while True: + loopcount = loopcount - 1 + try: + mangledline, replacements = re.subn(self.m_reBBCode, r"\g", mangledline) + except: + return mangledline + + # when the result didn't change, all tags should be gone (but also stop if maxnum iterations are reached) + if replacements == 0 or loopcount < 1: + break + + # return last replace mangling + return mangledline + + def Render(self, bForce): + outLine = 0 + inLine = 0 + mode = self.GetLCDMode() + + self.HandleBacklight(mode) + + while (outLine < int(self.GetRows()) and inLine < len(self.m_lcdMode[mode])): + #parse the progressbar infolabel by ourselfs! + if self.m_lcdMode[mode][inLine]['type'] == LCD_LINETYPE.LCD_LINETYPE_PROGRESS or self.m_lcdMode[mode][inLine]['type'] == LCD_LINETYPE.LCD_LINETYPE_PROGRESSTIME: + # get playtime and duration and convert into seconds + percent = self.m_InfoLabels.GetProgressPercent() + pixelsWidth = self.SetProgressBar(percent, self.m_lcdMode[mode][inLine]['endx']) + line = "p" + str(pixelsWidth) + else: + if self.m_lcdMode[mode][inLine]['type'] == LCD_LINETYPE.LCD_LINETYPE_ICONTEXT: + self.SetPlayingStateIcon() + + line = self.m_InfoLabels.GetInfoLabel(self.m_lcdMode[mode][inLine]['text']) + + if len(line) > 0: + line = self.StripBBCode(line) + + self.SetProgressBar(0, -1) + + if self.m_bAllowEmptyLines or len(line) > 0: + self.SetLine(mode, outLine, line, self.m_lcdMode[mode][inLine], bForce) + outLine += 1 + + inLine += 1 + + # fill remainder with empty space if not bigscreen + if self.m_lcdMode[mode][0]['type'] != LCD_LINETYPE.LCD_LINETYPE_BIGSCREEN: + while outLine < int(self.GetRows()): + self.SetLine(mode, outLine, "", g_dictEmptyLineDescriptor, bForce) + outLine += 1 + + if self.m_cExtraIcons is not None: + self.SetExtraInformation() + self.m_bstrSetLineCmds += self.m_cExtraIcons.GetOutputCommands() + + self.FlushLines() + + def DoDimOnMusic(self, mode): + return (mode == LCD_MODE.LCD_MODE_MUSIC or mode == LCD_MODE.LCD_MODE_PVRRADIO) and self.m_Settings.getDimOnMusicPlayback() + + def DoDimOnVideo(self, mode): + return (mode == LCD_MODE.LCD_MODE_VIDEO or mode == LCD_MODE.LCD_MODE_TVSHOW or mode == LCD_MODE.LCD_MODE_PVRTV) and self.m_Settings.getDimOnVideoPlayback() + + def DoDimOnScreensaver(self, mode): + return (mode == LCD_MODE.LCD_MODE_SCREENSAVER) and self.m_Settings.getDimOnScreensaver() + + def HandleBacklight(self, mode): + # dimming display in case screensaver is active or something is being played back (and not paused!) + doDim = False + + if self.DoDimOnScreensaver(mode): + doDim = True + elif not (self.m_InfoLabels.IsPlayerPlaying() and self.m_InfoLabels.IsPlayerPaused()) and (self.DoDimOnVideo(mode) or self.DoDimOnMusic(mode)): + doDim = True + + if doDim: + if not self.m_bCurrentlyDimmed: + if (self.m_timeDisableOnPlayTimer + self.m_iDimOnPlayDelay) < time.time(): + self.SetBackLight(0) + self.m_bCurrentlyDimmed = True + else: + self.m_timeDisableOnPlayTimer = time.time() + if self.m_bCurrentlyDimmed: + self.SetBackLight(1) + self.m_bCurrentlyDimmed = False + + def SetExtraInfoPlaying(self, isplaying, isvideo, isaudio): + # make sure output scaling indicators are off when not playing and/or not playing video + if not isplaying or not isvideo: + self.m_cExtraIcons.ClearIconStates(LCD_EXTRAICONCATEGORIES.LCD_ICONCAT_OUTSCALE) + + if isplaying: + if isvideo: + try: + iVideoRes = int(self.m_InfoLabels.GetInfoLabel("VideoPlayer.VideoResolution")) + except: + iVideoRes = int(0) + + try: + iScreenRes = int(self.m_InfoLabels.GetInfoLabel("System.ScreenHeight")) + except: + iScreenRes = int(0) + + if self.m_InfoLabels.PlayingLiveTV(): + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_TV, True) + elif self.m_InfoLabels.IsInternetStream(): + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_WEBCASTING, True) + else: + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_MOVIE, True) + + if iVideoRes < 720: + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_RESOLUTION_SD, True) + else: + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_RESOLUTION_HD, True) + + if iScreenRes <= (iVideoRes + (float(iVideoRes) * 0.1)) and iScreenRes >= (iVideoRes - (float(iVideoRes) * 0.1)): + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_OUTSOURCE, True) + else: + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_OUTFIT, True) + + elif isaudio: + if self.m_InfoLabels.IsInternetStream(): + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_WEBCASTING, True) + else: + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_MUSIC, True) + + else: # not playing + + # Set active mode indicator based on current active window + iWindowID = self.m_InfoLabels.GetActiveWindowID() + + if self.m_InfoLabels.IsWindowIDPVR(iWindowID): + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_TV, True) + elif self.m_InfoLabels.IsWindowIDVideo(iWindowID): + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_MOVIE, True) + elif self.m_InfoLabels.IsWindowIDMusic(iWindowID): + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_MUSIC, True) + elif self.m_InfoLabels.IsWindowIDPictures(iWindowID): + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_PHOTO, True) + elif self.m_InfoLabels.IsWindowIDWeather(iWindowID): + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_WEATHER, True) + else: + self.m_cExtraIcons.ClearIconStates(LCD_EXTRAICONCATEGORIES.LCD_ICONCAT_MODES) + + def SetExtraInfoCodecs(self, isplaying, isvideo, isaudio): + # initialise stuff to avoid uninitialised var stuff + strVideoCodec = "" + strAudioCodec = "" + iAudioChannels = 0 + + if isplaying: + if self.m_InfoLabels.IsPassthroughAudio(): + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_SPDIF, True) + else: + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_SPDIF, False) + + if isvideo: + strVideoCodec = str(self.m_InfoLabels.GetInfoLabel("VideoPlayer.VideoCodec")).lower() + strAudioCodec = str(self.m_InfoLabels.GetInfoLabel("VideoPlayer.AudioCodec")).lower() + iAudioChannels = self.m_InfoLabels.GetInfoLabel("VideoPlayer.AudioChannels") + elif isaudio: + strVideoCodec = "" + strAudioCodec = str(self.m_InfoLabels.GetInfoLabel("MusicPlayer.Codec")).lower() + iAudioChannels = self.m_InfoLabels.GetInfoLabel("MusicPlayer.Channels") + + if self.m_bWasStopped: + self.m_bWasStopped = False + self.m_strOldVideoCodec = "" + self.m_strOldAudioCodec = "" + self.m_iOldAudioChannelsVar = 0 + + # check video codec + if self.m_strOldVideoCodec != strVideoCodec: + # work only when video codec changed + self.m_strOldVideoCodec = strVideoCodec + + # any mpeg video + # FIXME: "hdmv" is returned as video codec for ANYTHING played directly + # from bluray media played via libbluray and friends, regardless of the + # real codec (mpeg2/h264/vc1). Ripping to e.g. MKV and playing that back + # returns the correct codec id. As the display is wrong for VC-1 only, + # accept that the codec icon is right only in maybe 70-80% of all playback + # cases. This needs fixing in XBMC! See http://trac.xbmc.org/ticket/13969 + if strVideoCodec in ["mpg", "mpeg", "mpeg2video", "h264", "x264", "mpeg4", "hdmv", "hevc"]: + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_VCODEC_MPEG, True) + + # any divx + elif strVideoCodec in ["divx", "dx50", "div3"]: + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_VCODEC_DIVX, True) + + # xvid + elif strVideoCodec == "xvid": + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_VCODEC_XVID, True) + + # wmv and vc-1 + elif strVideoCodec in ["wmv", "wvc1", "vc-1", "vc1"]: + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_VCODEC_WMV, True) + + # anything else + else: + self.m_cExtraIcons.ClearIconStates(LCD_EXTRAICONCATEGORIES.LCD_ICONCAT_VIDEOCODECS) + + # check audio codec + if self.m_strOldAudioCodec != strAudioCodec: + # work only when audio codec changed + self.m_strOldAudioCodec = strAudioCodec + + # any mpeg audio + if strAudioCodec in ["mpga", "mp2"]: + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_ACODEC_MPEG, True) + + # any ac3/dolby digital/dd+/truehd + elif strAudioCodec in ["ac3", "eac3", "truehd"]: + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_ACODEC_AC3, True) + + # any dts including hires variants + elif strAudioCodec in ["dts", "dca", "dtshd_hra", "dtshd_ma"]: + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_ACODEC_DTS, True) + + # mp3 + elif strAudioCodec in ["mp3", "mp3float"]: + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_ACODEC_MP3, True) + + # any ogg vorbis + elif strAudioCodec in ["ogg", "vorbis"]: + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_ACODEC_OGG, True) + + # any wma + elif strAudioCodec in ["wma", "wmav2"]: + if isvideo: + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_ACODEC_VWMA, True) + else: + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_ACODEC_AWMA, True) + + # any pcm, wav or flac + elif strAudioCodec in ["wav", "flac", "pcm", "pcm_bluray", "pcm_s24le"]: + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_ACODEC_WAV, True) + + # anything else + else: + self.m_cExtraIcons.ClearIconStates(LCD_EXTRAICONCATEGORIES.LCD_ICONCAT_AUDIOCODECS) + + # make sure iAudioChannels contains something useful + if iAudioChannels == "" and strAudioCodec != "": + iAudioChannels = 2 + elif iAudioChannels == "": + iAudioChannels = 0 + else: + iAudioChannels = int(iAudioChannels) + + # update audio channels indicator + if self.m_iOldAudioChannelsVar != iAudioChannels: + # work only when audio channels changed + self.m_iOldAudioChannelsVar = iAudioChannels + + # decide which icon (set) to activate + if iAudioChannels > 0 and iAudioChannels <= 3: + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_OUT_2_0, True) + elif iAudioChannels <= 6: + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_OUT_5_1, True) + elif iAudioChannels <= 8: + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_OUT_7_1, True) + else: + self.m_cExtraIcons.ClearIconStates(LCD_EXTRAICONCATEGORIES.LCD_ICONCAT_AUDIOCHANNELS) + + else: + self.m_cExtraIcons.ClearIconStates(LCD_EXTRAICONCATEGORIES.LCD_ICONCAT_CODECS) + self.m_bWasStopped = True + + def SetExtraInfoGeneric(self, ispaused): + if self.m_InfoLabels.IsMuted(): + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_MUTE, True) + else: + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_MUTE, False) + + if ispaused: + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_PAUSE, True) + else: + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_PAUSE, False) + + if self.m_InfoLabels.IsPVRRecording(): + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_RECORD, True) + else: + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_RECORD, False) + + if self.m_InfoLabels.IsPlaylistRandom(): + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_SHUFFLE, True) + else: + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_SHUFFLE, False) + + if self.m_InfoLabels.IsPlaylistRepeatAny(): + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_REPEAT, True) + else: + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_REPEAT, False) + + if self.m_InfoLabels.IsDiscInDrive(): + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_DISC_IN, True) + else: + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_DISC_IN, False) + + if self.m_InfoLabels.IsScreenSaverActive(): + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_TIME, True) + else: + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_TIME, False) + + if self.m_InfoLabels.WindowIsActive(WINDOW_IDS.WINDOW_DIALOG_VOLUME_BAR): + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_VOLUME, True) + self.m_bVolumeChangeActive = True + else: + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_VOLUME, False) + self.m_bVolumeChangeActive = False + + if self.m_InfoLabels.WindowIsActive(WINDOW_IDS.WINDOW_DIALOG_KAI_TOAST): + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_ALARM, True) + else: + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_ALARM, False) + + def SetExtraInfoBars(self, isplaying): + for i in range(1, LCD_EXTRABARS_MAX + 1): + if self.m_extraBars[i] == "progress": + if isplaying: + self.m_cExtraIcons.SetBar(i, (self.m_InfoLabels.GetProgressPercent() * 100)) + else: + self.m_cExtraIcons.SetBar(i, 0) + elif self.m_extraBars[i] == "volume": + self.m_cExtraIcons.SetBar(i, self.m_InfoLabels.GetVolumePercent()) + elif self.m_extraBars[i] == "volumehidden": + if self.m_bVolumeChangeActive: + self.m_cExtraIcons.SetBar(i, self.m_InfoLabels.GetVolumePercent()) + else: + self.m_cExtraIcons.SetBar(i, 0) + elif self.m_extraBars[i] == "menu": + if isplaying: + self.m_cExtraIcons.SetBar(i, 0) + else: + self.m_cExtraIcons.SetBar(i, 100) + elif self.m_extraBars[i] == "alwayson": + self.m_cExtraIcons.SetBar(i, 100) + else: + self.m_cExtraIcons.SetBar(i, 0) + + def SetExtraInformation(self): + bPaused = self.m_InfoLabels.IsPlayerPaused() + bPlaying = self.m_InfoLabels.IsPlayerPlaying() + + bIsVideo = self.m_InfoLabels.PlayingVideo() + bIsAudio = self.m_InfoLabels.PlayingAudio() + + self.m_cExtraIcons.SetIconState(LCD_EXTRAICONS.LCD_EXTRAICON_PLAYING, + bPlaying and not (bPaused and self.m_bDisablePlayIndicatorOnPause)) + + self.SetExtraInfoPlaying(bPlaying, bIsVideo, bIsAudio) + self.SetExtraInfoCodecs(bPlaying, bIsVideo, bIsAudio) + self.SetExtraInfoGeneric(bPaused) + self.SetExtraInfoBars(bPlaying) diff --git a/resources/lib/lcdproc.py b/resources/lib/lcdproc.py new file mode 100644 index 00000000..ca65f721 --- /dev/null +++ b/resources/lib/lcdproc.py @@ -0,0 +1,642 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# XBMC LCDproc addon +# Copyright (C) 2012-2024 Team Kodi +# Copyright (C) 2012-2024 Daniel 'herrnst' Scheller +# + +import re +import time + +import xbmc + +from socket import * + +from .settings import * +from .lcdbase import * + +from .lcdproc_extra_imon import * +from .lcdproc_extra_mdm166a import * + +from .infolabels import * + +MAX_ROWS = 20 +MAX_BIGDIGITS = 20 +INIT_RETRY_INTERVAL = 2 +INIT_RETRY_INTERVAL_MAX = 60 + +class LCDProc(LcdBase): + def __init__(self, settings): + self.m_bStop = True + self.m_lastInitAttempt = 0 + self.m_initRetryInterval = INIT_RETRY_INTERVAL + self.m_used = True + self.m_socket = None + self.m_sockreadbuf = b'' + self.m_timeLastSockAction = time.time() + self.m_timeSocketIdleTimeout = 2 + self.m_strLineText = [None]*MAX_ROWS + self.m_strLineType = [None]*MAX_ROWS + self.m_bstrLineIcon = [None]*MAX_ROWS + self.m_strDigits = [None]*MAX_BIGDIGITS + self.m_iProgressBarWidth = 0 + self.m_iProgressBarLine = -1 + self.m_bstrIconName = b"BLOCK_FILLED" + self.m_iBigDigits = int(8) # 12:45:78 / colons count as digit + self.m_iOffset = 1 + self.m_bstrSetLineCmds = b"" + self.m_cExtraIcons = None + + LcdBase.__init__(self, settings) + + def ReadUntil(self, separator): + if not self.m_socket: + return b"" + + while separator not in self.m_sockreadbuf: + data = self.m_socket.recv(1024) + if not data: + raise EOFError + self.m_sockreadbuf += data + + line, tmp, self.m_sockreadbuf = self.m_sockreadbuf.partition(separator) + + return line + + def SendCommand(self, strCmd, bCheckRet): + countcmds = strCmd.count(b'\n') + sendcmd = strCmd + ret = True + + # Single command without lf + if countcmds < 1: + countcmds = 1 + sendcmd += b"\n" + + try: + # Send commands to LCDproc server + self.m_socket.sendall(sendcmd) + except Exception as ex: + # Something bad happened, abort + log(LOGERROR, "SendCommand(): Caught %s on m_socket.sendall()" % type(ex)) + return False + + # Update last socketaction timestamp + self.m_timeLastSockAction = time.time() + + # Repeat for number of found commands + for i in range(1, (countcmds + 1)): + # Read in (multiple) responses + while True: + try: + # Read server reply + reply = self.ReadUntil(b"\n") + except Exception as ex: + # (Re)read failed, abort + log(LOGERROR, "SendCommand(): Caught %s when reading back response(s)" % type(ex)) + return False + + # Skip these messages + if reply[:6] == b'listen': + continue + elif reply[:6] == b'ignore': + continue + elif reply[:3] == b'key': + continue + elif reply[:9] == b'menuevent': + continue + + # Response seems interesting, so stop here + break + + if not bCheckRet: + continue # no return checking desired, so be fine + + if strCmd == b'noop' and reply == b'noop complete': + continue # noop has special reply + + if reply == b'success': + continue + + ret = False + + # Leave information something undesired happened + if ret is False: + log(LOGWARNING, "Reply to '%s' was '%s'" % (strCmd.decode(self.m_strLCDEncoding), reply.decode(self.m_strLCDEncoding))) + + return ret + + def SetupScreen(self): + # Add screen first + if not self.SendCommand(b"screen_add xbmc", True): + return False + + # Set screen priority + if not self.SendCommand(b"screen_set xbmc -priority info", True): + return False + + # Turn off heartbeat if desired + if not self.m_Settings.getHeartBeat(): + if not self.SendCommand(b"screen_set xbmc -heartbeat off", True): + return False + + # Initialize command list var + strInitCommandList = b"" + + # Setup widgets (scrollers and hbars first) + for i in range(1,int(self.m_iRows)+1): + # Text widgets + strInitCommandList += b"widget_add xbmc lineScroller%i scroller\n" % (i) + + # Progress bars + strInitCommandList += b"widget_add xbmc lineProgress%i hbar\n" % (i) + + # Reset bars to zero + strInitCommandList += b"widget_set xbmc lineProgress%i 0 0 0\n" % (i) + + self.m_strLineText[i-1] = "" + self.m_strLineType[i-1] = "" + + # Setup icons last + for i in range(1,int(self.m_iRows)+1): + # Icons + strInitCommandList += b"widget_add xbmc lineIcon%i icon\n" % (i) + + # Default icon + strInitCommandList += b"widget_set xbmc lineIcon%i 0 0 BLOCK_FILLED\n" % (i) + + self.m_bstrLineIcon[i-1] = b"" + + for i in range(1,int(self.m_iBigDigits + 1)): + # Big Digit + strInitCommandList += b"widget_add xbmc lineBigDigit%i num\n" % (i) + + # Set Digit + strInitCommandList += b"widget_set xbmc lineBigDigit%i 0 0\n" % (i) + + self.m_strDigits[i] = b"" + + if not self.SendCommand(strInitCommandList, True): + return False + + return True + + def Initialize(self): + connected = False + if not self.m_used: + return False#nothing to do + + #don't try to initialize too often + now = time.time() + if (now - self.m_lastInitAttempt) < self.m_initRetryInterval: + return False + self.m_lastInitAttempt = now + + if self.Connect(): + if LcdBase.Initialize(self): + # reset the retry interval after a successful connect + self.m_initRetryInterval = INIT_RETRY_INTERVAL + self.m_bStop = False + connected = True + + else: + log(LOGERROR, "Connection successful but LCD.xml has errors, aborting connect") + + if not connected: + # preventively close socket + self.CloseSocket() + + # give up after INIT_RETRY_INTERVAL_MAX (60) seconds + if self.m_initRetryInterval > INIT_RETRY_INTERVAL_MAX: + self.m_used = False + log(LOGERROR,"Connect failed. Giving up. Please fix any connection problems and restart the addon.") + else: + self.m_initRetryInterval = self.m_initRetryInterval * 2 + log(LOGERROR,"Connect failed. Retry in %d seconds." % self.m_initRetryInterval) + + return connected + + def DetermineExtraSupport(self): + rematch_imon = "SoundGraph iMON(.*)LCD" + rematch_mdm166a = "Targa(.*)mdm166a" + rematch_imonvfd = "Soundgraph(.*)VFD" + + bUseExtraIcons = self.m_Settings.getUseExtraElements() + + # Never cause script failure/interruption by this! This is totally optional! + try: + # Retrieve driver name for additional functionality + self.m_socket.send(b"info\n") + reply = self.ReadUntil(b"\n").strip().decode("ascii") + + # When the LCDd driver doesn't supply a valid string, inform and return + if reply == "": + log(LOGINFO, "Empty driver information reply") + return + + log(LOGINFO, "Driver information reply: " + reply) + + if re.match(rematch_imon, reply): + log(LOGINFO, "SoundGraph iMON LCD detected") + if bUseExtraIcons: + self.m_cExtraIcons = LCDproc_extra_imon() + + # override bigdigits counter, the imonlcd driver handles bigdigits + # different: digits count for two columns instead of three + self.m_iBigDigits = 7 + + elif re.match(rematch_mdm166a, reply): + log(LOGINFO, "Futaba/Targa USB mdm166a VFD detected") + if bUseExtraIcons: + self.m_cExtraIcons = LCDproc_extra_mdm166a() + + elif re.match(rematch_imonvfd, reply): + log(LOGINFO, "SoundGraph iMON IR/VFD detected") + + if self.m_cExtraIcons is not None: + self.m_cExtraIcons.Initialize() + + except: + pass + + def Connect(self): + self.CloseSocket() + + try: + ip = self.m_Settings.getHostIp() + port = self.m_Settings.getHostPort() + log(LOGDEBUG,"Open " + str(ip) + ":" + str(port)) + + self.m_socket = socket(AF_INET, SOCK_STREAM) + self.m_socket.settimeout(15) + self.m_socket.connect((ip, port)) + self.m_socket.settimeout(3) + + except Exception as ex: + log(LOGERROR, "Connect(): Caught %s on initial connect, aborting" % type(ex)) + return False + + try: + # Start a new session + self.m_socket.send(b"hello\n") + + # Receive LCDproc data to determine row and column information + reply = self.ReadUntil(b"\n").decode("ascii") + log(LOGDEBUG,"Reply: " + reply) + + # parse reply by regex + lcdinfo = re.match(r"^connect .+ protocol ([0-9\.]+) lcd wid (\d+) hgt (\d+) cellwid (\d+) cellhgt (\d+)$", reply) + + # if regex didn't match, LCDproc is incompatible or something's odd + if lcdinfo is None: + return False + + # protocol version must currently either be 0.3 or 0.4 + if float(lcdinfo.group(1)) not in [0.3, 0.4]: + log(LOGERROR, "Only LCDproc protocols 0.3 and 0.4 supported (got " + lcdinfo.group(1) +")") + return False + + # set up class vars + self.m_iColumns = int(lcdinfo.group(2)) + self.m_iRows = int(lcdinfo.group(3)) + self.m_iCellWidth = int(lcdinfo.group(4)) + self.m_iCellHeight = int(lcdinfo.group(5)) + + # tell users what's going on + log(LOGINFO, "Connected to LCDd at %s:%s, Protocol version %s - Geometry %sx%s characters (%sx%s pixels, %sx%s pixels per character)" % (str(ip), str(port), float(lcdinfo.group(1)), str(self.m_iColumns), str(self.m_iRows), str(self.m_iColumns * self.m_iCellWidth), str(self.m_iRows * self.m_iCellHeight), str(self.m_iCellWidth), str(self.m_iCellHeight))) + + # Set up BigNum values based on display geometry + if self.m_iColumns < 13: + self.m_iBigDigits = 0 # No clock + elif self.m_iColumns < 17: + self.m_iBigDigits = 5 # HH:MM + elif self.m_iColumns < 20: + self.m_iBigDigits = 7 # H:MM:SS on play, HH:MM on clock + else: + self.m_iBigDigits = 8 # HH:MM:SS + + # Check LCDproc if we can enable any extras or override values + # (might override e.g. m_iBigDigits!) + self.DetermineExtraSupport() + + except Exception as ex: + log(LOGERROR,"Connect(): Caught %s during hello/info phase, aborting." % type(ex)) + return False + + if not self.SetupScreen(): + log(LOGERROR, "Screen setup failed!") + return False + + return True + + def CloseSocket(self): + if self.m_socket: + # no pyexceptions, please, we're disconnecting anyway + try: + # if we served extra elements, (try to) reset them + if self.m_cExtraIcons is not None: + if not self.SendCommand(self.m_cExtraIcons.GetClearAllCmd(), True): + log(LOGERROR, "CloseSocket(): Cannot clear extra icons") + + # do gracefully disconnect (send directly as we won't get any response on this) + self.m_socket.send(b"bye\n") + # and close socket afterwards + self.m_socket.close() + except: + # exception caught on this, so what? :) + pass + + # delete/cleanup extra support instance + del self.m_cExtraIcons + self.m_cExtraIcons = None + + self.m_sockreadbuf = b'' + self.m_socket = None + + def IsConnected(self): + if not self.m_socket: + return False + + # Ping only every SocketIdleTimeout seconds + if (self.m_timeLastSockAction + self.m_timeSocketIdleTimeout) > time.time(): + return True + + if not self.SendCommand(b"noop", True): + log(LOGERROR, "noop failed in IsConnected(), aborting!") + return False + + return True + + def SetBackLight(self, iLight): + if not self.m_socket: + return + log(LOGDEBUG, "Switch Backlight to: " + str(iLight)) + + # Build command + if iLight == 0: + cmd = b"screen_set xbmc -backlight off\n" + elif iLight > 0: + cmd = b"screen_set xbmc -backlight on\n" + + # Send to server + if not self.SendCommand(cmd, True): + log(LOGERROR, "SetBackLight(): Cannot change backlight state") + self.CloseSocket() + + def SetContrast(self, iContrast): + #TODO: Not sure if you can control contrast from client + return + + def Stop(self): + self.CloseSocket() + self.m_bStop = True + + def Suspend(self): + if self.m_bStop or not self.m_socket: + return + + # Build command to suspend screen + cmd = b"screen_set xbmc -priority hidden\n" + + # Send to server + if not self.SendCommand(cmd, True): + log(LOGERROR, "Suspend(): Cannot suspend") + self.CloseSocket() + + def Resume(self): + if self.m_bStop or not self.m_socket: + return + + # Build command to resume screen + cmd = b"screen_set xbmc -priority info\n" + + # Send to server + if not self.SendCommand(cmd, True): + log(LOGERROR, "Resume(): Cannot resume") + self.CloseSocket() + + def GetColumns(self): + return int(self.m_iColumns) + + def GetBigDigitTime(self, mode): + ret = "" + + if self.m_InfoLabels.IsPlayerPlaying(): + if not (mode == LCD_MODE.LCD_MODE_SCREENSAVER and self.m_InfoLabels.IsPlayerPaused()): + ret = self.m_InfoLabels.GetPlayerTime()[-self.m_iBigDigits:] + + if ret == "": # no usable timestring, e.g. not playing anything + strSysTime = self.m_InfoLabels.GetSystemTime() + + if self.m_iBigDigits >= 8: # return h:m:s + ret = strSysTime + elif self.m_iBigDigits >= 5: # return h:m when display too small + ret = strSysTime[:5] + + return ret + + def SetBigDigits(self, strTimeString, bForceUpdate): + iOffset = 1 + iDigitCount = 1 + iStringOffset = 0 + strRealTimeString = "" + + if strTimeString == "" or strTimeString == None: + return + + iStringLength = int(len(strTimeString)) + + if self.m_bCenterBigDigits: + iColons = strTimeString.count(":") + iWidth = 3 * (iStringLength - iColons) + iColons + iOffset = 1 + max(self.m_iColumns - iWidth, 0) / 2 + + if iStringLength > self.m_iBigDigits: + iStringOffset = len(strTimeString) - self.m_iBigDigits + iOffset = 1; + + if self.m_iOffset != iOffset: + # on offset change force redraw + bForceUpdate = True + self.m_iOffset = iOffset + + for i in range(int(iStringOffset), int(iStringLength)): + if self.m_strDigits[iDigitCount] != strTimeString[i] or bForceUpdate: + self.m_strDigits[iDigitCount] = strTimeString[i] + + if strTimeString[i] == ":": + self.m_bstrSetLineCmds += b"widget_set xbmc lineBigDigit%i %i 10\n" % (iDigitCount, iOffset) + elif strTimeString[i].isdigit(): + self.m_bstrSetLineCmds += b"widget_set xbmc lineBigDigit%i %i %s\n" % (iDigitCount, iOffset, strTimeString[i].encode(self.m_strLCDEncoding)) + else: + self.m_bstrSetLineCmds += b"widget_set xbmc lineBigDigit%i 0 0\n" % (iDigitCount) + + if strTimeString[i] == ":": + iOffset += 1 + else: + iOffset += 3 + + iDigitCount += 1 + + while iDigitCount <= self.m_iBigDigits: + if self.m_strDigits[iDigitCount] != "" or bForceUpdate: + self.m_strDigits[iDigitCount] = "" + self.m_bstrSetLineCmds += b"widget_set xbmc lineBigDigit%i 0 0\n" % (iDigitCount) + + iDigitCount += 1 + + def SetProgressBar(self, percent, pxWidth): + self.m_iProgressBarWidth = int(float(percent) * pxWidth) + return self.m_iProgressBarWidth + + def SetPlayingStateIcon(self): + bPlaying = self.m_InfoLabels.IsPlayerPlaying() + bPaused = self.m_InfoLabels.IsPlayerPaused() + bForwarding = self.m_InfoLabels.IsPlayerForwarding() + bRewinding = self.m_InfoLabels.IsPlayerRewinding() + + self.m_bstrIconName = b"STOP" + + if bForwarding: + self.m_bstrIconName = b"FF" + elif bRewinding: + self.m_bstrIconName = b"FR" + elif bPaused: + self.m_bstrIconName = b"PAUSE" + elif bPlaying: + self.m_bstrIconName = b"PLAY" + + def GetRows(self): + return int(self.m_iRows) + + def ClearBigDigits(self, fullredraw = True): + for i in range(1,int(self.m_iBigDigits + 1)): + # Clear Digit + if fullredraw: + self.m_bstrSetLineCmds += b"widget_set xbmc lineBigDigit%i 0 0\n" % (i) + self.m_strDigits[i] = "" + + # on full redraw, make sure all widget get redrawn by resetting their type + if fullredraw: + for i in range(0, int(self.GetRows())): + self.m_strLineType[i] = "" + self.m_strLineText[i] = "" + self.m_bstrLineIcon[i] = b"" + + def ClearLine(self, iLine): + self.m_bstrSetLineCmds += b"widget_set xbmc lineIcon%i 0 0 BLOCK_FILLED\n" % (iLine) + self.m_bstrSetLineCmds += b"widget_set xbmc lineProgress%i 0 0 0\n" % (iLine) + self.m_bstrSetLineCmds += b"widget_set xbmc lineScroller%i 1 %i %i %i m 1 \"\"\n" % (iLine, iLine, self.m_iColumns, iLine) + + def SetLine(self, mode, iLine, strLine, dictDescriptor, bForce): + if self.m_bStop or not self.m_socket: + return + + if iLine < 0 or iLine >= int(self.m_iRows): + return + + plTime = self.m_InfoLabels.GetPlayerTime() + plDuration = self.m_InfoLabels.GetPlayerDuration() + ln = iLine + 1 + bExtraForce = False + drawLineText = False + + if self.m_strLineType[iLine] != dictDescriptor['type']: + if dictDescriptor['type'] == LCD_LINETYPE.LCD_LINETYPE_BIGSCREEN: + self.ClearDisplay() + else: + if self.m_strLineType[iLine] == LCD_LINETYPE.LCD_LINETYPE_BIGSCREEN: + self.ClearBigDigits() + else: + self.ClearLine(int(iLine + 1)) + + self.m_strLineType[iLine] = dictDescriptor['type'] + bExtraForce = True + + if dictDescriptor['type'] == LCD_LINETYPE.LCD_LINETYPE_PROGRESS and dictDescriptor['text'] != "": + self.m_bstrSetLineCmds += b"widget_set xbmc lineScroller%i 1 %i %i %i m 1 \"%s\"\n" % (ln, ln, self.m_iColumns, ln, dictDescriptor['text'].encode(self.m_strLCDEncoding)) + + if dictDescriptor['type'] == LCD_LINETYPE.LCD_LINETYPE_PROGRESSTIME and dictDescriptor['text'] != "": + self.m_bstrSetLineCmds += b"widget_set xbmc lineScroller%i 1 %i %i %i m 1 \"%s\"\n" % (ln, ln, self.m_iColumns, ln, dictDescriptor['text'].encode(self.m_strLCDEncoding)) + + if dictDescriptor['type'] == LCD_LINETYPE.LCD_LINETYPE_BIGSCREEN: + strLineLong = self.GetBigDigitTime(mode) + elif dictDescriptor['type'] == LCD_LINETYPE.LCD_LINETYPE_PROGRESSTIME: + strLineLong = plTime + self.m_bProgressbarBlank * (self.m_iColumns - len(plTime) - len(plDuration)) + plDuration + else: + strLineLong = strLine + + strLineLong.strip() + + iMaxLineLen = dictDescriptor['endx'] - (int(dictDescriptor['startx']) - 1) + iScrollSpeed = self.m_Settings.getScrollDelay() + bstrScrollMode = self.m_Settings.getLCDprocScrollMode().encode(self.m_strLCDEncoding) + + if len(strLineLong) > iMaxLineLen: # if the string doesn't fit the display... + if iScrollSpeed != 0: # add separator when scrolling enabled + if bstrScrollMode == b"m": # and scrollmode is marquee + strLineLong += self.m_strScrollSeparator + else: # or cut off + strLineLong = strLineLong[:iMaxLineLen] + iScrollSpeed = 1 + + iStartX = dictDescriptor['startx'] + + # check if update is required + if strLineLong != self.m_strLineText[iLine] or bForce: + # bigscreen + if dictDescriptor['type'] == LCD_LINETYPE.LCD_LINETYPE_BIGSCREEN: + self.SetBigDigits(strLineLong, bExtraForce) + # progressbar line + elif dictDescriptor['type'] == LCD_LINETYPE.LCD_LINETYPE_PROGRESS: + self.m_bstrSetLineCmds += b"widget_set xbmc lineProgress%i %i %i %i\n" % (ln, iStartX, ln, self.m_iProgressBarWidth) + # progressbar line with time + elif dictDescriptor['type'] == LCD_LINETYPE.LCD_LINETYPE_PROGRESSTIME: + drawLineText = True + pLenFract = float(self.m_iColumns - int(len(plDuration) + len(plTime))) / self.m_iColumns + pTimeLen = int(self.m_iProgressBarWidth * pLenFract) + self.m_bstrSetLineCmds += b"widget_set xbmc lineProgress%i %i %i %i\n" % (ln, iStartX + len(plTime), ln, pTimeLen) + # everything else (text, icontext) + else: + drawLineText = True + if len(strLineLong) < iMaxLineLen and dictDescriptor['align'] != LCD_LINEALIGN.LCD_LINEALIGN_LEFT: + iSpaces = iMaxLineLen - len(strLineLong) + if dictDescriptor['align'] == LCD_LINEALIGN.LCD_LINEALIGN_RIGHT: + iStartX += iSpaces + elif dictDescriptor['align'] == LCD_LINEALIGN.LCD_LINEALIGN_CENTER: + iStartX += int(iSpaces / 2) + + if drawLineText: + self.m_bstrSetLineCmds += b"widget_set xbmc lineScroller%i %i %i %i %i %s %i \"%s\"\n" % (ln, iStartX, ln, self.m_iColumns, ln, bstrScrollMode, iScrollSpeed, re.escape(strLineLong.encode(self.m_strLCDEncoding, errors="replace"))) + + # cache contents + self.m_strLineText[iLine] = strLineLong + + if dictDescriptor['type'] == LCD_LINETYPE.LCD_LINETYPE_ICONTEXT: + if self.m_bstrLineIcon[iLine] != self.m_bstrIconName or bExtraForce: + self.m_bstrLineIcon[iLine] = self.m_bstrIconName + + self.m_bstrSetLineCmds += b"widget_set xbmc lineIcon%i 1 %i %s\n" % (ln, ln, self.m_bstrIconName) + + def ClearDisplay(self): + log(LOGDEBUG, "Clearing display contents") + + # clear line buffer first + self.FlushLines() + + # set all widgets to empty stuff and/or offscreen + for i in range(1,int(self.m_iRows)+1): + self.ClearLine(i) + + # add commands to clear big digits + self.ClearBigDigits() + + # send to display + self.FlushLines() + + def FlushLines(self): + if len(self.m_bstrSetLineCmds) > 0: + # Send complete command package + self.SendCommand(self.m_bstrSetLineCmds, False) + + self.m_bstrSetLineCmds = b"" diff --git a/resources/lib/lcdproc_extra_base.py b/resources/lib/lcdproc_extra_base.py new file mode 100644 index 00000000..8a834037 --- /dev/null +++ b/resources/lib/lcdproc_extra_base.py @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# XBMC LCDproc addon +# Copyright (C) 2012-2024 Team Kodi +# Copyright (C) 2012-2024 Daniel 'herrnst' Scheller +# +# Stub class for extra symbol support e.g. on SoundGraph iMON or mdm166a LCDs/VFDs +# + +class LCDproc_extra_base(): + def __init__(self): + pass + +# @abstractmethod + def Initialize(self): + pass + +# @abstractmethod + def SetOutputIcons(self): + pass + +# @abstractmethod + def SetOutputBars(self): + pass + +# @abstractmethod + def GetOutputCommands(self): + pass + +# @abstractmethod + def SetBar(self, barnum, percent): + pass + +# @abstractmethod + def SetIconState(self, icon, state): + pass + +# @abstractmethod + def ClearIconStates(self, category): + pass + +# @abstractmethod + def GetClearAllCmd(self): + pass diff --git a/resources/lib/lcdproc_extra_imon.py b/resources/lib/lcdproc_extra_imon.py new file mode 100644 index 00000000..4e7e648c --- /dev/null +++ b/resources/lib/lcdproc_extra_imon.py @@ -0,0 +1,334 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# XBMC LCDproc addon +# Copyright (C) 2012-2024 Team Kodi +# Copyright (C) 2012-2024 Daniel 'herrnst' Scheller +# +# Support for extra symbols on SoundGraph iMON LCD displays +# Original C implementation (C) 2010 Christian Leuschen +# + +import time + +from .extraicons import * +from .lcdproc_extra_base import * + +IMON_OUTPUT_INTERVAL = 0.2 # seconds + +# extra icon bitmasks +class IMON_ICONS: + ICON_SPINDISC = 0x01 << 0 + ICON_TOP_MUSIC = 0x01 << 1 + ICON_TOP_MOVIE = 0x01 << 2 + ICON_TOP_PHOTO = (0x01 << 1) | (0x01 << 2) + ICON_TOP_CDDVD = 0x01 << 3 + ICON_TOP_TV = (0x01 << 1) | (0x01 << 3) + ICON_TOP_WEBCASTING = (0x01 << 2) | (0x01 << 3) + ICON_TOP_NEWSWEATHER = (0x01 << 1) | (0x01 << 2) | (0x01 << 3) + ICON_CH_2_0 = 0x01 << 4 + ICON_CH_5_1 = 0x01 << 5 + ICON_CH_7_1 = (0x01 << 4) | (0x01 << 5) + ICON_SPDIF = 0x01 << 6 + ICON_OUT_SRC = 0x01 << 7 + ICON_OUT_FIT = 0x01 << 8 + ICON_OUT_SD = 0x01 << 9 + ICON_OUT_HDTV = 0x01 << 10 + ICON_SCR1 = 0x01 << 11 + ICON_SCR2 = 0x01 << 12 + ICON_ACODEC_MP3 = 0x01 << 13 + ICON_ACODEC_OGG = 0x01 << 14 + ICON_ACODEC_AWMA = (0x01 << 13) | (0x01 << 14) + ICON_ACODEC_WAV = 0x01 << 15 + ICON_ACODEC_MPEG = 0x01 << 16 + ICON_ACODEC_AC3 = 0x01 << 17 + ICON_ACODEC_DTS = (0x01 << 16) | (0x01 << 17) + ICON_ACODEC_VWMA = 0x01 << 18 + ICON_VCODEC_MPEG = 0x01 << 19 + ICON_VCODEC_DIVX = 0x01 << 20 + ICON_VCODEC_XVID = (0x01 << 19) | (0x01 << 20) + ICON_VCODEC_WMV = 0x01 << 21 + ICON_VOLUME = 0x01 << 22 + ICON_TIME = 0x01 << 23 + ICON_ALARM = 0x01 << 24 + ICON_REC = 0x01 << 25 + ICON_REPEAT = 0x01 << 26 + ICON_SHUFFLE = 0x01 << 27 + BARS = 0x01 << 28 # additionally needs bar values in other bits + ICON_DISC_IN = 0x01 << 29 + ICON_DUMMY = 0x01 << 30 # Dummy icon so bars won't reset + + # clear masks + ICON_CLEAR_TOPROW = 0xffffffff &~ ((0x01 << 1) | (0x01 << 2) | (0x01 << 3)) + ICON_CLEAR_OUTSCALE = 0xffffffff &~ ((0x01 << 7) | (0x01 << 8) | (0x01 << 9) | (0x01 << 10)) + ICON_CLEAR_CHANNELS = 0xffffffff &~ ((0x01 << 4) | (0x01 << 5)) + ICON_CLEAR_BR = 0xffffffff &~ ((0x01 << 13) | (0x01 << 14) | (0x01 << 15)) + ICON_CLEAR_BM = 0xffffffff &~ ((0x01 << 16) | (0x01 << 17) | (0x01 << 18)) + ICON_CLEAR_BL = 0xffffffff &~ ((0x01 << 19) | (0x01 << 20) | (0x01 << 21)) + +class LCDproc_extra_imon(LCDproc_extra_base): + def __init__(self): + self.m_iOutputValueOldIcons = 1 + self.m_iOutputValueOldBars = 1 + self.m_iOutputValueIcons = 0 + self.m_iOutputValueBars = 0 + self.m_iOutputTimer = time.time() + + LCDproc_extra_base.__init__(self) + + # private + def _DoOutputCommand(self): + ret = False + + if (self.m_iOutputTimer + IMON_OUTPUT_INTERVAL) < time.time(): + ret = True + self.m_iOutputTimer = time.time() + + return ret + + # private + def _SetBarDo(self, barnum, percent): + if barnum == 1: + bitmask = 0x00000FC0 + bitshift = 6 + elif barnum == 2: + bitmask = 0x00FC0000 + bitshift = 18 + elif barnum == 3: + bitmask = 0x0000003F + bitshift = 0 + elif barnum == 4: + bitmask = 0x0003F000 + bitshift = 12 + else: + return + + if percent < 0: + rpercent = 0 + elif percent > 100: + rpercent = 100 + else: + rpercent = percent + + self.m_iOutputValueBars = (self.m_iOutputValueBars &~ bitmask) + self.m_iOutputValueBars |= (int(32 * (rpercent / 100)) << bitshift) & bitmask + self.m_iOutputValueBars |= IMON_ICONS.BARS + + # private + def _SetIconStateDo(self, bitmask, state): + if state: + self.m_iOutputValueIcons |= bitmask + else: + self.m_iOutputValueIcons &= ~bitmask + + def Initialize(self): + for i in range(1, 5): + self.SetBar(i, float(0)) + + def SetOutputIcons(self): + ret = b"" + + # Make sure we don't send "0" to LCDproc, this would reset bars + self.m_iOutputValueIcons |= IMON_ICONS.ICON_DUMMY + + if self.m_iOutputValueIcons != self.m_iOutputValueOldIcons: + self.m_iOutputValueOldIcons = self.m_iOutputValueIcons + ret += b"output %d\n" % (self.m_iOutputValueIcons) + + return ret + + def SetOutputBars(self): + ret = b"" + + if self.m_iOutputValueBars != self.m_iOutputValueOldBars: + self.m_iOutputValueOldBars = self.m_iOutputValueBars + ret += b"output %d\n" % (self.m_iOutputValueBars) + + return ret + + def GetOutputCommands(self): + ret = b"" + + if self._DoOutputCommand(): + ret += self.SetOutputIcons() + + if ret == b"": + ret += self.SetOutputBars() + + return ret + + def SetBar(self, barnum, percent): + self._SetBarDo(barnum, percent) + + def SetIconState(self, icon, state): + if icon == LCD_EXTRAICONS.LCD_EXTRAICON_PLAYING: + self._SetIconStateDo(IMON_ICONS.ICON_SPINDISC, state) + + # Icons used for "Modes" category + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_MOVIE: + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_TOPROW + self._SetIconStateDo(IMON_ICONS.ICON_TOP_MOVIE, state) + + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_MUSIC: + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_TOPROW + self._SetIconStateDo(IMON_ICONS.ICON_TOP_MUSIC, state) + + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_WEBCASTING: + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_TOPROW + self._SetIconStateDo(IMON_ICONS.ICON_TOP_WEBCASTING, state) + + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_WEATHER: + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_TOPROW + self._SetIconStateDo(IMON_ICONS.ICON_TOP_NEWSWEATHER, state) + + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_TV: + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_TOPROW + self._SetIconStateDo(IMON_ICONS.ICON_TOP_TV, state) + + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_PHOTO: + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_TOPROW + self._SetIconStateDo(IMON_ICONS.ICON_TOP_PHOTO, state) + + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_RESOLUTION_SD: + self._SetIconStateDo(IMON_ICONS.ICON_OUT_SD, state) + self._SetIconStateDo(IMON_ICONS.ICON_OUT_HDTV, False) + + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_RESOLUTION_HD: + self._SetIconStateDo(IMON_ICONS.ICON_OUT_SD, False) + self._SetIconStateDo(IMON_ICONS.ICON_OUT_HDTV, state) + + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_OUTSOURCE: + self._SetIconStateDo(IMON_ICONS.ICON_OUT_SRC, state) + self._SetIconStateDo(IMON_ICONS.ICON_OUT_FIT, False) + + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_OUTFIT: + self._SetIconStateDo(IMON_ICONS.ICON_OUT_SRC, False) + self._SetIconStateDo(IMON_ICONS.ICON_OUT_FIT, state) + + # Codec/Channel information + # Video Codecs + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_VCODEC_MPEG: + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_BL + self._SetIconStateDo(IMON_ICONS.ICON_VCODEC_MPEG, state) + + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_VCODEC_DIVX: + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_BL + self._SetIconStateDo(IMON_ICONS.ICON_VCODEC_DIVX, state) + + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_VCODEC_XVID: + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_BL + self._SetIconStateDo(IMON_ICONS.ICON_VCODEC_XVID, state) + + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_VCODEC_WMV: + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_BL + self._SetIconStateDo(IMON_ICONS.ICON_VCODEC_WMV, state) + + # Audio Codecs + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_ACODEC_MPEG: + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_BM + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_BR + self._SetIconStateDo(IMON_ICONS.ICON_ACODEC_MPEG, state) + + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_ACODEC_AC3: + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_BM + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_BR + self._SetIconStateDo(IMON_ICONS.ICON_ACODEC_AC3, state) + + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_ACODEC_DTS: + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_BM + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_BR + self._SetIconStateDo(IMON_ICONS.ICON_ACODEC_DTS, state) + + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_ACODEC_MP3: + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_BM + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_BR + self._SetIconStateDo(IMON_ICONS.ICON_ACODEC_MP3, state) + + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_ACODEC_VWMA: + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_BM + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_BR + self._SetIconStateDo(IMON_ICONS.ICON_ACODEC_VWMA, state) + + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_ACODEC_AWMA: + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_BM + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_BR + self._SetIconStateDo(IMON_ICONS.ICON_ACODEC_AWMA, state) + + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_ACODEC_OGG: + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_BM + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_BR + self._SetIconStateDo(IMON_ICONS.ICON_ACODEC_OGG, state) + + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_ACODEC_WAV: + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_BM + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_BR + self._SetIconStateDo(IMON_ICONS.ICON_ACODEC_WAV, state) + + # Output channels + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_OUT_2_0: + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_CHANNELS + self._SetIconStateDo(IMON_ICONS.ICON_CH_2_0, state) + + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_OUT_5_1: + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_CHANNELS + self._SetIconStateDo(IMON_ICONS.ICON_CH_5_1, state) + + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_OUT_7_1: + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_CHANNELS + self._SetIconStateDo(IMON_ICONS.ICON_CH_7_1, state) + + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_SPDIF: + self._SetIconStateDo(IMON_ICONS.ICON_SPDIF, state) + + # Generic application state icons + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_RECORD: + self._SetIconStateDo(IMON_ICONS.ICON_REC, state) + + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_SHUFFLE: + self._SetIconStateDo(IMON_ICONS.ICON_SHUFFLE, state) + + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_REPEAT: + self._SetIconStateDo(IMON_ICONS.ICON_REPEAT, state) + + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_DISC_IN: + self._SetIconStateDo(IMON_ICONS.ICON_DISC_IN, state) + + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_TIME: + self._SetIconStateDo(IMON_ICONS.ICON_TIME, state) + + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_VOLUME: + self._SetIconStateDo(IMON_ICONS.ICON_VOLUME, state) + + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_ALARM: + self._SetIconStateDo(IMON_ICONS.ICON_ALARM, state) + + def ClearIconStates(self, category): + if category == LCD_EXTRAICONCATEGORIES.LCD_ICONCAT_MODES: + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_TOPROW + + elif category == LCD_EXTRAICONCATEGORIES.LCD_ICONCAT_OUTSCALE: + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_OUTSCALE + + elif category == LCD_EXTRAICONCATEGORIES.LCD_ICONCAT_CODECS: + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_CHANNELS + self.m_iOutputValueIcons &= ~IMON_ICONS.ICON_SPDIF + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_BL + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_BM + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_BR + + elif category == LCD_EXTRAICONCATEGORIES.LCD_ICONCAT_VIDEOCODECS: + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_BL + + elif category == LCD_EXTRAICONCATEGORIES.LCD_ICONCAT_AUDIOCODECS: + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_BM + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_BR + + elif category == LCD_EXTRAICONCATEGORIES.LCD_ICONCAT_AUDIOCHANNELS: + self.m_iOutputValueIcons &= IMON_ICONS.ICON_CLEAR_CHANNELS + + def GetClearAllCmd(self): + self.m_iOutputValueOldIcons = 0 + self.m_iOutputValueOldBars = 0 + self.m_iOutputValueIcons = 0 + self.m_iOutputValueBars = 0 + + return b"output 0\n" diff --git a/resources/lib/lcdproc_extra_mdm166a.py b/resources/lib/lcdproc_extra_mdm166a.py new file mode 100644 index 00000000..4bfe2297 --- /dev/null +++ b/resources/lib/lcdproc_extra_mdm166a.py @@ -0,0 +1,136 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# XBMC LCDproc addon +# Copyright (C) 2012-2024 Team Kodi +# Copyright (C) 2012-2024 Daniel 'herrnst' Scheller +# +# Support for extra symbols on Futaba/Targa USB mdm166a VFD displays +# Original C implementation (C) 2010 Christian Leuschen +# + +from .extraicons import * +from .lcdproc_extra_base import * + +# extra icon bitmasks +class MDM166A_ICONS: + ICON_PLAY = 0x01 << 0 + ICON_PAUSE = 0x01 << 1 + ICON_RECORD = 0x01 << 2 + ICON_MESSAGE = 0x01 << 3 + ICON_AT = 0x01 << 4 + ICON_MUTE = 0x01 << 5 + ICON_ANTENNA = 0x01 << 6 + ICON_VOLUME = 0x01 << 7 + ICON_ANTLOW = 0x01 << 13 + ICON_ANTMED = 0x01 << 14 + ICON_ANTHIGH = (0x01 << 13) | (0x01 << 14) + + # clear masks + ICON_CLEAR_ANTENNABAR = 0xffffffff &~ ((0x01 << 13) | (0x01 << 14)) + +class LCDproc_extra_mdm166a(LCDproc_extra_base): + def __init__(self): + self.m_iOutputValueOldIcons = 1 + self.m_iOutputValueIcons = 0 + + LCDproc_extra_base.__init__(self) + + # private + def _SetBarDo(self, barnum, percent): + # progress bar + if barnum == 1: + bitmask = 0x003F8000 + bitshift = 15 + scale = 96 + # volume indicator + elif barnum == 2: + bitmask = 0x00001F00 + bitshift = 8 + scale = 28 + else: + return + + if percent < 0: + rpercent = 0 + elif percent > 100: + rpercent = 100 + else: + rpercent = percent + + self.m_iOutputValueIcons = (self.m_iOutputValueIcons &~ bitmask) + self.m_iOutputValueIcons |= (int(scale * (rpercent / 100)) << bitshift) & bitmask + + # private + def _SetIconStateDo(self, bitmask, state): + if state: + self.m_iOutputValueIcons |= bitmask + else: + self.m_iOutputValueIcons &= ~bitmask + + def Initialize(self): + for i in range(1, 5): + self.SetBar(i, float(0)) + + def SetOutputIcons(self): + ret = b"" + + if self.m_iOutputValueIcons != self.m_iOutputValueOldIcons: + self.m_iOutputValueOldIcons = self.m_iOutputValueIcons + ret += b"output %d\n" % (self.m_iOutputValueIcons) + + return ret + + def GetOutputCommands(self): + return self.SetOutputIcons() + + def SetBar(self, barnum, percent): + self._SetBarDo(barnum, percent) + + def SetIconState(self, icon, state): + # General states + if icon == LCD_EXTRAICONS.LCD_EXTRAICON_MUTE: + self._SetIconStateDo(MDM166A_ICONS.ICON_MUTE, state) + + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_PLAYING: + self._SetIconStateDo(MDM166A_ICONS.ICON_PLAY, state) + + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_PAUSE: + self._SetIconStateDo(MDM166A_ICONS.ICON_PAUSE, state) + + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_ALARM: + self._SetIconStateDo(MDM166A_ICONS.ICON_MESSAGE, state) + + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_RECORD: + self._SetIconStateDo(MDM166A_ICONS.ICON_RECORD, state) + + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_VOLUME: + self._SetIconStateDo(MDM166A_ICONS.ICON_VOLUME, state) + + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_SPDIF: + self._SetIconStateDo(MDM166A_ICONS.ICON_ANTENNA, state) + + # Output channels + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_OUT_2_0: + self.m_iOutputValueIcons &= MDM166A_ICONS.ICON_CLEAR_ANTENNABAR + self._SetIconStateDo(MDM166A_ICONS.ICON_ANTLOW, state) + + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_OUT_5_1: + self.m_iOutputValueIcons &= MDM166A_ICONS.ICON_CLEAR_ANTENNABAR + self._SetIconStateDo(MDM166A_ICONS.ICON_ANTMED, state) + + elif icon == LCD_EXTRAICONS.LCD_EXTRAICON_OUT_7_1: + self.m_iOutputValueIcons &= MDM166A_ICONS.ICON_CLEAR_ANTENNABAR + self._SetIconStateDo(MDM166A_ICONS.ICON_ANTHIGH, state) + + def ClearIconStates(self, category): + if category == LCD_EXTRAICONCATEGORIES.LCD_ICONCAT_CODECS: + self.m_iOutputValueIcons &= MDM166A_ICONS.ICON_CLEAR_ANTENNABAR + + elif category == LCD_EXTRAICONCATEGORIES.LCD_ICONCAT_AUDIOCHANNELS: + self.m_iOutputValueIcons &= MDM166A_ICONS.ICON_CLEAR_ANTENNABAR + + def GetClearAllCmd(self): + self.m_iOutputValueOldIcons = 0 + self.m_iOutputValueIcons = 0 + + return b"output 0\n" diff --git a/resources/lib/settings.py b/resources/lib/settings.py new file mode 100644 index 00000000..c8f3e72c --- /dev/null +++ b/resources/lib/settings.py @@ -0,0 +1,264 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# XBMC LCDproc addon +# Copyright (C) 2012-2024 Team Kodi +# Copyright (C) 2012-2024 Daniel 'herrnst' Scheller +# + +import time + +from .common import * + +class Settings(): + + ######## + # ctor + def __init__(self): + # init class members (settings) with defaults + self._hostip = "127.0.0.1" + self._hostport = 13666 + self._timer = time.time() + self._heartbeat = False + self._scrolldelay = 1 + self._scrollmode = "0" + self._settingsChanged = True + self._dimonscreensaver = False + self._dimonshutdown = False + self._dimonvideoplayback = False + self._dimonmusicplayback = False + self._dimdelay = 0 + self._navtimeout = 3 + self._refreshrate = 1 + self._hideconnpopups = True + self._usealternatecharset = False + self._charset = "iso-8859-1" + self._useextraelements = True + self._systimeformat = 3 + + def getHostIp(self): + return self._hostip + + def getHostPort(self): + return self._hostport + + def getHeartBeat(self): + return self._heartbeat + + def getUseExtraElements(self): + return self._useextraelements + + def getScrollDelay(self): + return self._scrolldelay + + def getScrollMode(self): + return self._scrollmode + + def getLCDprocScrollMode(self): + if self._scrollmode == "1": + return "h" + return "m" + + def getDimOnScreensaver(self): + return self._dimonscreensaver + + def getDimOnShutdown(self): + return self._dimonshutdown + + def getDimOnVideoPlayback(self): + return self._dimonvideoplayback + + def getDimOnMusicPlayback(self): + return self._dimonmusicplayback + + def getDimDelay(self): + return self._dimdelay + + def getNavTimeout(self): + return self._navtimeout + + def getRefreshRate(self): + return self._refreshrate + + def getHideConnPopups(self): + return self._hideconnpopups + + def getSysTimeFormat(self): + # make sure to keep this in sync with settings.xml! + ret = "HH:mm:ss" + if self._systimeformat == "0": + ret = "H:mm" + elif self._systimeformat == "1": + ret = "HH:mm" + elif self._systimeformat == "2": + ret = "H:mm:ss" + elif self._systimeformat == "3": + ret = "HH:mm:ss" + + return ret + + def getCharset(self): + ret = "" + + # if alternatecharset is disabled, return LCDproc's default + if self._usealternatecharset == False: + ret = "iso-8859-1" + else: + # make sure to keep this in sync with settings.xml! + if self._charset == "1": + ret = "iso-8859-15" + elif self._charset == "2": + ret = "koi8-r" + elif self._charset == "3": + ret = "cp1251" + elif self._charset == "4": + ret = "iso-8859-5" + elif self._charset == "5": + ret = "hd44780_a00" + elif self._charset == "6": + ret = "hd44780_a02" + else: + ret = "iso-8859-1" + + return ret + + # check for new settings and handle them if anything changed + # only checks if the last check is 5 secs old + # returns if a reconnect is needed due to settings change + def checkForNewSettings(self): + # TODO: for now impl. stat on addon.getAddonInfo('profile')/settings.xml and use mtime + # check for new settings every 5 secs + reconnect = False + + if time.time() - self._timer > 5: + reconnect = self.setup() + self._timer = time.time() + + return reconnect + + def didSettingsChange(self): + settingsChanged = self._settingsChanged + self._settingsChanged = False + return settingsChanged + + # handle all settings that might require a reinit and/or reconnect + # (e.g. network config changes) + # returns true if reconnect is needed due to network changes + def handleCriticalSettings(self): + reconnect = False + + hostip = KODI_ADDON_SETTINGS.getSetting("hostip") + hostport = int(KODI_ADDON_SETTINGS.getSetting("hostport")) + heartbeat = KODI_ADDON_SETTINGS.getSetting("heartbeat") == "true" + useextraelements = KODI_ADDON_SETTINGS.getSetting("useextraelements") == "true" + + # server settings + # we need to reconnect if networkaccess bool changes + # or if network access is enabled and ip or port have changed + if self._hostip != hostip or self._hostport != hostport or self._heartbeat != heartbeat: + if self._hostip != hostip: + log(LOGDEBUG, "settings: changed hostip to " + str(hostip)) + self._hostip = hostip + reconnect = True + + if self._hostport != hostport: + # make sure valid port number was given + if hostport > 0 and hostport < 65536: + log(LOGDEBUG, "settings: changed hostport to " + str(hostport)) + self._hostport = hostport + reconnect = True + else: + log(LOGDEBUG, "settings: invalid hostport value " + str(hostport) + ", resetting to old value " + str(self._hostport)) + KODI_ADDON_SETTINGS.setSetting("hostport", str(self._hostport)) + + if self._heartbeat != heartbeat: + log(LOGDEBUG, "settings: toggled heartbeat bool") + self._heartbeat = heartbeat + reconnect = True + + # extra element support needs a reinit+reconnect so the extraelement + # support object resets + if self._useextraelements != useextraelements: + self._useextraelements = useextraelements + reconnect = True + + return reconnect + + def handleLcdSettings(self): + scrolldelay = int(float(KODI_ADDON_SETTINGS.getSetting("scrolldelay").replace(",", "."))) + scrollmode = KODI_ADDON_SETTINGS.getSetting("scrollmode") + dimonscreensaver = KODI_ADDON_SETTINGS.getSetting("dimonscreensaver") == "true" + dimonshutdown = KODI_ADDON_SETTINGS.getSetting("dimonshutdown") == "true" + dimonvideoplayback = KODI_ADDON_SETTINGS.getSetting("dimonvideoplayback") == "true" + dimonmusicplayback = KODI_ADDON_SETTINGS.getSetting("dimonmusicplayback") == "true" + dimdelay = int(float(KODI_ADDON_SETTINGS.getSetting("dimdelay").replace(",", "."))) + navtimeout = int(float(KODI_ADDON_SETTINGS.getSetting("navtimeout").replace(",", "."))) + refreshrate = int(float(KODI_ADDON_SETTINGS.getSetting("refreshrate").replace(",", "."))) + hideconnpopups = KODI_ADDON_SETTINGS.getSetting("hideconnpopups") == "true" + usealternatecharset = KODI_ADDON_SETTINGS.getSetting("usealternatecharset") == "true" + charset = KODI_ADDON_SETTINGS.getSetting("charset") + systimeformat = KODI_ADDON_SETTINGS.getSetting("systimeformat") + + if self._scrolldelay != scrolldelay: + self._scrolldelay = scrolldelay + self._settingsChanged = True + + if self._scrollmode != scrollmode: + self._scrollmode = scrollmode + self._settingsChanged = True + + if self._dimonscreensaver != dimonscreensaver: + self._dimonscreensaver = dimonscreensaver + self._settingsChanged = True + + if self._dimonshutdown != dimonshutdown: + self._dimonshutdown = dimonshutdown + self._settingsChanged = True + + if self._dimonvideoplayback != dimonvideoplayback: + self._dimonvideoplayback = dimonvideoplayback + self._settingsChanged = True + + if self._dimonmusicplayback != dimonmusicplayback: + self._dimonmusicplayback = dimonmusicplayback + self._settingsChanged = True + + if self._dimdelay != dimdelay: + self._dimdelay = dimdelay + self._settingsChanged = True + + if self._navtimeout != navtimeout: + self._navtimeout = navtimeout + self._settingsChanged = True + + if self._refreshrate != refreshrate: + self._refreshrate = refreshrate + + if refreshrate < 1: + self._refreshrate = 1 + + self._settingsChanged = True + + if self._hideconnpopups != hideconnpopups: + self._hideconnpopups = hideconnpopups + self._settingsChanged = True + + if self._usealternatecharset != usealternatecharset: + self._usealternatecharset = usealternatecharset + self._settingsChanged = True + + if self._charset != charset: + self._charset = charset + self._settingsChanged = True + + if self._systimeformat != systimeformat: + self._systimeformat = systimeformat + self._settingsChanged = True + + # handles all settings and applies them as needed + # returns if a reconnect is needed due to settings changes + def setup(self): + reconnect = False + reconnect = self.handleCriticalSettings() + self.handleLcdSettings() + + return reconnect diff --git a/resources/lib/xbmclcdproc.py b/resources/lib/xbmclcdproc.py new file mode 100644 index 00000000..84185fff --- /dev/null +++ b/resources/lib/xbmclcdproc.py @@ -0,0 +1,88 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# XBMC LCDproc addon +# Copyright (C) 2012-2024 Team Kodi +# Copyright (C) 2012-2024 Daniel 'herrnst' Scheller +# +# Main addon handler/control +# + +# base imports +import time + +# Kodi imports +import xbmc +import xbmcgui + +from .common import * +from .settings import * +from .lcdproc import * + +class XBMCLCDproc(): + + ######## + # ctor + def __init__(self): + self._failedConnectionNotified = False + self._initialConnectAttempt = True + + # instantiate xbmc.Monitor object + self._xbmcMonitor = xbmc.Monitor() + + # instantiate Settings object + self._Settings = Settings() + + # instantiate LCDProc object + self._LCDproc = LCDProc(self._Settings) + + # initialize components + self._Settings.setup() + + ######## + # HandleConnectionNotification(): + # evaluate and handle dispay of connection notification popups + def HandleConnectionNotification(self, bConnectSuccess): + if not bConnectSuccess: + if not self._failedConnectionNotified: + self._failedConnectionNotified = True + self._initialConnectAttempt = False + text = KODI_ADDON_SETTINGS.getLocalizedString(32500) + xbmcgui.Dialog().notification(KODI_ADDON_NAME, text, KODI_ADDON_ICON) + else: + text = KODI_ADDON_SETTINGS.getLocalizedString(32501) + if not self._initialConnectAttempt: + xbmcgui.Dialog().notification(KODI_ADDON_NAME, text, KODI_ADDON_ICON) + self._failedConnectionNotified = True + + def HandleConnectLCD(self): + ret = True + + reconnect = self._Settings.checkForNewSettings() + + # check for new settings - networksettings changed? + if reconnect or not self._LCDproc.IsConnected(): + + # reset notification flag if settingchanges require reconnect + if reconnect: + self._failedConnectionNotified = False + + ret = self._LCDproc.Initialize() + if not self._Settings.getHideConnPopups(): + self.HandleConnectionNotification(ret) + + return ret + + ######## + # RunLCD(): + # Main loop, triggers data inquiry and rendering, handles setting changes and connection issues + def RunLCD(self): + while not self._xbmcMonitor.waitForAbort(1.0 / float(self._Settings.getRefreshRate())): + if self.HandleConnectLCD(): + settingsChanged = self._Settings.didSettingsChange() + + if settingsChanged: + self._LCDproc.UpdateGUISettings() + + self._LCDproc.Render(settingsChanged) + + self._LCDproc.Shutdown() diff --git a/resources/settings.xml b/resources/settings.xml new file mode 100644 index 00000000..b8d154a3 --- /dev/null +++ b/resources/settings.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/script.xbmc.lcd/addon.xml b/script.xbmc.lcd/addon.xml deleted file mode 100644 index cfc417e3..00000000 --- a/script.xbmc.lcd/addon.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - XBMC LCD/VFD - This addon will add the LCD/VFD feature which was integrated into XBMC before. There has to be an lcdproc daemon (LCDd) running somewhere in the network or local to use the addon. - all - - diff --git a/script.xbmc.lcd/changelog.txt b/script.xbmc.lcd/changelog.txt deleted file mode 100644 index 286dcd13..00000000 --- a/script.xbmc.lcd/changelog.txt +++ /dev/null @@ -1,2 +0,0 @@ -1.0.0 -- initial addon release diff --git a/script.xbmc.lcd/lcdmain.py b/script.xbmc.lcd/lcdmain.py deleted file mode 100644 index 4598b2e8..00000000 --- a/script.xbmc.lcd/lcdmain.py +++ /dev/null @@ -1,156 +0,0 @@ -''' - FHEM for XBMC - Copyright (C) 2011 Team XBMC - - 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. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -''' -import xbmc -import xbmcaddon -import xbmcgui -import time -import os - -__settings__ = xbmcaddon.Addon(id='script.xbmc.lcd') -__cwd__ = __settings__.getAddonInfo('path') -__icon__ = os.path.join(__cwd__,"icon.png") -__scriptname__ = "XBMC LCD/VFD" - -BASE_RESOURCE_PATH = xbmc.translatePath( os.path.join( __cwd__, 'resources', 'lib' ) ) -sys.path.append (BASE_RESOURCE_PATH) - -from settings import * -from lcdproc import * - -global g_failedConnectionNotified -global g_lcdproc - -global g_oldMenu -global g_oldSubMenu -global g_timer - -def initGlobals(): - global g_failedConnectionNotified - global g_lcdproc - global g_oldMenu - global g_oldSubMenu - global g_timer - - g_failedConnectionNotified = False - settings_initGlobals() - g_lcdproc = LCDProc() - g_oldMenu = "" - g_oldSubMenu = "" - g_timer = time.time() - - -#returns the settings category based on the currently played media -#returns "movie" if a movies is played, "musicvideo" if a musicvideo is played", "other" else -def getLcdMode(): - ret = LCD_MODE.LCD_MODE_GENERAL -# LCD_MODE_XBE_LAUNCH = 5 - screenSaver = xbmc.getCondVisibility("System.ScreenSaverActive") - playingVideo = xbmc.getCondVisibility("Player.HasVideo") - playingMusic = xbmc.getCondVisibility("Player.HasAudio") - - if screenSaver: - ret = LCD_MODE.LCD_MODE_SCREENSAVER - elif playingVideo: #we play something - ret = LCD_MODE.LCD_MODE_VIDEO - elif playingMusic: - ret = LCD_MODE.LCD_MODE_MUSIC - - return ret - -def process_lcd(): - global g_oldMenu - global g_oldSubMenu - global g_timer - - bBacklightDimmed = False - - while not xbmc.abortRequested: - handleConnectLCD() - navtimeout = settings_getNavTimeout() - menu = xbmc.getInfoLabel("$INFO[System.CurrentWindow]") - subMenu = xbmc.getInfoLabel("$INFO[System.CurrentControl]") - settingsChanged = settings_didSettingsChange() - mode = getLcdMode() - - #handle navigation - if menu != g_oldMenu or subMenu != g_oldSubMenu or (g_timer + navtimeout) > time.time(): - g_lcdproc.Render(LCD_MODE.LCD_MODE_NAVIGATION,settingsChanged) - if menu != g_oldMenu or subMenu != g_oldSubMenu: - g_timer = time.time() - g_oldMenu = menu - g_oldSubMenu = subMenu - else:#handle all other lcd modes - if mode == LCD_MODE.LCD_MODE_SCREENSAVER and settings_getDimOnScreensaver(): - g_lcdproc.SetBackLight(0) - bBacklightDimmed = True - g_lcdproc.Render(getLcdMode(),settingsChanged) - #turn the backlight on when leaving screensaver and it was dimmed - if mode != LCD_MODE.LCD_MODE_SCREENSAVER and bBacklightDimmed: - g_lcdproc.SetBackLight(1) - bBacklightDimmed = False - - if mode == LCD_MODE.LCD_MODE_MUSIC: - g_lcdproc.DisableOnPlayback(False, True) - elif mode == LCD_MODE.LCD_MODE_VIDEO: - g_lcdproc.DisableOnPlayback(True, False) - else: - g_lcdproc.DisableOnPlayback(False, False) - - time.sleep(1) #refresh every second - -def handleConnectLCD(): - global g_failedConnectionNotified - - while not xbmc.abortRequested: - #check for new settings - if settings_checkForNewSettings() or not g_lcdproc.IsConnected(): #networksettings changed? - g_failedConnectionNotified = False #reset notification flag - else: - return True - - ret = g_lcdproc.Initialize() - - if not ret: - print "lcd: connection to LCDProc failed" - count = 10 - while (not xbmc.abortRequested) and (count > 0): - time.sleep(1) - count -= 1 - if not g_failedConnectionNotified: - g_failedConnectionNotified = True - text = __settings__.getLocalizedString(500) - xbmc.executebuiltin("XBMC.Notification(%s,%s,%s,%s)" % (__scriptname__,text,10,__icon__)) - else: - text = __settings__.getLocalizedString(501) - if not g_failedConnectionNotified: - xbmc.executebuiltin("XBMC.Notification(%s,%s,%s,%s)" % (__scriptname__,text,10,__icon__)) - g_failedConnectionNotified = True - print "lcd: connected to LCD" - break - return True - -#MAIN - entry point -initGlobals() - -#main loop -while not xbmc.abortRequested: - settings_setup() - process_lcd() #lcd loop - -#lcd_initGlobals() #clears lists - for skin doesn't show the old values -#fhem_updateInfoWindow() #push cleared values to the skin diff --git a/script.xbmc.lcd/resources/language/English/strings.xml b/script.xbmc.lcd/resources/language/English/strings.xml deleted file mode 100644 index 3aed6167..00000000 --- a/script.xbmc.lcd/resources/language/English/strings.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - General - Use remote LCDProc - LCDd IP - Show heartbeat symbol - Delay for scrolling text - Dim backlight on screensaver - Navigation display duration (s) - - - - Failed to connect to LCDProc! - Connected to LCDProc! - Settings changed! - - - diff --git a/script.xbmc.lcd/resources/language/German/strings.xml b/script.xbmc.lcd/resources/language/German/strings.xml deleted file mode 100644 index f956f254..00000000 --- a/script.xbmc.lcd/resources/language/German/strings.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - Allgemein - Entfernten LCDProc server benutzen - LCDd IP - Heartbeatsymbol anzeigen - Geschwindigkeit fuer gescrollten Text - Hintergrundbeleuchtung ausschalten, wenn Bildschirmschoner laeuft - Anzeigedauer der Navigationsansicht (s) - - - Fehler beim Verbinden zu LCDProc! - Verbunden mit LCDProc! - Einstellungen geaendert! - diff --git a/script.xbmc.lcd/resources/lib/lcdbase.py b/script.xbmc.lcd/resources/lib/lcdbase.py deleted file mode 100644 index f3138ad9..00000000 --- a/script.xbmc.lcd/resources/lib/lcdbase.py +++ /dev/null @@ -1,468 +0,0 @@ -''' - LCD/VFD for XBMC - Copyright (C) 2011 Team XBMC - - 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. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -''' - -import platform -import xbmc -import xbmcgui -import sys -import os -import re -import telnetlib -import time - -from xml.etree import ElementTree as xmltree -from array import array - -__scriptname__ = sys.modules[ "__main__" ].__scriptname__ -__settings__ = sys.modules[ "__main__" ].__settings__ -__cwd__ = sys.modules[ "__main__" ].__cwd__ -__icon__ = sys.modules[ "__main__" ].__icon__ -__lcdxml__ = xbmc.translatePath( os.path.join("special://masterprofile","LCD.xml")) - -from settings import * - -# global functions -def log(loglevel, msg): - xbmc.log("### [%s] - %s" % (__scriptname__,msg,),level=loglevel ) - -''' -# TEMPLATE: TRANSLATION-TABLE FOR FUTURE LCD-TYPE-CHARSETS -{ -0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, -0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, -0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, -0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, -0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, -0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, -0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, -0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, -0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, -0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, -0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, -0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, -0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, -0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, -0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, -0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff -} - -''' -''' -# UNUSED by now -def GetLCDCharsetCharacter(_nCharacter, _nCharset): - - arrCharsets = [[ # Xbmc default, currently implemented elsewhere - [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], - [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], - [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], - [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], - [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], - [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], - [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], - [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] - ], - [ # Small Char - [0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01], # | _ - [0x1f, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x1f], # _ _| - [0x1f, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11], # | | - [0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x1f], # _| - [0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x1f], # |_| _ - [0x1f, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1f], # _ |_ - [0x1f, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01], # | _ - [0x1f, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x1f] # |_| - ], - [ # Medium Char - [0x1f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], # - [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f], # _ - [0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x1f], # |_ _ - [0x1f, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18], # _ | - [0x1f, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x1f], # |_ _ - [0x1f, 0x1f, 0x03, 0x03, 0x03, 0x03, 0x1f, 0x1f], # _ _| - [0x1f, 0x1f, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03], # | - [0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x1f, 0x1f] # _| - ], - [ # Big Char - [0x01, 0x03, 0x03, 0x07, 0x07, 0x0f, 0x0f, 0x1f], # topleft corner - [0x10, 0x18, 0x18, 0x1c, 0x1c, 0x1e, 0x1e, 0x1f], # topright corner - [0x1f, 0x1e, 0x1e, 0x1c, 0x1c, 0x18, 0x18, 0x10], # bottomright corner - [0x1f, 0x0f, 0x0f, 0x07, 0x07, 0x03, 0x03, 0x01], # bottomleft corner - [0x1f, 0x1f, 0x1f, 0x1f, 0x00, 0x00, 0x00, 0x00], # upper half block - # Free to use - [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], - [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], - [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] - ]] - - if _nCharset == -1: - _nCharset = m_eCurrentCharset - - if ( ( _nCharacter >= 64 ) or ( _nCharset >= CUSTOM_CHARSET.CUSTOM_CHARSET_MAX ) ): - return 0 - - return arrCharsets[_nCharset][_nCharacter/8][_nCharacter%8] -''' - -# enumerations -class DISABLE_ON_PLAY: - DISABLE_ON_PLAY_NONE = 0 - DISABLE_ON_PLAY_VIDEO = 1 - DISABLE_ON_PLAY_MUSIC = 2 - -class LCD_MODE: - LCD_MODE_GENERAL = 0 - LCD_MODE_MUSIC = 1 - LCD_MODE_VIDEO = 2 - LCD_MODE_NAVIGATION = 3 - LCD_MODE_SCREENSAVER = 4 - LCD_MODE_XBE_LAUNCH = 5 - LCD_MODE_MAX = 6 - -class CUSTOM_CHARSET: - CUSTOM_CHARSET_DEFAULT = 0 - CUSTOM_CHARSET_SMALLCHAR = 1 - CUSTOM_CHARSET_MEDIUMCHAR = 2 - CUSTOM_CHARSET_BIGCHAR = 3 - CUSTOM_CHARSET_MAX = 4 - -class LcdBase(): - def __init__(self): - self.m_disableOnPlay = DISABLE_ON_PLAY.DISABLE_ON_PLAY_NONE - self.m_eCurrentCharset = CUSTOM_CHARSET.CUSTOM_CHARSET_DEFAULT - self.m_lcdMode = [None] * LCD_MODE.LCD_MODE_MAX - self.m_bDimmedOnPlayback = False - -# @abstractmethod - def _concrete_method(self): - pass -# @abstractmethod - def Stop(self): - pass - -# @abstractmethod - def Suspend(self): - pass - -# @abstractmethod - def Resume(self): - pass - -# @abstractmethod - def SetBackLight(self, iLight): - pass - -# @abstractmethod - def SetContrast(self, iContrast): - pass - -# @abstractmethod - def SetLine(self, iLine, strLine): - pass - -# @abstractmethod - def GetColumns(self): - pass - -# @abstractmethod - def GetRows(self): - pass - -# @abstractmethod - def SetProgressBar(self, percent, lineIdx): - pass - - def GetProgressBarPercent(self, tCurrent, tTotal): - return float(tCurrent)/float(tTotal) - - def SetCharset(self,_nCharset): - if _nCharset < CUSTOM_CHARSET.CUSTOM_CHARSET_MAX: - self.m_eCurrentCharset = _nCharset - - def GetBigDigit(self,_nCharset, _nDigit, _nLine, _nMinSize, _nMaxSize, _bSpacePadding): - # Get the partial digit(s) for the given line - # that is needed to build a big character - nCurrentSize = 0 - nCurrentValue = 0 - nValue = 0 - strDigits = "" - strCurrentDigit = "" - - # If the charset doesn't match our - # custom chars, return with nothing - # The XBMC 'icon' charset - if ( _nCharset == CUSTOM_CHARSET.CUSTOM_CHARSET_DEFAULT ) or ( _nCharset >= CUSTOM_CHARSET.CUSTOM_CHARSET_MAX ): - return "" - - arrSizes = [ - [ 1, 1 ], - [ 1, 2 ], - [ 2, 2 ], - [ 3, 4 ]] - - # Return with nothing if the linenumber falls outside our char 'height' - if _nLine > arrSizes[ _nCharset ][1]: - return "" - - # Define the 2x1 line characters - arrMedNumbers = [ - [[0x0a], [0x0c]], # 0 - [[0x08], [0x08]], # 1 # 0xaf - [[0x0e], [0x0d]], # 2 - [[0x09], [0x0b]], # 3 - [[0x0c], [0x08]], # 4 - [[0x0d], [0x0b]], # 5 - [[0x0d], [0x0c]], # 6 - [[0x0e], [0x08]], # 7 - [[0x0f], [0x0c]], # 8 - [[0x0f], [0x0b]]] # 9 - - # Define the 2x2 bold line characters - arrMedBoldNumbers = [ - [[0x0b, 0x0e], [0x0a, 0x0f]], #0 - [[0x0e, 0x20], [0x0f, 0x09]], #1 - [[0x08, 0x0d], [0x0c, 0x09]], #2 - [[0x08, 0x0d], [0x09, 0x0f]], #3 - [[0x0a, 0x0f], [0x20, 0x0e]], #4 - [[0x0c, 0x08], [0x09, 0x0d]], #5 - [[0x0b, 0x08], [0x0c, 0x0d]], #6 - [[0x08, 0x0e], [0x20, 0x0e]], #7 - [[0x0c, 0x0d], [0x0a, 0x0f]], #8 - [[0x0c, 0x0d], [0x09, 0x0f]]] # 9 - - # Define the 4 line characters (this could be more readable, but that may take up to 3 screens) - arrBigNumbers = [ - [ - [0x08, 0xa0, 0x09], # 0 - [0xa0, 0x20, 0xa0], # 0 - [0xa0, 0x20, 0xa0], # 0 - [0x0b, 0xa0, 0x0a], # 0 - ], - [ - [0x08, 0xa0, 0x20], # 1 - [0x20, 0xa0, 0x20], # 1 - [0x20, 0xa0, 0x20], # 1 - [0xa0, 0xa0, 0xa0], # 1 - ], - [ - [0x08, 0xa0, 0x09], # 2 - [0x20, 0x08, 0x0a], # 2 - [0x08, 0x0a, 0x20], # 2 - [0xa0, 0xa0, 0xa0], # 2 - ], - [ - [0x08, 0xa0, 0x09], # 3 - [0x20, 0x20, 0xa0], # 3 - [0x20, 0x0c, 0xa0], # 3 - [0x0b, 0xa0, 0x0a], # 3 - ], - [ - [0xa0, 0x20, 0xa0], # 4 - [0xa0, 0xa0, 0xa0], # 4 - [0x20, 0x20, 0xa0], # 4 - [0x20, 0x20, 0xa0], # 4 - ], - [ - [0xa0, 0xa0, 0xa0], # 5 - [0xa0, 0x20, 0x20], # 5 - [0x20, 0x0c, 0xa0], # 5 - [0xa0, 0xa0, 0x0a], # 5 - ], - [ - [0x08, 0xa0, 0x09], # 6 - [0xa0, 0x20, 0x20], # 6 - [0xa0, 0x0c, 0xa0], # 6 - [0x0b, 0xa0, 0x0a], # 6 - ], - [ - [0xa0, 0xa0, 0xa0], # 7 - [0x20, 0x20, 0xa0], # 7 - [0x20, 0x20, 0xa0], # 7 - [0x20, 0x20, 0xa0], # 7 - ], - [ - [0x08, 0xa0, 0x09], # 8 - [0xa0, 0x20, 0xa0], # 8 - [0xa0, 0x0c, 0xa0], # 8 - [0x0b, 0xa0, 0x0a], # 8 - ], - [ - [0x08, 0xa0, 0x09], # 9 - [0xa0, 0x20, 0xa0], # 9 - [0x20, 0x0c, 0xa0], # 9 - [0x0b, 0xa0, 0x0a], # 9 - ], - ] - - - if _nDigit < 0: - # TODO: Add a '-' sign - _nDigit = -_nDigit - - # Set the current size, and value (base numer) - nCurrentSize = 1 - nCurrentValue = 10 - - # Build the characters - strDigits = "" - - while ( nCurrentSize <= _nMinSize ) or ( _nDigit >= nCurrentValue and (nCurrentSize <= _nMaxSize or _nMaxSize == 0) ): - # Determine current value - nValue = ( _nDigit % nCurrentValue ) / ( nCurrentValue / 10 ) - - # Reset current digit - strCurrentDigit = "" - for nX in range(0, arrSizes[ _nCharset ][0]): - # Add a space if we have more than one digit, and the given - # digit is smaller than the current value (base numer) we are dealing with - if _bSpacePadding and ((nCurrentValue / 10) > _nDigit ) and ( nCurrentSize > 1 ): - strCurrentDigit += " " - # TODO: make sure this is not hardcoded - else: - if _nCharset == CUSTOM_CHARSET.CUSTOM_CHARSET_SMALLCHAR: - strCurrentDigit += arrMedNumbers[ nValue ][ _nLine ][ nX ] - elif _nCharset == CUSTOM_CHARSET.CUSTOM_CHARSET_SMALLCHAR: - strCurrentDigit += arrMedBoldNumbers[ nValue ][ _nLine ][ nX ] - elif _nCharset == CUSTOM_CHARSET.CUSTOM_CHARSET_BIGCHAR: - strCurrentDigit += arrBigNumbers[ nValue ][ _nLine ][ nX ] - - # Add as partial string - # Note that is it reversed, I.E. 'LSB' is added first - strDigits = strCurrentDigit + strDigits - - # Increase the size and base number - nCurrentSize += 1 - nCurrentValue *= 10 - - # Update the character mode - m_eCurrentCharset = _nCharset - - # Return the created digit part - return strDigits - - def Initialize(self): - self.m_eCurrentCharset = CUSTOM_CHARSET.CUSTOM_CHARSET_DEFAULT - self.m_disableOnPlay = DISABLE_ON_PLAY.DISABLE_ON_PLAY_NONE - self.LoadSkin(__lcdxml__) - - # Big number blocks, used for screensaver clock - # Note, the big block isn't here, it's in the LCD's ROM - - def IsConnected(self): - return True - - - def LoadSkin(self, xmlFile): - self.Reset() - doc = xmltree.parse(xmlFile) - for element in doc.getiterator(): - #PARSE LCD infos - if element.tag == "lcd": - # load our settings - disableOnPlay = element.find("disableonplay") - if disableOnPlay != None: - self.m_disableOnPlay = DISABLE_ON_PLAY.DISABLE_ON_PLAY_NONE - if str(disableOnPlay.text).find("video") >= 0: - self.m_disableOnPlay += DISABLE_ON_PLAY.DISABLE_ON_PLAY_VIDEO - if str(disableOnPlay.text).find("music") >= 0: - self.m_disableOnPlay += DISABLE_ON_PLAY.DISABLE_ON_PLAY_MUSIC - #load moads - tmpMode = element.find("music") - self.LoadMode(tmpMode, LCD_MODE.LCD_MODE_MUSIC) - - tmpMode = element.find("video") - self.LoadMode(tmpMode, LCD_MODE.LCD_MODE_VIDEO) - - tmpMode = element.find("general") - self.LoadMode(tmpMode, LCD_MODE.LCD_MODE_GENERAL) - - tmpMode = element.find("navigation") - self.LoadMode(tmpMode, LCD_MODE.LCD_MODE_NAVIGATION) - - tmpMode = element.find("screensaver") - self.LoadMode(tmpMode, LCD_MODE.LCD_MODE_SCREENSAVER) - - tmpMode = element.find("xbelaunch") - self.LoadMode(tmpMode, LCD_MODE.LCD_MODE_XBE_LAUNCH) - - - def LoadMode(self, node, mode): - if node == None: - return - for line in node.findall("line"): - self.m_lcdMode[mode].append(str(line.text)) - - def Reset(self): - self.m_disableOnPlay = DISABLE_ON_PLAY.DISABLE_ON_PLAY_NONE - for i in range(0,LCD_MODE.LCD_MODE_MAX): - self.m_lcdMode[i] = [] #clear list - - def timeToSecs(self, timeAr): - arLen = len(timeAr) - if arLen == 1: - currentSecs = int(timeAr[0]) - elif arLen == 2: - currentSecs = int(timeAr[0]) * 60 + int(timeAr[1]) - elif arLen == 3: - currentSecs = int(timeAr[0]) * 60 * 60 + int(timeAr[1]) * 60 + int(timeAr[2]) - return currentSecs - - def getCurrentTimeSecs(self): - currentTimeAr = xbmc.getInfoLabel("Player.Time").split(":") - return self.timeToSecs(currentTimeAr) - - def getCurrentDurationSecs(self): - currentDurationAr = xbmc.getInfoLabel("Player.Duration").split(":") - return self.timeToSecs(currentDurationAr) - - def Render(self, mode, bForce): - outLine = 0 - inLine = 0 - - while (outLine < int(self.GetRows()) and inLine < len(self.m_lcdMode[mode])): - #parse the progressbar infolabel by ourselfs! - if self.m_lcdMode[mode][inLine] == "$INFO[LCD.ProgressBar]": - # get playtime and duration and convert into seconds - currentSecs = self.getCurrentTimeSecs() - durationSecs = self.getCurrentDurationSecs() - percent = self.GetProgressBarPercent(currentSecs,durationSecs) - pixelsWidth = self.SetProgressBar(percent, outLine) - line = "p" + str(pixelsWidth) - else: - line = xbmc.getInfoLabel(self.m_lcdMode[mode][inLine]) - self.SetProgressBar(0, -1) - - inLine += 1 - if len(line) > 0: -# log(xbmc.LOGDEBUG, "Request write of line" + str(outLine) + ": " + str(line)) - self.SetLine(outLine, line, bForce) - outLine += 1 - - # fill remainder with empty space - while outLine < int(self.GetRows()): -# log(xbmc.LOGDEBUG, "Request write of emptyline" + str(outLine)) - self.SetLine(outLine, "", bForce) - outLine += 1 - - def DisableOnPlayback(self, playingVideo, playingAudio): - if (playingVideo and (self.m_disableOnPlay & DISABLE_ON_PLAY.DISABLE_ON_PLAY_VIDEO)) or (playingAudio and (self.m_disableOnPlay & DISABLE_ON_PLAY.DISABLE_ON_PLAY_MUSIC)): - if not self.m_bDimmedOnPlayback: - self.SetBackLight(0) - self.m_bDimmedOnPlayback = True - elif self.m_bDimmedOnPlayback: - self.SetBackLight(1) - self.m_bDimmedOnPlayback = False - diff --git a/script.xbmc.lcd/resources/lib/lcdproc.py b/script.xbmc.lcd/resources/lib/lcdproc.py deleted file mode 100644 index a11b0f75..00000000 --- a/script.xbmc.lcd/resources/lib/lcdproc.py +++ /dev/null @@ -1,362 +0,0 @@ -''' - LCD/VFD for XBMC - Copyright (C) 2011 Team XBMC - - 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. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -''' - -import platform -import xbmc -import xbmcgui -import sys -import os -import re -import telnetlib -import time - -from socket import * - -__scriptname__ = sys.modules[ "__main__" ].__scriptname__ -__settings__ = sys.modules[ "__main__" ].__settings__ -__cwd__ = sys.modules[ "__main__" ].__cwd__ -__icon__ = sys.modules[ "__main__" ].__icon__ - -from settings import * -from lcdbase import * - - -''' -def fhem_parseXML(xmlstr): - global g_fht_list - global g_fhttk_list - global g_fs20_list - - ret = True - fhemcontents = xmltree.fromstring(xmlstr) - for element in fhemcontents.getiterator(): - #PARSE FHT infos heating control - if element.tag == "FHT_LIST": - for child in element: - if child.tag == "FHT": - fhtobj = FHTObj() - fhtobj.name = child.attrib.get('name') - for subchild in child: - if subchild.tag == "ATTR" and subchild.attrib.get('key') == "room": - fhtobj.room = subchild.attrib.get('value') - if subchild.tag == "STATE" and subchild.attrib.get('key') == "measured-temp": - fhtobj.temperature = subchild.attrib.get('value') - if subchild.tag == "STATE" and subchild.attrib.get('key') == "actuator": - fhtobj.actuator = subchild.attrib.get('value') - if subchild.tag == "STATE" and subchild.attrib.get('key') == "battery": - fhtobj.battery = subchild.attrib.get('value') - if subchild.tag == "STATE" and subchild.attrib.get('key') == "mode": - fhtobj.mode = subchild.attrib.get('value') - if subchild.tag == "STATE" and subchild.attrib.get('key') == "desired-temp": - fhtobj.setTemp = subchild.attrib.get('value') - if subchild.tag == "STATE" and subchild.attrib.get('key') == "windowsensor": - fhtobj.windowSensor = subchild.attrib.get('value') - g_fht_list.append(fhtobj) - - #PARSE FHTTK infos window sensors - if element.tag == "CUL_FHTTK_LIST": - for child in element: - if child.tag == "CUL_FHTTK": - fhttkobj = FHTTKObj() - fhttkobj.name = child.attrib.get('name') - for subchild in child: - if subchild.tag == "ATTR" and subchild.attrib.get('key') == "room": - fhttkobj.room = subchild.attrib.get('value') - if subchild.tag == "STATE" and subchild.attrib.get('key') == "Battery": - fhttkobj.battery = subchild.attrib.get('value') - if subchild.tag == "STATE" and subchild.attrib.get('key') == "Window": - fhttkobj.window = subchild.attrib.get('value') - g_fhttk_list.append(fhttkobj) - - #PARSE FS20 infos switches - if element.tag == "FS20_LIST": - for child in element: - if child.tag == "FS20": - fs20obj = FS20Obj() - fs20obj.name = child.attrib.get('name') - for subchild in child: - if subchild.tag == "ATTR" and subchild.attrib.get('key') == "room": - fs20obj.room = subchild.attrib.get('value') - if subchild.tag == "STATE" and subchild.attrib.get('key') == "state": - fs20obj.state = subchild.attrib.get('value') - - g_fs20_list.append(fs20obj) - - return ret -''' - -def log(loglevel, msg): - xbmc.log("### [%s] - %s" % (__scriptname__,msg,),level=loglevel ) - -SCROLL_SPEED_IN_MSEC = 250 -MAX_ROWS = 20 -INIT_RETRY_INTERVAL = 2 -INIT_RETRY_INTERVAL_MAX = 60000 - -class LCDProc(LcdBase): - def __init__(self): - self.m_iActualpos = 0 - self.m_iBackLight = 32 - self.m_iLCDContrast = 50 - self.m_bStop = True - self.m_sockfd = -1 - self.m_lastInitAttempt = 0 - self.m_initRetryInterval = INIT_RETRY_INTERVAL - self.m_used = True - self.tn = telnetlib.Telnet() - self.m_strLine = [None]*MAX_ROWS - self.m_iProgressBarWidth = 0 - self.m_iProgressBarLine = -1 - LcdBase.__init__(self) - - def Initialize(self): - connected = False - if not self.m_used: - return False#nothing to do - - #don't try to initialize too often - now = time.time() - if (now - self.m_lastInitAttempt) < self.m_initRetryInterval: - return False - self.m_lastInitAttempt = now - - LcdBase.Initialize(self) - - if self.Connect(): - # reset the retry interval after a successful connect - self.m_initRetryInterval = INIT_RETRY_INTERVAL - self.m_bStop = False - connected = True - else: - self.CloseSocket() - - if not connected: - # give up after 60 seconds - if self.m_initRetryInterval > INIT_RETRY_INTERVAL_MAX: - self.m_used = False - log(xbmc.LOGERROR,"Connect failed. Giving up.") - else: - self.m_initRetryInterval = self.m_initRetryInterval * 2 - log(xbmc.LOGERROR,"Connect failed. Retry in %d seconds." % self.m_initRetryInterval) - - return connected - - def Connect(self): - self.CloseSocket() - - try: - ip = settings_getHostIp() - port = settings_getHostPort() - log(xbmc.LOGDEBUG,"Open " + str(ip) + ":" + str(port)) - - self.tn.open(ip, port) - # Start a new session - self.tn.write("hello\n") - # time.sleep(1) - # Receive LCDproc data to determine row and column information - reply = self.tn.read_until("\n",3) - log(xbmc.LOGDEBUG,"Reply: " + reply) - - if len(reply) < 5: - return False - - i = 0 - while (i < (len(reply)-5)) and reply[i:i+3] != "lcd" and (i+3) < len(reply): - i = i + 1 - - if i < len(reply): - tmparray = re.findall(r'\d+',reply[i:]) - if len(tmparray) >= 2: - self.m_iColumns = int(tmparray[0]) - self.m_iRows = int(tmparray[1]) - self.m_iCellWidth = int(tmparray[2]) - self.m_iCellHeight = int(tmparray[3]) - log(xbmc.LOGDEBUG, "LCDproc data: Columns %s - Rows %s - CellWidth %s." % (str(self.m_iColumns), str(self.m_iRows), str(self.m_iCellWidth))) - except: - log(xbmc.LOGERROR,"Connect: Telnet exception.") - return False - - # Build command to setup screen - cmd = "screen_add xbmc\n" - cmd += "screen_set xbmc -priority info\n" - if not settings_getHeartBeat(): - cmd += "screen_set xbmc -heartbeat off\n" - - cmd += self.GetWidgetsCmd() - - try: - #Send to server - self.tn.write(cmd) - self.tn.read_until("\n",3) - except: - log(xbmc.LOGERROR, "Connect: Telnet exception - send") - return False - - return True - - - def CloseSocket(self): - self.tn.close() - - def IsConnected(self): - if self.tn.get_socket() == None: - return False - - try: - self.tn.write("noop\n") - self.tn.read_until("\n",3) - except: - log(xbmc.LOGERROR, "Unable to write to socket - IsConnected") - self.CloseSocket() - return False - return True - - def GetWidgetsCmd(self): - cmd = "" - for i in range(1,int(self.m_iRows)+1): - cmd += "widget_add xbmc lineScroller" + str(i) + " scroller\n" - for i in range(1,int(self.m_iRows)+1): - cmd += "widget_add xbmc lineString" + str(i) + " string\n" -# for i in range(1,int(self.m_iRows)+1): -# cmd += "widget_add xbmc lineProgress" + str(i) + " hbar\n" - return cmd - - def SetBackLight(self, iLight): - if self.tn.get_socket() == None: - return - log(xbmc.LOGDEBUG, "Switch Backlight to: " + str(iLight)) - - # Build command - cmd = "" - if iLight == 0: - self.m_bStop = True - cmd += "screen_set xbmc -backlight off\n" - elif iLight > 0: - self.m_bStop = False - cmd += "screen_set xbmc -backlight on\n" - cmd += self.GetWidgetsCmd() - - # Send to server - try: - self.tn.write(cmd) - self.tn.read_until("\n",3) - except: - log(xbmc.LOGERROR, "Unable to write to socket - SetBackLight") - self.CloseSocket() - - def SetContrast(self, iContrast): - #TODO: Not sure if you can control contrast from client - return - - def Stop(self): - self.CloseSocket() - self.m_bStop = True - - def Suspend(self): - if self.m_bStop or self.tn.get_socket() == None: - return - - # Build command to suspend screen - cmd = "screen_set xbmc -priority hidden\n" - - # Send to server - try: - self.tn.write(cmd) - self.tn.read_until("\n",3) - except: - log(xbmc.LOGERROR, "Unable to write to socket - Suspend") - self.CloseSocket() - - def Resume(self): - if self.m_bStop or self.tn.get_socket() == None: - return - - # Build command to resume screen - cmd = "screen_set xbmc -priority info\n" - - # Send to server - try: - self.tn.write(cmd) - self.tn.read_until("\n",3) - except: - log(xbmc.LOGERROR, "Unable to write to socket - Resume") - self.CloseSocket() - - def GetColumns(self): - return int(self.m_iColumns) - - def SetProgressBar(self, percent, lineIdx): - iColumns = int(self.m_iColumns) - 2 # -2 because of [surroundings] - iNumHorPixels = int(self.m_iCellWidth) * int(iColumns) - self.m_iProgressBarWidth = int(float(percent) * iNumHorPixels) - self.m_iProgressBarLine = lineIdx - return self.m_iProgressBarWidth - - def GetRows(self): - return int(self.m_iRows) - - def SetLine(self, iLine, strLine, bForce): - if self.m_bStop or self.tn.get_socket() == None: - return - - if iLine < 0 or iLine >= int(self.m_iRows): - return - - strLineLong = strLine - strLineLong.strip() - - # make string fit the display if it's smaller than the width - if len(strLineLong) < int(self.m_iColumns): - numSpaces = int(self.m_iColumns) - len(strLineLong) - strLineLong.ljust(numSpaces) #pad with spaces - elif len(strLineLong) > int(self.m_iColumns): #else if the string doesn't fit the display, lcdproc will scroll it, so we need a space - strLineLong += " " - - if strLineLong != self.m_strLine[iLine] or bForce: - ln = iLine + 1 - cmd = "" - if int(self.m_iProgressBarLine) >= 0 and self.m_iProgressBarLine == iLine: - cmd = "widget_add xbmc lineProgress%i hbar\n" % (ln) - cmd += "widget_set xbmc lineProgress%i 2 %i %i\n" % (ln, ln, self.m_iProgressBarWidth) - if settings_getScrollDelay() != 0: - cmd += "widget_set xbmc lineScroller%i 1 %i %i %i m %i [\n" % (ln, ln, self.m_iColumns, ln, settings_getScrollDelay()) - cmd += "widget_add xbmc lineScroller2%i scroller\n" % (ln) - cmd += "widget_set xbmc lineScroller2%i %i %i %i %i m %i ]\n" % (ln, self.m_iColumns, ln, self.m_iColumns, ln, settings_getScrollDelay()) - else: - cmd += "widget_set xbmc lineString%i 1 %i [\n" % (ln, ln) - cmd += "widget_add xbmc lineString2%i string\n" % (ln) - cmd += "widget_set xbmc lineString2%i %i %i ]\n" % (ln, self.m_iColumns, ln) - elif settings_getScrollDelay() != 0: - cmd = "widget_del xbmc lineScroller2%i\n" % (ln) - cmd += "widget_del xbmc lineProgress%i\n" % (ln) - cmd += "widget_set xbmc lineScroller%i 1 %i %i %i m %i \"%s\"\n" % (ln, ln, int(self.m_iColumns), ln, settings_getScrollDelay(), strLineLong) - else: - cmd = "widget_del xbmc lineString2%i\n" % (ln) - cmd += "widget_del xbmc lineProgress%i\n" % (ln) - cmd += "widget_set xbmc lineString%i 1 %i \"%s\"\n" % (ln, ln, strLineLong) - - # Send to server - try: - self.tn.get_socket().send(cmd) #use the socket here for getting the special chars over the wire - self.tn.read_until("\n",3) - except: - log(xbmc.LOGERROR, "Unable to write to socket - SetLine") - self.CloseSocket() - - self.m_strLine[iLine] = strLineLong - diff --git a/script.xbmc.lcd/resources/lib/settings.py b/script.xbmc.lcd/resources/lib/settings.py deleted file mode 100644 index 2e26f279..00000000 --- a/script.xbmc.lcd/resources/lib/settings.py +++ /dev/null @@ -1,169 +0,0 @@ -''' - LCD/VFD for XBMC - Copyright (C) 2011 Team XBMC - - 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. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -''' - -import sys -import time -import xbmc -__scriptname__ = sys.modules[ "__main__" ].__scriptname__ -__settings__ = sys.modules[ "__main__" ].__settings__ -__cwd__ = sys.modules[ "__main__" ].__cwd__ -__icon__ = sys.modules[ "__main__" ].__icon__ -sys.path.append (__cwd__) - -from lcdbase import LCD_MODE - -#general -global g_hostip -global g_hostport -global g_timer -global g_heartbeat -global g_scrolldelay -global g_settingsChanged -global g_dimonscreensaver -global g_navtimeout - -#init globals with defaults -def settings_initGlobals(): - global g_hostip - global g_hostport - global g_timer - global g_heartbeat - global g_scrolldelay - global g_settingsChanged - global g_dimonscreensaver - global g_navtimeout - - - - g_hostip = "127.0.0.1" - g_hostport = 13666 - g_timer = time.time() - g_heartbeat = False - g_scrolldelay = 1 - g_settigsChanged = True - g_dimonscreensaver = False - g_navtimeout = 3 - - - -def settings_getHostIp(): - global g_hostip - return g_hostip - -def settings_getHostPort(): - global g_hostport - return g_hostport - -def settings_getHeartBeat(): - global g_heartbeat - return g_heartbeat - -def settings_getScrollDelay(): - global g_scrolldelay - return g_scrolldelay - -def settings_getDimOnScreensaver(): - global g_dimonscreensaver - return g_dimonscreensaver - -def settings_getNavTimeout(): - global g_navtimeout - return g_navtimeout - -#check for new settings and handle them if anything changed -#only checks if the last check is 5 secs old -#returns if a reconnect is needed due to settings change -def settings_checkForNewSettings(): -#todo for now impl. stat on addon.getAddonInfo('profile')/settings.xml and use mtime -#check for new settings every 5 secs - global g_timer - reconnect = False - - if time.time() - g_timer > 5: - reconnect = settings_setup() - g_timer = time.time() - return reconnect - -def settings_didSettingsChange(): - global g_settingsChanged - settingsChanged = g_settingsChanged - g_settingsChanged = False - return settingsChanged - -#handle all settings in the general tab according to network access -#returns true if reconnect is needed due to network changes -def settings_handleNetworkSettings(): - global g_hostip - global g_hostport - reconnect = False - - hostip = __settings__.getSetting("hostip") - hostport = g_hostport - - #server settings - #we need to reconnect if networkaccess bool changes - #or if network access is enabled and ip or port have changed - if g_hostip != hostip or g_hostport != hostport: - if g_hostip != hostip: - print "lcd: changed hostip to " + str(hostip) - g_hostip = hostip - - if g_hostport != hostport: - print "lcd: changed hostport to " + str(hostport) - g_hostport = hostport - reconnect = True - return reconnect - -def settings_handleLcdSettings(): - global g_scrolldelay - global g_heartbeat - global g_settingsChanged - global g_dimonscreensaver - global g_navtimeout - g_settingsChanged = False - - scrolldelay = int(float(__settings__.getSetting("scrolldelay"))) - heartbeat = __settings__.getSetting("heartbeat") == "true" - dimonscreensaver = __settings__.getSetting("dimonscreensver") == "true" - navtimeout = int(float(__settings__.getSetting("navtimeout"))) - - if g_scrolldelay != scrolldelay: - g_scrolldelay = scrolldelay - g_settingsChanged = True - - if g_heartbeat != heartbeat: - g_heartbeat = heartbeat - g_settingsChanged = True - - if g_dimonscreensaver != dimonscreensaver: - g_dimonscreensaver = dimonscreensaver - g_settingsChanged = True - - if g_navtimeout != navtimeout: - g_navtimeout = navtimeout - g_settingsChanged = True - -#handles all settings of boblight and applies them as needed -#returns if a reconnect is needed due to settings changes -def settings_setup(): - reconnect = False - reconnect = settings_handleNetworkSettings() - settings_handleLcdSettings() - - return reconnect - diff --git a/script.xbmc.lcd/resources/settings.xml b/script.xbmc.lcd/resources/settings.xml deleted file mode 100644 index 775e60f6..00000000 --- a/script.xbmc.lcd/resources/settings.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - -