Skip to content

Instantly share code, notes, and snippets.

@MilhouseVH
Last active June 22, 2017 06:08
Show Gist options
  • Save MilhouseVH/9fc2ed4cbf0e0efaf4adee04bbd1c834 to your computer and use it in GitHub Desktop.
Save MilhouseVH/9fc2ed4cbf0e0efaf4adee04bbd1c834 to your computer and use it in GitHub Desktop.
################################################################################
# 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 PNGPlayer(threading.Thread):
def __init__(self, patterns, responses):
threading.Thread.__init__(self)
self.patterns = patterns
self.responses = responses
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 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, *args, **kwargs):
xbmc.Player.__init__(self)
self.patterns = Queue.Queue()
self.responses = Queue.Queue()
self.thread = PNGPlayer(self.patterns, self.responses)
self.thread.start()
'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.startPattern('startup', False, 0.02)
def startPattern(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 finishPattern(wait=None):
self.startPattern(None, wait=wait)
def onPlayBackEnded(self):
'Will be called when Kodi stops playing a file'
self.startPattern('stop')
def onPlayBackPaused(self):
'Will be called when user pauses a playing file'
self.startPattern('pause')
def onPlayBackResumed(self):
'Will be called when user resumes a paused file'
self.startPattern('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.startPattern('skipf')
else:
self.startPattern('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.startPattern('ffwd' if self.speed > 0 else 'rew', True, self.speed_map[self.speed])
else:
self.finishPattern()
#OR: self.startPattern('play') ???
def onPlayBackStarted(self):
'Will be called when Kodi starts playing a file'
self.startPattern('play')
def onPlayBackStopped(self):
'Will be called when user stops Kodi playing a file'
self.startPattern('stop')
class SliceMonitor(xbmc.Monitor):
def __init__(self, player):
xbmc.Monitor.__init__(self)
self.player = player
def onScreensaverActivated(self):
'Will be called when screensaver kicks in'
self.player.startPattern('sleep')
def onScreensaverDeactivated(self):
'Will be called when screensaver goes off'
self.player.startPattern('wake')
def onSettingsChanged(self):
'Will be called when addon settings are changed'
# meh
if (__name__ == "__main__"):
player = SlicePlayer()
monitor = SliceMonitor(player)
while not monitor.abortRequested():
if monitor.waitForAbort():
player.startPattern('shutdown', wait=5.0)
del SlicePlayer
del SliceMonitor
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment