Implemented video playback for questions
This commit is contained in:
parent
d7a2d8c56a
commit
09466d83a8
|
@ -40,6 +40,7 @@ five questions. A question can have the following keys:
|
||||||
- Answer (to remind you of the answer, not used in the program)
|
- Answer (to remind you of the answer, not used in the program)
|
||||||
- Type (type of question)
|
- Type (type of question)
|
||||||
- Double-Jeopardy (if the question is a Double-Jeopardy, default false)
|
- Double-Jeopardy (if the question is a Double-Jeopardy, default false)
|
||||||
|
- Audio (for videos, if the video should have audio or not, default false)
|
||||||
|
|
||||||
Four *Types* of question are supported:
|
Four *Types* of question are supported:
|
||||||
|
|
||||||
|
@ -48,6 +49,7 @@ Four *Types* of question are supported:
|
||||||
four spaces
|
four spaces
|
||||||
- Image: The Question key is a path to an image, which is displayed on screen
|
- Image: The Question key is a path to an image, which is displayed on screen
|
||||||
- Music: The Question key is a path to a music file, which is played
|
- Music: The Question key is a path to a music file, which is played
|
||||||
|
- Video: The Question key is a path to a video file, which is played
|
||||||
|
|
||||||
|
|
||||||
Gamestate
|
Gamestate
|
||||||
|
|
14
question.py
14
question.py
|
@ -10,8 +10,8 @@ class QuestionException(Exception):
|
||||||
class Questions(object):
|
class Questions(object):
|
||||||
""" Object holding all the questions """
|
""" Object holding all the questions """
|
||||||
|
|
||||||
QUESTION_TYPES = ["Text", "Image", "Music", "Code"]
|
QUESTION_TYPES = ["Text", "Image", "Music", "Code", "Video"]
|
||||||
QUESTION_KEYS = ["Name", "Question", "Answer", "Type", "Double-Jeopardy"]
|
QUESTION_KEYS = ["Name", "Question", "Answer", "Type", "Double-Jeopardy", "Audio"]
|
||||||
|
|
||||||
def __init__(self, qfile):
|
def __init__(self, qfile):
|
||||||
self.qfile = qfile
|
self.qfile = qfile
|
||||||
|
@ -72,18 +72,24 @@ class Questions(object):
|
||||||
if key not in self.QUESTION_KEYS:
|
if key not in self.QUESTION_KEYS:
|
||||||
raise QuestionException("Qestion %d from section %d (%s) has invalid keyword '%s'" % (j, i, sec["Section"], key))
|
raise QuestionException("Qestion %d from section %d (%s) has invalid keyword '%s'" % (j, i, sec["Section"], key))
|
||||||
|
|
||||||
# check Double-Jeopardy is a bool and is set to false it non-existant
|
# check Double-Jeopardy is a bool and is set to false if non-existant
|
||||||
if "Double-Jeopardy" not in q.keys():
|
if "Double-Jeopardy" not in q.keys():
|
||||||
q["Double-Jeopardy"] = False
|
q["Double-Jeopardy"] = False
|
||||||
elif type(q["Double-Jeopardy"]) != bool:
|
elif type(q["Double-Jeopardy"]) != bool:
|
||||||
raise QuestionException("The Double-Jeopardy key from question %d from section %d (%s) must be either true or false" % (j, i, sec["Section"]))
|
raise QuestionException("The Double-Jeopardy key from question %d from section %d (%s) must be either true or false" % (j, i, sec["Section"]))
|
||||||
|
|
||||||
|
# check Audio is a bool and is set to false if non-existant
|
||||||
|
if "Audio" not in q.keys():
|
||||||
|
q["Audio"] = False
|
||||||
|
elif type(q["Audio"]) != bool:
|
||||||
|
raise QuestionException("The Audio key from question %d from section %d (%s) must be either true or false" % (j, i, sec["Section"]))
|
||||||
|
|
||||||
# check for broken question types
|
# check for broken question types
|
||||||
if q["Type"] not in self.QUESTION_TYPES:
|
if q["Type"] not in self.QUESTION_TYPES:
|
||||||
raise QuestionException("Question %d from Section %d (%s) has an invalid type '%s' (valid types are %s)" % (j, i, sec["Section"], q["Type"], ", ".join(self.QUESTION_TYPES)))
|
raise QuestionException("Question %d from Section %d (%s) has an invalid type '%s' (valid types are %s)" % (j, i, sec["Section"], q["Type"], ", ".join(self.QUESTION_TYPES)))
|
||||||
|
|
||||||
# check if file for music/image questions exist
|
# check if file for music/image questions exist
|
||||||
if q["Type"] in ("Music", "Image"):
|
if q["Type"] in ("Music", "Image", "Video"):
|
||||||
if not os.path.isfile(q["Question"]):
|
if not os.path.isfile(q["Question"]):
|
||||||
raise QuestionException("File for question %d, section %d (%s) not found" % (j, i, sec["Section"]))
|
raise QuestionException("File for question %d, section %d (%s) not found" % (j, i, sec["Section"]))
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
|
from PySide import phonon
|
||||||
|
|
||||||
|
class VideoPlayer(object):
|
||||||
|
def __init__(self, video, audio=False):
|
||||||
|
self._videoFile = video
|
||||||
|
self._audio = audio
|
||||||
|
|
||||||
|
self._widget = None
|
||||||
|
self._media_obj = phonon.Phonon.MediaObject()
|
||||||
|
self._media_src = phonon.Phonon.MediaSource(self._videoFile)
|
||||||
|
|
||||||
|
self._audio_out = None
|
||||||
|
|
||||||
|
# setup media object
|
||||||
|
self._media_obj.setCurrentSource(self._media_src)
|
||||||
|
# make media object loop
|
||||||
|
self._media_obj.finished.connect(lambda: self._media_obj.play())
|
||||||
|
|
||||||
|
if self._audio:
|
||||||
|
self._audio_out = phonon.Phonon.AudioOutput(phonon.Phonon.VideoCategory)
|
||||||
|
phonon.Phonon.createPath(self._media_obj, self._audio_out)
|
||||||
|
|
||||||
|
def get_widget(self):
|
||||||
|
if self._widget == None:
|
||||||
|
self._widget = phonon.Phonon.VideoWidget()
|
||||||
|
self._widget.setScaleMode(phonon.Phonon.VideoWidget.ScaleAndCrop)
|
||||||
|
|
||||||
|
phonon.Phonon.createPath(self._media_obj, self._widget)
|
||||||
|
|
||||||
|
return self._widget
|
||||||
|
|
||||||
|
def play(self):
|
||||||
|
self._media_obj.play()
|
||||||
|
|
||||||
|
def pause(self):
|
||||||
|
self._media_obj.pause()
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self._media_obj.stop()
|
||||||
|
|
26
windows.py
26
windows.py
|
@ -4,6 +4,7 @@ import copy
|
||||||
|
|
||||||
from gamestate import QuestionAnswers
|
from gamestate import QuestionAnswers
|
||||||
from music import MusicBox
|
from music import MusicBox
|
||||||
|
from video import VideoPlayer
|
||||||
from player import Player, ButtonEvent, nobodyColor
|
from player import Player, ButtonEvent, nobodyColor
|
||||||
|
|
||||||
class QuestionWindow(QtGui.QDialog):
|
class QuestionWindow(QtGui.QDialog):
|
||||||
|
@ -20,6 +21,7 @@ class QuestionWindow(QtGui.QDialog):
|
||||||
self.dj = dj
|
self.dj = dj
|
||||||
|
|
||||||
self._windowSetup = False
|
self._windowSetup = False
|
||||||
|
self._videoPlayer = None
|
||||||
|
|
||||||
if answers is not None:
|
if answers is not None:
|
||||||
self.answers = answers
|
self.answers = answers
|
||||||
|
@ -27,7 +29,7 @@ class QuestionWindow(QtGui.QDialog):
|
||||||
self.answers = QuestionAnswers(self.section, self.qnumber)
|
self.answers = QuestionAnswers(self.section, self.qnumber)
|
||||||
|
|
||||||
if not self.answers.is_answered():
|
if not self.answers.is_answered():
|
||||||
if self.question["Type"] != "Music":
|
if not self._question_has_audio():
|
||||||
MusicBox.play_music("questionSong")
|
MusicBox.play_music("questionSong")
|
||||||
|
|
||||||
if self.dj:
|
if self.dj:
|
||||||
|
@ -43,6 +45,8 @@ class QuestionWindow(QtGui.QDialog):
|
||||||
tag = "%s-%s" % (self.section, self.qnumber)
|
tag = "%s-%s" % (self.section, self.qnumber)
|
||||||
MusicBox.add_music(tag, self.question["Question"])
|
MusicBox.add_music(tag, self.question["Question"])
|
||||||
MusicBox.play_music(tag)
|
MusicBox.play_music(tag)
|
||||||
|
elif self.question["Type"] == "Video":
|
||||||
|
self._videoPlayer.play()
|
||||||
|
|
||||||
def get_answers(self):
|
def get_answers(self):
|
||||||
return self.answers
|
return self.answers
|
||||||
|
@ -51,6 +55,8 @@ class QuestionWindow(QtGui.QDialog):
|
||||||
if not self._inWindow:
|
if not self._inWindow:
|
||||||
self.buzzersOpen.emit(False)
|
self.buzzersOpen.emit(False)
|
||||||
MusicBox.stop_music()
|
MusicBox.stop_music()
|
||||||
|
if self._videoPlayer:
|
||||||
|
self._videoPlayer.stop()
|
||||||
event.accept()
|
event.accept()
|
||||||
else:
|
else:
|
||||||
event.ignore()
|
event.ignore()
|
||||||
|
@ -74,6 +80,7 @@ class QuestionWindow(QtGui.QDialog):
|
||||||
self.layout.addStretch()
|
self.layout.addStretch()
|
||||||
|
|
||||||
qlabel = None
|
qlabel = None
|
||||||
|
stretch = 0
|
||||||
if self.question["Type"] == "Text":
|
if self.question["Type"] == "Text":
|
||||||
qlabel = self._mkQuestionLabel(self.question["Question"])
|
qlabel = self._mkQuestionLabel(self.question["Question"])
|
||||||
elif self.question["Type"] == "Music":
|
elif self.question["Type"] == "Music":
|
||||||
|
@ -92,10 +99,15 @@ class QuestionWindow(QtGui.QDialog):
|
||||||
code = map(lambda x: x + ((maxLineLen-len(x))*" "), code)
|
code = map(lambda x: x + ((maxLineLen-len(x))*" "), code)
|
||||||
|
|
||||||
qlabel = self._mkQuestionLabel("<pre>"+"\n".join(code)+"</pre>", monospaced=True)
|
qlabel = self._mkQuestionLabel("<pre>"+"\n".join(code)+"</pre>", monospaced=True)
|
||||||
|
elif self.question["Type"] == "Video":
|
||||||
|
self._videoPlayer = VideoPlayer(self.question["Question"], self.question["Audio"])
|
||||||
|
qlabel = self._videoPlayer.get_widget()
|
||||||
|
stretch = 1
|
||||||
else:
|
else:
|
||||||
raise ValueError("%s is an unknown type for section %s question name %s" % (self.question["Type"], self.section, self.question["Name"]))
|
raise ValueError("%s is an unknown type for section %s question name %s" % (self.question["Type"], self.section, self.question["Name"]))
|
||||||
|
|
||||||
self.layout.addWidget(qlabel)
|
self.layout.addWidget(qlabel, stretch=stretch)
|
||||||
|
|
||||||
self.layout.addStretch()
|
self.layout.addStretch()
|
||||||
|
|
||||||
self.setLayout(self.layout)
|
self.setLayout(self.layout)
|
||||||
|
@ -106,6 +118,8 @@ class QuestionWindow(QtGui.QDialog):
|
||||||
done = False
|
done = False
|
||||||
if self.question["Type"] == "Music":
|
if self.question["Type"] == "Music":
|
||||||
MusicBox.stop_music()
|
MusicBox.stop_music()
|
||||||
|
elif self.question["Type"] == "Video":
|
||||||
|
self._videoPlayer.pause()
|
||||||
|
|
||||||
self._inWindow = True
|
self._inWindow = True
|
||||||
player = self.players[e.get_playerno()-1]
|
player = self.players[e.get_playerno()-1]
|
||||||
|
@ -124,8 +138,11 @@ class QuestionWindow(QtGui.QDialog):
|
||||||
if not done:
|
if not done:
|
||||||
self.buzzersOpen.emit(True)
|
self.buzzersOpen.emit(True)
|
||||||
if self.question["Type"] == "Music":
|
if self.question["Type"] == "Music":
|
||||||
# restart music if question was not answered
|
# resume music if question was not answered
|
||||||
MusicBox.play_music("%s-%s" % (self.section, self.qnumber))
|
MusicBox.play_music("%s-%s" % (self.section, self.qnumber))
|
||||||
|
elif self.question["Type"] == "Video":
|
||||||
|
# resume video if question was not answered
|
||||||
|
self._videoPlayer.play()
|
||||||
|
|
||||||
elif e.get_playerno() > len(self.players) and not self._inWindow:
|
elif e.get_playerno() > len(self.players) and not self._inWindow:
|
||||||
# unknown player! to not confuse certain devices we send a buttons open event
|
# unknown player! to not confuse certain devices we send a buttons open event
|
||||||
|
@ -158,6 +175,8 @@ class QuestionWindow(QtGui.QDialog):
|
||||||
def playerButtonPress(self, no):
|
def playerButtonPress(self, no):
|
||||||
QtCore.QCoreApplication.postEvent(self, ButtonEvent(int(no)))
|
QtCore.QCoreApplication.postEvent(self, ButtonEvent(int(no)))
|
||||||
|
|
||||||
|
def _question_has_audio(self):
|
||||||
|
return self.question["Type"] == "Music" or (self.question["Type"] == "Video" and self.question["Audio"])
|
||||||
|
|
||||||
class QuestionAnswerWindow(QtGui.QDialog):
|
class QuestionAnswerWindow(QtGui.QDialog):
|
||||||
CORRECT = 1
|
CORRECT = 1
|
||||||
|
@ -413,7 +432,6 @@ class PlayerStartWindow(QtGui.QDialog):
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def closeEvent(self, event):
|
def closeEvent(self, event):
|
||||||
MusicBox.stop_music()
|
MusicBox.stop_music()
|
||||||
self.buzzersOpen.emit(False)
|
self.buzzersOpen.emit(False)
|
||||||
|
|
Loading…
Reference in New Issue