1
0
Fork 0
mirror of https://github.com/Kunsi/pretalx-plugin-broadcast-tools synced 2025-04-28 22:50:59 +00:00

rename plugin to 'pretalx_broadcast_tools'

This commit is contained in:
Franzi 2021-11-22 12:09:01 +01:00
parent 7c5e58023c
commit 213db3f640
Signed by: kunsi
GPG key ID: 12E3D2136B818350
17 changed files with 81 additions and 82 deletions

View file

@ -0,0 +1,21 @@
from django.apps import AppConfig
from django.utils.translation import gettext_lazy
class PluginApp(AppConfig):
name = "pretalx_broadcast_tools"
verbose_name = "Broadcasting Tools"
class PretalxPluginMeta:
name = gettext_lazy("Broadcasting Tools")
author = "kunsi"
description = gettext_lazy(
"Some tools which can be used for supporting a broadcasting "
"software, for example a 'lower third' page which can be "
"embedded into your broadcasting software"
)
visible = True
version = "0.1.2"
def ready(self):
from . import signals # NOQA

View file

@ -0,0 +1,20 @@
from django.utils.translation import gettext_lazy as _
from hierarkey.forms import HierarkeyForm
from i18nfield.forms import I18nFormField, I18nFormMixin, I18nTextInput
class BroadcastToolsSettingsForm(I18nFormMixin, HierarkeyForm):
lower_thirds_no_talk_info = I18nFormField(
help_text=_(
"Will be shown as talk title if there's currently no talk running."
),
label=_('"no talk running" information'),
widget=I18nTextInput,
required=True,
)
lower_thirds_info_string = I18nFormField(
help_text=_("Will only be shown if there's a talk running."),
label=_("info line"),
required=False,
widget=I18nTextInput,
)

View file

@ -0,0 +1,36 @@
from django.dispatch import receiver
from django.urls import resolve, reverse
from django.utils.translation import gettext_noop
from django.utils.translation import ugettext_lazy as _
from i18nfield.strings import LazyI18nString
from pretalx.common.models.settings import hierarkey
from pretalx.orga.signals import nav_event_settings
hierarkey.add_default(
"lower_thirds_no_talk_info",
LazyI18nString.from_gettext(
gettext_noop("Sorry, there's currently no talk running")
),
LazyI18nString,
)
hierarkey.add_default("lower_thirds_info_string", "", LazyI18nString)
@receiver(nav_event_settings)
def navbar_info(sender, request, **kwargs):
url = resolve(request.path_info)
if not request.user.has_perm("orga.change_settings", request.event):
return []
return [
{
"label": _("lower thirds"),
"url": reverse(
"plugins:pretalx_broadcast_tools:orga",
kwargs={
"event": request.event.slug,
},
),
"active": url.namespace == "plugins:pretalx_broadcast_tools"
and url.url_name == "orga",
}
]

View file

@ -0,0 +1,36 @@
* {
margin: 0;
padding: 0;
line-height: 1.2em;
}
#box {
width: 1020px;
position: absolute;
bottom: 80px;
left: 50%;
margin-left: -510px;
color: white;
font-family: "Muli","Open Sans","OpenSans","Helvetica Neue",Helvetica,Arial,sans-serif;
padding: 15px;
box-shadow: 5px 5px 10px 0px rgba(50, 50, 50, 0.75);
background-color: #3aa57c;
}
#title {
font-size: 30px;
font-weight: 500;
margin-bottom: 15px;
}
#speaker {
font-size: 20px;
}
#info_line {
font-size: 16px;
text-align: right;
}

View file

@ -0,0 +1,82 @@
schedule = null;
room_name = null;
event_info = null;
$(function() {
$('#speaker').text('Content will appear soon.');
});
function update_lower_third() {
current_time = new Date(Date.now()).getTime()
try {
hash = decodeURIComponent(window.location.hash.substring(1));
room_name = hash;
} catch (e) {
console.error(e);
return
}
if (!schedule || !event_info) {
console.warn("There's no schedule or no event info yet, exiting ...");
return
}
if (schedule['rooms'].length > 1 && !schedule['rooms'].includes(room_name)) {
$('#title').text('Error')
$('#speaker').text('Invalid room_name. Valid names: ' + schedule['rooms'].join(', '));
return
}
current_talk = null;
for (talk_i in schedule['talks']) {
talk = schedule['talks'][talk_i]
if (schedule['rooms'].length > 1 && talk['room'] != room_name) {
// not in this room
continue;
}
talk_start = new Date(talk['start']).getTime();
talk_end = new Date(talk['end']).getTime();
if (talk_start < current_time && talk_end > current_time) {
current_talk = talk;
}
}
if (current_talk) {
$('#title').text(current_talk['title']);
$('#speaker').text(current_talk['persons'].join(', '));
$('#info_line').text(current_talk['infoline']);
} else {
$('#title').text(event_info['no_talk']);
$('#speaker').text('');
$('#info_line').text('');
}
if (current_talk && current_talk['track']) {
$('#box').css('border-bottom', '10px solid ' + current_talk['track']['color']);
} else {
$('#box').css('border-bottom', 'none');
}
}
window.setInterval(update_lower_third, 1000);
function update_schedule() {
$.getJSON('../event.json', function(data) {
event_info = data;
$('#box').css('background-color', data['color']);
});
$.getJSON('../schedule.json', function(data) {
console.info('schedule updated with ' + data['talks'].length + ' talks in ' + data['rooms'].length + ' rooms');
schedule = data;
window.setTimeout(update_schedule, 30000);
});
}
update_schedule();

View file

@ -0,0 +1,21 @@
{% load static %}
{% load compress %}
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html" charset="UTF-8">
<title>{{ request.event.name }} lower thirds</title>
{% compress js %}
<script src="{% static "vendored/jquery-3.1.1.js" %}"></script>
{% endcompress %}
<script src="{% static "pretalx_broadcast_tools/update.js" %}"></script>
<link rel="stylesheet" href="{% static "pretalx_broadcast_tools/frontend.css" %}" />
</head>
<body>
<div id="box">
<p id="title">Loading ...</p>
<p id="speaker">Content should appear soon. If not, please verify you have Javascript enabled.</p>
<p id="info_line"></p>
</div>
</body>
</html>

View file

@ -0,0 +1,52 @@
{% extends "orga/base.html" %}
{% load bootstrap4 %}
{% load i18n %}
{% block content %}
<form method="post">
{% csrf_token %}
<fieldset>
<legend>
{% translate "Set up lower thirds" %}
</legend>
{% bootstrap_field form.lower_thirds_no_talk_info layout='event' %}
{% bootstrap_field form.lower_thirds_info_string layout='event' %}
<p>
The info line will be shown on the bottom right side of your
lower third. If you set it to an empty string, it will automatically
hide itself.
</p>
<p>
pretalx will automatically replace some placeholders in your info
string.
Use <code>{CODE}</code> to embed the talk code (<code>MUX9U3</code>
for example). You could use this to directly link to the talk
feedback page.
Use <code>{EVENT_SLUG}</code> to get the event slug.
Use <code>{TALK_SLUG}</code> to get the talk slug.
</p>
{% if request.event.rooms %}
<h3>{% trans "room list" %}</h3>
<ul>
{% for room in request.event.rooms.all %}
<li><a href="{% url 'plugins:pretalx_broadcast_tools:lowerthirds' request.event.slug %}#{{ room.name }}">{{ room.name }}</a></li>
{% endfor %}
</ul>
{% endif %}
<div class="submit-group panel">
<span></span>
<span class="d-flex flex-row-reverse">
<button
type="submit" class="btn btn-success btn-lg"
name="action" value="save"
>
<i class="fa fa-check"></i>
{% trans "Save" %}
</button>
</span>
</div>
</form>
{% endblock %}

View file

@ -0,0 +1,27 @@
from django.urls import re_path
from pretalx.event.models.event import SLUG_CHARS
from . import views
urlpatterns = [
re_path(
f"^(?P<event>[{SLUG_CHARS}]+)/p/broadcast-tools/lower-thirds/$",
views.BroadcastToolsLowerThirdsView.as_view(),
name="lowerthirds",
),
re_path(
f"^(?P<event>[{SLUG_CHARS}]+)/p/broadcast-tools/event.json$",
views.BroadcastToolsEventInfoView.as_view(),
name="event_info",
),
re_path(
f"^(?P<event>[{SLUG_CHARS}]+)/p/broadcast-tools/schedule.json$",
views.BroadcastToolsScheduleView.as_view(),
name="schedule",
),
re_path(
f"^orga/event/(?P<event>[{SLUG_CHARS}]+)/settings/p/broadcast-tools/$",
views.BroadcastToolsOrgaView.as_view(),
name="orga",
),
]

View file

@ -0,0 +1,108 @@
import datetime as dt
import pytz
from django.http import JsonResponse
from django.views.generic import FormView
from django.views.generic.base import TemplateView
from pretalx.agenda.views.schedule import ScheduleMixin
from pretalx.common.mixins.views import EventPermissionRequired, PermissionRequired
from pretalx.schedule.exporters import ScheduleData
from .forms import BroadcastToolsSettingsForm
class BroadcastToolsLowerThirdsView(TemplateView):
template_name = "pretalx_broadcast_tools/lower_thirds.html"
class BroadcastToolsOrgaView(PermissionRequired, FormView):
form_class = BroadcastToolsSettingsForm
permission_required = "orga.change_settings"
template_name = "pretalx_broadcast_tools/orga.html"
def get_success_url(self):
return self.request.path
def form_valid(self, form):
form.save()
return super().form_valid(form)
def get_object(self):
return self.request.event
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
return {
"obj": self.request.event,
"attribute_name": "settings",
"locales": self.request.event.locales,
**kwargs,
}
class BroadcastToolsEventInfoView(TemplateView):
def get(self, request, *args, **kwargs):
color = self.request.event.primary_color or "#3aa57c"
return JsonResponse(
{
"slug": self.request.event.slug,
"name": str(self.request.event.name),
"no_talk": str(self.request.event.settings.lower_thirds_no_talk_info),
"color": color,
},
)
class BroadcastToolsScheduleView(EventPermissionRequired, ScheduleMixin, TemplateView):
permission_required = "agenda.view_schedule"
def get(self, request, *args, **kwargs):
schedule = ScheduleData(
event=self.request.event,
schedule=self.schedule,
)
tz = pytz.timezone(schedule.event.timezone)
infoline = str(schedule.event.settings.infoline or "")
return JsonResponse(
{
"rooms": sorted(
{
str(room["name"])
for day in schedule.data
for room in day["rooms"]
}
),
"talks": [
{
"id": talk.submission.id,
"start": talk.start.astimezone(tz).isoformat(),
"end": (talk.start + dt.timedelta(minutes=talk.duration))
.astimezone(tz)
.isoformat(),
"slug": talk.frab_slug,
"title": talk.submission.title,
"persons": sorted(
{
person.get_display_name()
for person in talk.submission.speakers.all()
}
),
"track": {
"color": talk.submission.track.color,
"name": str(talk.submission.track.name),
}
if talk.submission.track
else None,
"room": str(room["name"]),
"infoline": infoline.format(
EVENT_SLUG=str(schedule.event.slug),
TALK_SLUG=talk.frab_slug,
CODE=talk.submission.code,
),
}
for day in schedule.data
for room in day["rooms"]
for talk in room["talks"]
],
},
)