|
|
|
#!/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()
|
|
|
|
|