Last active
June 22, 2017 06:07
-
-
Save MilhouseVH/e684c41aa65881ffdc3a32451a44bd17 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
################################################################################ | |
# This file is part of LibreELEC - https://libreelec.tv | |
# Copyright (C) 2016-present Team LibreELEC | |
# | |
# LibreELEC 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. | |
# | |
# LibreELEC 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 LibreELEC. If not, see <http://www.gnu.org/licenses/>. | |
################################################################################ | |
from PIL import Image | |
import os | |
import threading | |
import time | |
import xbmc | |
''' | |
ffwd.png | |
pause.png | |
play.png | |
quit.png | |
rew.png | |
shutdown.png | |
skipf.png | |
skipr.png | |
sleep.png | |
startup.png | |
stop.png | |
wake.png | |
''' | |
class PNGPatternPlayer(threading.Thread): | |
def __init__(self): | |
threading.Thread.__init__(self) | |
self.patterns = Queue.Queue() | |
self.responses = Queue.Queue() | |
self.start() | |
def clearPattern(self): | |
with open('/dev/ws2812', 'wb') as f: | |
f.write(bytearray(25)) | |
def playPattern(self, pixels, width, height, delay): | |
xbmc.log('playing pattern', xbmc.LOGNOTICE) | |
#xbmc.log('width: %d' % self.width, xbmc.LOGNOTICE) | |
#xbmc.log('height: %d' % self.height, xbmc.LOGNOTICE) | |
for y in range(height): | |
x_pixels = [] | |
for x in range(width): | |
pixel = [] | |
r, g, b, a = pixels[x, y] | |
pixel.append(hex(r)[2:].zfill(2)) | |
pixel.append(hex(g)[2:].zfill(2)) | |
pixel.append(hex(b)[2:].zfill(2)) | |
pixel.append(hex(a)[2:].zfill(2)) | |
x_pixels.append(''.join(str(e) for e in pixel)) | |
hex_str = ' '.join(str(e) for e in x_pixels) | |
with open('/dev/ws2812', 'wb') as f: | |
f.write(bytearray.fromhex(hex_str)) | |
time.sleep(delay) | |
def play(self, file, repeat=False, delay=0.030, wait=None): | |
if wait is not None: | |
# wait up to specified time if this pattern is to be processed synchronously | |
self.patterns.put((file, repeat, delay, True)) | |
try: | |
result = self.responses.get(block=True, timeout=wait) | |
except Queue.Empty: | |
pass | |
else: | |
self.patterns.put((file, repeat, delay, False)) | |
def stop(wait=None): | |
self.play(None, wait=wait) | |
def run(self): | |
repeat = False | |
while True: | |
try: | |
(file, repeat, delay, wait) = self.patterns.get(block=True, timeout=0 if repeat else None) | |
if file is not None: | |
xbmc.log('playing: /usr/share/kodi/media/ledpatterns/%s.png' % file, xbmc.LOGNOTICE) | |
image = Image.open('/usr/share/kodi/media/ledpatterns/%s.png' % file) | |
pixels = image.load() | |
width, height = image.size | |
self.playPattern(pixels, width, height, delay) | |
else: | |
self.clearPattern() | |
if wait: | |
self.responses.put(True) | |
# Queue will be empty if we're repeating the last pattern and there is no new work | |
except Queue.Empty: | |
self.playPattern(pixels, width, height, delay) | |
class SlicePlayer(xbmc.Player): | |
def __init__(self, patterns): | |
xbmc.Player.__init__(self) | |
self.patterns = patterns | |
'maps kodi player speed to delay in seconds' | |
self.speed_map = { 1: 0.060, | |
2: 0.040, | |
4: 0.035, | |
8: 0.030, | |
16: 0.025, | |
32: 0.015, | |
} | |
self.speed = 1 | |
self.patterns.start('startup', False, 0.02) | |
def onPlayBackEnded(self): | |
'Will be called when Kodi stops playing a file' | |
self.patterns.play('stop') | |
def onPlayBackPaused(self): | |
'Will be called when user pauses a playing file' | |
self.patterns.play('pause') | |
def onPlayBackResumed(self): | |
'Will be called when user resumes a paused file' | |
self.patterns.play('play') | |
def onPlayBackSeek(self, iTime, seekOffset): | |
'Will be called when user seeks to a time' | |
# todo: not working | |
xbmc.log('time offset: %d' % iTime, xbmc.LOGNOTICE) | |
xbmc.log('seek offset: %d' % seekOffset, xbmc.LOGNOTICE) | |
if seekOffset > 0: | |
self.patterns.play('skipf') | |
else: | |
self.patterns.play('skipr') | |
def onPlayBackSeekChapter(self, chapter): | |
'Will be called when user performs a chapter seek' | |
pass | |
def onPlayBackSpeedChanged(self, speed): | |
'Will be called when players speed changes. (eg. user FF/RW)' | |
xbmc.log('seek speed: %d' % speed, xbmc.LOGNOTICE) | |
self.speed = speed | |
if self.speed != 1: | |
self.patterns.play('ffwd' if self.speed > 0 else 'rew', True, self.speed_map[self.speed]) | |
else: | |
self.patterns.stop() | |
#OR: self.startPattern('play') ??? | |
def onPlayBackStarted(self): | |
'Will be called when Kodi starts playing a file' | |
self.patterns.play('play') | |
def onPlayBackStopped(self): | |
'Will be called when user stops Kodi playing a file' | |
self.patterns.play('stop') | |
class SliceMonitor(xbmc.Monitor): | |
def __init__(self,patterns, player): | |
xbmc.Monitor.__init__(self) | |
self.patterns = patterns | |
self.player = player | |
def onScreensaverActivated(self): | |
'Will be called when screensaver kicks in' | |
self.patterns.play('sleep') | |
def onScreensaverDeactivated(self): | |
'Will be called when screensaver goes off' | |
self.patterns.play('wake') | |
def onSettingsChanged(self): | |
'Will be called when addon settings are changed' | |
# meh | |
if (__name__ == "__main__"): | |
patterns = PNGPatternPlayer() | |
player = SlicePlayer(patterns) | |
monitor = SliceMonitor(patterns, player) | |
while not monitor.abortRequested(): | |
if monitor.waitForAbort(): | |
patterns.play('shutdown', wait=5.0) | |
del SliceMonitor | |
del SlicePlayer | |
del PNGPatternPlayer |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment