Add automatic broadcast features and UI improvements

apikeys
Razmig Sarkissian 2 months ago
parent bcf5017169
commit 17d6313042
  1. 4
      tournaments/templates/tournaments/broadcast/broadcast.html
  2. 15
      tournaments/templates/tournaments/broadcast/broadcast_club.html
  3. 91
      tournaments/templates/tournaments/broadcast/broadcasted_auto.html
  4. 18
      tournaments/templates/tournaments/broadcast/broadcasted_bracket.html
  5. 63
      tournaments/templates/tournaments/broadcast/broadcasted_club_auto.html
  6. 63
      tournaments/templates/tournaments/broadcast/broadcasted_event_auto.html
  7. 2
      tournaments/templates/tournaments/broadcast/broadcasted_planning.html
  8. 22
      tournaments/views.py

@ -24,13 +24,15 @@
<div class="grid-x">
<div class="cell medium-6 large-6 topblock padding10">
<div class="bubble">
<div><a href="{% url 'automatic-broadcast' tournament.id %}">Automatique</a></div>
<div><a href="{% url 'automatic-broadcast' tournament.id %}">Auto</a></div>
<div><a href="{% url 'automatic-broadcast-event' tournament.event.id %}">Event Auto</a></div>
<div><a href="{% url 'broadcasted-matches' tournament.id %}">Matchs</a></div>
<div><a href="{% url 'broadcasted-group-stages' tournament.id %}">Poules</a></div>
<div><a href="{% url 'broadcasted-summons' tournament.id %}">Convocations</a></div>
<div><a href="{% url 'broadcasted-rankings' tournament.id %}">Classement</a></div>
<div><a href="{% url 'broadcasted-planning' tournament.id %}">(beta) Planning</a></div>
<div><a href="{% url 'broadcasted-bracket' tournament.id %}">(beta) Tableau</a></div>
<div><a href="{% url 'club-broadcast-auto' tournament.event.club.broadcast_code %}">Club Auto</a></div>
</div>
</div>

@ -8,6 +8,18 @@
{% block content %}
<div class="grid-x">
<!-- Club Auto Broadcast Link at the top -->
<div class="cell topblock padding10">
<div class="bubble" style="padding: 8px 15px; margin-bottom: 10px; background-color: #f8f9fa;">
<span style="font-size: 0.9em; color: #555;">
<a href="{% url 'club-broadcast-auto' club.broadcast_code %}" style="color: #007acc; text-decoration: none; font-weight: 500;">Diffusion automatique du club</a>
- Cycle automatiquement entre tous les tournois actifs +- 3 jours
</span>
</div>
</div>
<div class="cell topblock padding10">
<div class="bubble">
@ -30,7 +42,8 @@
<span>{{ tournament.private_label }}</span>
</div>
<div class="table-cell">
<span><a href="{% url 'automatic-broadcast' tournament.id %}">Automatic</a></span> |
<span><a href="{% url 'automatic-broadcast' tournament.id %}">Auto</a></span> |
<span><a href="{% url 'automatic-broadcast-event' tournament.event.id %}">Event Auto</a></span> |
<span><a href="{% url 'broadcasted-bracket' tournament.id %}">(beta) Tableau</a></span> |
<span><a href="{% url 'broadcasted-planning' tournament.id %}">(beta) Planning</a></span> |
<span><a href="{% url 'broadcasted-matches' tournament.id %}">Matchs</a></span> |

@ -200,6 +200,7 @@
</div>
</body>
</body>
<footer class="footer-broadcast">
{% if tournament.event.images.exists %}
@ -213,4 +214,94 @@
</div>
{% endif %}
</footer>
<script>
console.log('Tournament auto page loaded, tournament ID: {{ tournament.id }}');
let startTime = Date.now();
let lastActive = null;
let cycleCount = 0;
let maxPagesSeen = 0;
let hasNotifiedParent = false;
function checkForCompletion() {
try {
// Find the Alpine.js element
const alpineEl = document.querySelector('[x-data]');
if (!alpineEl || !alpineEl._x_dataStack) {
console.log('Alpine not ready yet');
return;
}
const data = alpineEl._x_dataStack[0];
const currentActive = data.active;
const pageCount = data.pageCount();
const elapsed = Date.now() - startTime;
if (pageCount === 0) {
console.log('No pages to display yet');
return;
}
// Track the maximum page number we've seen
maxPagesSeen = Math.max(maxPagesSeen, currentActive);
console.log(`Current page: ${currentActive}/${pageCount}, Max seen: ${maxPagesSeen}, Elapsed: ${Math.round(elapsed/1000)}s`);
let shouldComplete = false;
let reason = '';
// Calculate completion time: 15 seconds per page
const completionTime = pageCount * 15000; // 15 seconds per page
if (pageCount === 1) {
// Single page tournament: complete after 15 seconds
if (elapsed >= 15000) {
shouldComplete = true;
reason = 'Single page - 15 seconds elapsed';
}
} else if (pageCount > 1) {
// Multi-page tournament: complete when we cycle back to page 1 after seeing all pages
if (currentActive === 1 && lastActive > 1 && maxPagesSeen >= pageCount) {
shouldComplete = true;
reason = 'Multi-page - full cycle completed';
} else if (elapsed >= completionTime) {
// Fallback: complete after (pageCount * 15 seconds)
shouldComplete = true;
reason = `Multi-page - ${pageCount * 15} seconds elapsed`;
}
}
if (shouldComplete && !hasNotifiedParent) {
hasNotifiedParent = true;
cycleCount++;
console.log(`🎯 TOURNAMENT COMPLETED! Reason: ${reason}`);
// Send message to parent
if (window.parent !== window) {
window.parent.postMessage({
type: 'tournamentCycleComplete',
cycleCount: cycleCount,
tournamentId: '{{ tournament.id }}',
pageCount: pageCount,
reason: reason,
elapsedSeconds: Math.round(elapsed/1000)
}, '*');
console.log('Message sent to parent window');
} else {
console.log('No parent window found');
}
}
lastActive = currentActive;
} catch (error) {
console.error('Error checking completion:', error);
}
}
// Check every 2 seconds
setInterval(checkForCompletion, 2000);
console.log('Tournament completion detection initialized');
</script>
</html>

@ -43,6 +43,24 @@
padding: 20px;
max-width: 45%;
}
/* Reduce font size for player names */
.broadcast-mode .player .semibold {
font-size: 0.85em !important;
line-height: 1.2 !important;
}
/* Reduce font size for team weight */
.broadcast-mode .score.numbers {
font-size: 0.85em !important;
}
/* Optional: Also reduce single/two player text if needed */
.broadcast-mode .single-player .semibold,
.broadcast-mode .two-players .semibold {
font-size: 0.85em !important;
line-height: 1.2 !important;
}
</style>
</head>

@ -0,0 +1,63 @@
<!DOCTYPE html>
<html>
<head>
<title>Club Auto Broadcast</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body {
height: 100%;
overflow: hidden;
background-color: #000;
}
iframe {
width: 100vw;
height: 100vh;
border: none;
display: block;
background-color: #000;
}
</style>
</head>
<body>
<iframe id="tournamentFrame" src="about:blank"></iframe>
<script>
const tournamentIds = {{ tournament_ids|safe }};
let currentIndex = 0;
const frame = document.getElementById('tournamentFrame');
function loadNextTournament() {
if (tournamentIds.length === 0) {
document.body.innerHTML = '<div style="display: flex; align-items: center; justify-content: center; height: 100vh; font-size: 24px; color: white;">Aucun tournoi disponible pour {{ club_name }}</div>';
return;
}
const tournamentId = tournamentIds[currentIndex];
const url = `/tournament/${tournamentId}/broadcast/auto/`;
console.log(`Loading tournament ${currentIndex + 1}/${tournamentIds.length}: ${tournamentId.substring(0, 8)}`);
frame.src = url;
currentIndex = (currentIndex + 1) % tournamentIds.length;
}
// Listen for cycle completion messages from tournament iframe
window.addEventListener('message', function(event) {
if (event.data.type === 'tournamentCycleComplete') {
console.log(`Tournament completed (${event.data.reason})`);
setTimeout(loadNextTournament, 1000); // Switch after 1 second
}
});
// Load first tournament immediately
loadNextTournament();
</script>
</body>
</html>

@ -0,0 +1,63 @@
<!DOCTYPE html>
<html>
<head>
<title>Event Auto Broadcast</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body {
height: 100%;
overflow: hidden;
background-color: #000;
}
iframe {
width: 100vw;
height: 100vh;
border: none;
display: block;
background-color: #000;
}
</style>
</head>
<body>
<iframe id="tournamentFrame" src="about:blank"></iframe>
<script>
const tournamentIds = {{ tournament_ids|safe }};
let currentIndex = 0;
const frame = document.getElementById('tournamentFrame');
function loadNextTournament() {
if (tournamentIds.length === 0) {
document.body.innerHTML = '<div style="display: flex; align-items: center; justify-content: center; height: 100vh; font-size: 24px; color: white;">Aucun tournoi disponible</div>';
return;
}
const tournamentId = tournamentIds[currentIndex];
const url = `/tournament/${tournamentId}/broadcast/auto/`;
console.log(`Loading tournament ${currentIndex + 1}/${tournamentIds.length}: ${tournamentId.substring(0, 8)}`);
frame.src = url;
currentIndex = (currentIndex + 1) % tournamentIds.length;
}
// Listen for cycle completion messages from tournament iframe
window.addEventListener('message', function(event) {
if (event.data.type === 'tournamentCycleComplete') {
console.log(`Tournament completed (${event.data.reason})`);
setTimeout(loadNextTournament, 1000); // Switch after 1 second
}
});
// Load first tournament immediately
loadNextTournament();
</script>
</body>
</html>

@ -267,7 +267,7 @@
this.currentDayIndex = 0;
this.currentPageIndex = 0;
}
}, 15000);
}, 20000);
},
calculateFractionWidth() {

@ -521,18 +521,29 @@ def tournament_broadcast_home(request, tournament_id):
def automatic_broadcast(request, tournament_id):
tournament = get_object_or_404(Tournament, pk=tournament_id)
return render(request, 'tournaments/broadcast/broadcasted_auto.html', {
response = render(request, 'tournaments/broadcast/broadcasted_auto.html', {
'tournament': tournament,
'qr_code_url': qr_code_url(request, tournament_id),
'qr_code_options': qr_code_options(),
})
# Allow iframe embedding from same origin
response['X-Frame-Options'] = 'SAMEORIGIN'
return response
def automatic_broadcast_event(request, event_id):
event = get_object_or_404(Event, pk=event_id)
tournaments = Tournament.objects.filter(event=event)
tournament_ids = [str(tournament.id) for tournament in tournaments]
return render(request, 'tournaments/broadcast/broadcasted_auto_event.html', {
# Create QR code URL for the event broadcast
qr_code_url_val = reverse('automatic-broadcast-event', args=[event_id])
qr_code_url_full = request.build_absolute_uri(qr_code_url_val)
return render(request, 'tournaments/broadcast/broadcasted_event_auto.html', {
'tournament_ids': tournament_ids,
'event': event,
'qr_code_url': qr_code_url_full,
'qr_code_options': qr_code_options(),
})
def qr_code_url(request, tournament_id):
@ -774,13 +785,10 @@ def club_broadcast_auto(request, broadcast_code):
)
tournament_ids = [str(tournament.id) for tournament in tournaments]
#print(tournament_ids)
return render(request, 'tournaments/broadcast/broadcasted_auto_event.html', {
return render(request, 'tournaments/broadcast/broadcasted_club_auto.html', {
'tournament_ids': tournament_ids,
'club_name': club.name,
'qr_code_url': qr_code_url_with_query(request, club.id),
'qr_code_options': qr_code_options(),
})
def download(request):

Loading…
Cancel
Save