You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

183 lines
5.0 KiB

#!/usr/bin/python3
import threading
import os
import os.path
import random
import time
import sys
import getopt
import blup.output
import blup.animation
import blup.frame
class AnimationLoaderThread(threading.Thread):
"""
This class is used by the player to pre-load an animation while another one
is being played.
"""
def __init__(self, filename):
threading.Thread.__init__(self)
self.__filename = filename
self.__anim = None
self.__error = False
def run(self):
try:
self.__anim = blup.animation.load(self.__filename)
except Exception as e:
print('%s: %s while loading %s' % (self.__class__.__name__,
repr(e), self.__filename))
self.__error = True
self.__anim = None
def getAnim(self):
self.join()
return self.__anim
class MiniPlayer(object):
"""
Minimal animation player that does nothing but randomly selecting
animations out of a directory and playing them.
"""
def __init__(self, animDir, output):
self.__animDir = animDir
self.__output = output
self.loopTime = 10000
self.gap = 800
self.maxPlayNext = 3
self.__playNext = []
self.__running = False
def terminate(self):
self.__running = False
def playNext(self, filename):
""" Add an animation to the queue. """
if filename.find('/') >= 0:
raise ValueError('filename must not contain slashes')
if ( os.path.isfile(os.path.join(self.__animDir, filename)) and
len(self.__playNext) < self.maxPlayNext ):
self.__playNext.append(filename)
else:
return False
def getNextFilename(self):
"""
Return the next animation filename to be played, either from the queue,
or randomly chosen.
"""
if len(self.__playNext) > 0 and os.path.isfile(self.__playNext[0]):
return self.__playNext.pop(0)
else:
files = os.listdir(self.__animDir)
return random.choice(files)
def run(self):
"""
Runs the player until terminate() gets called (e.g. by another thread).
"""
self.__running = True
currentAnim = None
player = blup.animation.AnimationPlayer()
while self.__running:
# begin to load the next animation
filename = os.path.join(self.__animDir, self.getNextFilename())
loader = AnimationLoaderThread(filename)
loader.start()
# play the animation in case it had been successfully loaded before
if currentAnim is not None:
if currentAnim.duration < self.loopTime:
count = self.loopTime // currentAnim.duration
else:
count = 1
player.play(currentAnim, self.__output, count=count)
# show a blank frame for some thime
if self.gap > 0 and self.__running:
# TODO: use correct frame size
#dim = blup.frame.FrameDimension(18,8,8,3)
dim = blup.frame.FrameDimension(22, 16, 256, 3)
self.__output.sendFrame(blup.frame.Frame(dim))
time.sleep(self.gap / 1000.0)
# get the next animation from the loader
currentAnim = loader.getAnim()
def printUsage(errMsg=None):
if errMsg is not None:
print('error: %s\n' % (errMsg))
print('usage: %s [OPTIONS] PATH' % (sys.argv[0]))
print('where PATH is the directory containing the animations to play')
print('supported options:')
print(' -o OUTPUT where to output the frames (default: shell)')
print(' --output OUTPUT\n')
print(' -h print(this text')
print(' --help')
def main():
try:
(opts, args) = getopt.gnu_getopt(sys.argv, 'ho:', ['help', 'output='])
opts = dict(opts)
except getopt.GetoptError as e:
printUsage(e.msg)
sys.exit(1)
if '--help' in opts:
printUsage()
sys.exit(0)
if '-o' in opts:
output = opts['-o']
elif '--output' in opts:
output = opts['--output']
else:
output = 'shell'
try:
out = blup.output.getOutput(output)
except blup.output.IllegalOutputSpecificationError:
print('illegal output specification')
print('available outputs:')
print(blup.output.getOutputDescriptions())
sys.exit(1)
except Exception as e:
print('could not initialize output: %s' % (str(e)))
sys.exit(1)
if len(args) != 2:
printUsage()
sys.exit(1)
else:
animDir = args[1]
if not os.path.isdir(animDir):
print('%s is not a directory' % (animDir))
sys.exit(1)
p = MiniPlayer(animDir, out)
try:
p.run()
except KeyboardInterrupt:
sys.exit(0)
if __name__ == '__main__':
main()