2016-09-12 11:05:34 +02:00
|
|
|
import uuid
|
|
|
|
|
2015-02-18 01:45:39 +01:00
|
|
|
from django.utils.timezone import now
|
|
|
|
|
2016-09-17 22:26:23 +02:00
|
|
|
from ..utils.projector import ProjectorElement
|
2015-09-05 14:58:10 +02:00
|
|
|
from .config import config
|
2015-02-18 01:45:39 +01:00
|
|
|
from .exceptions import ProjectorException
|
2016-09-18 22:14:24 +02:00
|
|
|
from .models import Projector
|
2015-06-12 21:08:57 +02:00
|
|
|
|
2015-02-18 01:45:39 +01:00
|
|
|
|
|
|
|
class Clock(ProjectorElement):
|
|
|
|
"""
|
|
|
|
Clock on the projector.
|
|
|
|
"""
|
|
|
|
name = 'core/clock'
|
|
|
|
|
|
|
|
|
|
|
|
class Countdown(ProjectorElement):
|
|
|
|
"""
|
|
|
|
Countdown on the projector.
|
|
|
|
|
|
|
|
To start the countdown write into the config field:
|
|
|
|
|
|
|
|
{
|
2016-09-12 11:05:34 +02:00
|
|
|
"running": True,
|
2015-02-18 01:45:39 +01:00
|
|
|
"countdown_time": <timestamp>,
|
|
|
|
}
|
|
|
|
|
2015-09-14 23:16:31 +02:00
|
|
|
The timestamp is a POSIX timestamp (seconds) calculated from client
|
2015-02-18 01:45:39 +01:00
|
|
|
time, server time offset and countdown duration (countdown_time = now -
|
|
|
|
serverTimeOffset + duration).
|
|
|
|
|
2015-09-05 14:58:10 +02:00
|
|
|
To stop the countdown set the countdown time to the current value of the
|
2015-02-18 01:45:39 +01:00
|
|
|
countdown (countdown_time = countdown_time - now + serverTimeOffset)
|
2016-09-12 11:05:34 +02:00
|
|
|
and set running to False.
|
2015-02-18 01:45:39 +01:00
|
|
|
|
|
|
|
To reset the countdown (it is not a reset in a functional way) just
|
2016-09-12 11:05:34 +02:00
|
|
|
change the countdown time. The running value remains False.
|
2015-02-18 01:45:39 +01:00
|
|
|
|
2015-09-14 23:16:31 +02:00
|
|
|
Do not forget to send values for additional keywords like "stable" if
|
|
|
|
you do not want to use the default.
|
2015-09-05 14:58:10 +02:00
|
|
|
|
2015-09-14 23:16:31 +02:00
|
|
|
The countdown backend supports an extra keyword "default".
|
|
|
|
|
|
|
|
{
|
|
|
|
"default": <seconds>
|
|
|
|
}
|
|
|
|
|
|
|
|
This is used for the internal reset method if the countdown is coupled
|
|
|
|
with the list of speakers. The default of this default value can be
|
|
|
|
customized in OpenSlides config 'projector_default_countdown'.
|
|
|
|
|
|
|
|
Use additional keywords to control view behavior like "visable" and
|
|
|
|
"label". These keywords are not handles by the backend.
|
2015-02-18 01:45:39 +01:00
|
|
|
"""
|
|
|
|
name = 'core/countdown'
|
|
|
|
|
2016-02-27 20:25:06 +01:00
|
|
|
def check_data(self):
|
2015-09-05 14:58:10 +02:00
|
|
|
self.validate_config(self.config_entry)
|
2015-02-18 01:45:39 +01:00
|
|
|
|
2015-09-05 14:58:10 +02:00
|
|
|
@classmethod
|
|
|
|
def validate_config(cls, config_data):
|
|
|
|
"""
|
|
|
|
Raises ProjectorException if the given data are invalid.
|
|
|
|
"""
|
|
|
|
if not isinstance(config_data.get('countdown_time'), (int, float)):
|
2015-11-21 00:00:31 +01:00
|
|
|
raise ProjectorException('Invalid countdown time. Use integer or float.')
|
2016-09-12 11:05:34 +02:00
|
|
|
if not isinstance(config_data.get('running'), bool):
|
|
|
|
raise ProjectorException("Invalid running status. Has to be a boolean.")
|
2015-09-05 14:58:10 +02:00
|
|
|
if config_data.get('default') is not None and not isinstance(config_data.get('default'), int):
|
2015-11-21 00:00:31 +01:00
|
|
|
raise ProjectorException('Invalid default value. Use integer.')
|
2015-09-05 14:58:10 +02:00
|
|
|
|
|
|
|
@classmethod
|
2016-09-12 11:05:34 +02:00
|
|
|
def control(cls, action):
|
2015-09-05 14:58:10 +02:00
|
|
|
if action not in ('start', 'stop', 'reset'):
|
2016-09-12 11:05:34 +02:00
|
|
|
raise ValueError("Action must be 'start', 'stop' or 'reset', not {}.".format(action))
|
|
|
|
|
|
|
|
# Use the countdown with the lowest index
|
|
|
|
projectors = Projector.objects.all()
|
|
|
|
lowest_index = None
|
|
|
|
if projectors[0]:
|
|
|
|
for key, value in projectors[0].config.items():
|
|
|
|
if value['name'] == cls.name:
|
|
|
|
if lowest_index is None or value['index'] < lowest_index:
|
|
|
|
lowest_index = value['index']
|
|
|
|
|
|
|
|
if lowest_index is None:
|
|
|
|
# create a countdown
|
|
|
|
for projector in projectors:
|
|
|
|
projector_config = {}
|
|
|
|
for key, value in projector.config.items():
|
|
|
|
projector_config[key] = value
|
|
|
|
# new countdown
|
|
|
|
countdown = {
|
|
|
|
'name': 'core/countdown',
|
|
|
|
'stable': True,
|
|
|
|
'index': 1,
|
|
|
|
'default_time': config['projector_default_countdown'],
|
|
|
|
'visible': False,
|
|
|
|
'selected': True,
|
|
|
|
}
|
|
|
|
if action == 'start':
|
|
|
|
countdown['running'] = True
|
|
|
|
countdown['countdown_time'] = now().timestamp() + countdown['default_time']
|
|
|
|
elif action == 'reset' or action == 'stop':
|
|
|
|
countdown['running'] = False
|
|
|
|
countdown['countdown_time'] = countdown['default_time']
|
|
|
|
projector_config[uuid.uuid4().hex] = countdown
|
|
|
|
projector.config = projector_config
|
|
|
|
projector.save()
|
|
|
|
else:
|
|
|
|
# search for the countdown and modify it.
|
|
|
|
for projector in projectors:
|
|
|
|
projector_config = {}
|
|
|
|
found = False
|
|
|
|
for key, value in projector.config.items():
|
|
|
|
if value['name'] == cls.name and value['index'] == lowest_index:
|
|
|
|
try:
|
|
|
|
cls.validate_config(value)
|
|
|
|
except ProjectorException:
|
|
|
|
# Do not proceed if the specific procjector config data is invalid.
|
|
|
|
# The variable found remains False.
|
|
|
|
break
|
|
|
|
found = True
|
|
|
|
if action == 'start':
|
|
|
|
value['running'] = True
|
|
|
|
value['countdown_time'] = now().timestamp() + value['default_time']
|
|
|
|
elif action == 'stop' and value['running']:
|
|
|
|
value['running'] = False
|
|
|
|
value['countdown_time'] = value['countdown_time'] - now().timestamp()
|
|
|
|
elif action == 'reset':
|
|
|
|
value['running'] = False
|
|
|
|
value['countdown_time'] = value['default_time']
|
|
|
|
projector_config[key] = value
|
|
|
|
if found:
|
|
|
|
projector.config = projector_config
|
|
|
|
projector.save()
|
2015-09-05 14:58:10 +02:00
|
|
|
|
2015-02-18 01:45:39 +01:00
|
|
|
|
|
|
|
class Message(ProjectorElement):
|
|
|
|
"""
|
|
|
|
Short message on the projector. Rendered as overlay.
|
|
|
|
"""
|
|
|
|
name = 'core/message'
|
|
|
|
|
2016-02-27 20:25:06 +01:00
|
|
|
def check_data(self):
|
2015-02-18 01:45:39 +01:00
|
|
|
if self.config_entry.get('message') is None:
|
2015-11-21 00:00:31 +01:00
|
|
|
raise ProjectorException('No message given.')
|