|
|
|
@@ -71,10 +71,10 @@
|
|
|
|
|
max-width: 380px;
|
|
|
|
|
}
|
|
|
|
|
#notificationStack > div { pointer-events: auto; }
|
|
|
|
|
#editModal {
|
|
|
|
|
#editModal, #addCommandModal {
|
|
|
|
|
transition: opacity 0.2s;
|
|
|
|
|
}
|
|
|
|
|
#editModal.hidden { display: none; }
|
|
|
|
|
#editModal.hidden, #addCommandModal.hidden { display: none; }
|
|
|
|
|
</style>
|
|
|
|
|
|
|
|
|
|
<div id="notificationStack"></div>
|
|
|
|
@@ -137,9 +137,9 @@
|
|
|
|
|
|
|
|
|
|
{% if is_live %}
|
|
|
|
|
<!-- ===== LAYOUT EN LIVE ===== -->
|
|
|
|
|
<!-- Ligne 1 : Player (2/3) | Formulaire commande (1/3) -->
|
|
|
|
|
<!-- Ligne 1 : Player (2/3) | Infos stream dynamiques (1/3) -->
|
|
|
|
|
<div class="grid lg:grid-cols-3 gap-4">
|
|
|
|
|
<!-- Player Twitch + stats dynamiques (2/3) -->
|
|
|
|
|
<!-- Player Twitch (2/3) -->
|
|
|
|
|
<div class="lg:col-span-2 bg-white dark:bg-gray-800 rounded-xl shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden">
|
|
|
|
|
<div class="aspect-video bg-gray-900">
|
|
|
|
|
<iframe
|
|
|
|
@@ -150,12 +150,12 @@
|
|
|
|
|
</div>
|
|
|
|
|
<div class="p-3 bg-gray-50 dark:bg-gray-700 flex items-center justify-between">
|
|
|
|
|
<div class="flex items-center gap-2">
|
|
|
|
|
<span class="flex h-2 w-2 relative">
|
|
|
|
|
<span class="flex h-2 w-2 relative" id="liveIndicator">
|
|
|
|
|
<span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-red-400 opacity-75"></span>
|
|
|
|
|
<span class="relative inline-flex rounded-full h-2 w-2 bg-red-500"></span>
|
|
|
|
|
</span>
|
|
|
|
|
<span class="text-sm font-medium text-gray-900 dark:text-white">EN DIRECT</span>
|
|
|
|
|
<span class="text-sm text-gray-500 dark:text-gray-400">• {{ viewer_count }} viewers</span>
|
|
|
|
|
<span class="text-sm font-medium text-gray-900 dark:text-white" id="liveStatusLabel">EN DIRECT</span>
|
|
|
|
|
<span class="text-sm text-gray-500 dark:text-gray-400" id="playerViewerCount">• {{ viewer_count }} viewers</span>
|
|
|
|
|
</div>
|
|
|
|
|
<a href="https://www.twitch.tv/{{ twitch_channel }}" target="_blank" class="text-xs text-purple-600 dark:text-purple-400 hover:underline flex items-center gap-1">
|
|
|
|
|
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"></path></svg>
|
|
|
|
@@ -164,54 +164,68 @@
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Formulaire Nouvelle commande (1/3) -->
|
|
|
|
|
<div class="bg-white dark:bg-gray-800 rounded-xl shadow-sm border border-gray-200 dark:border-gray-700 p-4">
|
|
|
|
|
<h2 class="text-sm font-semibold text-gray-900 dark:text-white mb-3 flex items-center gap-2">
|
|
|
|
|
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path></svg>
|
|
|
|
|
Nouvelle commande
|
|
|
|
|
<!-- Infos stream dynamiques (1/3) -->
|
|
|
|
|
<div class="bg-white dark:bg-gray-800 rounded-xl shadow-sm border border-gray-200 dark:border-gray-700 p-4 flex flex-col gap-4">
|
|
|
|
|
<h2 class="text-sm font-semibold text-gray-900 dark:text-white flex items-center gap-2">
|
|
|
|
|
<svg class="w-4 h-4 text-purple-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
|
|
|
|
|
Infos du stream
|
|
|
|
|
</h2>
|
|
|
|
|
<form action="{{ url_for('add_twitch_commande') }}" method="POST" class="space-y-3">
|
|
|
|
|
<input type="text" name="trigger" placeholder="!commande" required
|
|
|
|
|
class="w-full px-3 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 text-gray-900 dark:text-white focus:ring-2 focus:ring-purple-500 text-sm">
|
|
|
|
|
<select name="twitch_permission"
|
|
|
|
|
class="w-full px-3 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 text-gray-900 dark:text-white focus:ring-2 focus:ring-purple-500 text-sm">
|
|
|
|
|
{% for value, label in twitch_permissions.items() %}
|
|
|
|
|
<option value="{{ value }}">{{ label }}</option>
|
|
|
|
|
{% endfor %}
|
|
|
|
|
</select>
|
|
|
|
|
<textarea name="response" rows="3" placeholder="Réponse... ({user} = mention)" required
|
|
|
|
|
class="w-full px-3 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 text-gray-900 dark:text-white focus:ring-2 focus:ring-purple-500 text-sm resize-none"></textarea>
|
|
|
|
|
<button type="submit" class="w-full px-3 py-2 bg-purple-600 hover:bg-purple-700 text-white rounded-lg transition-colors font-medium text-sm">Ajouter</button>
|
|
|
|
|
</form>
|
|
|
|
|
|
|
|
|
|
<div class="space-y-3 flex-1">
|
|
|
|
|
<!-- Titre -->
|
|
|
|
|
<div>
|
|
|
|
|
<div class="text-xs text-gray-500 dark:text-gray-400 mb-1">Titre</div>
|
|
|
|
|
<div class="text-sm font-medium text-gray-900 dark:text-white leading-snug" id="streamTitle">{{ stream_title or 'N/A' }}</div>
|
|
|
|
|
</div>
|
|
|
|
|
<!-- Jeu / Catégorie -->
|
|
|
|
|
<div>
|
|
|
|
|
<div class="text-xs text-gray-500 dark:text-gray-400 mb-1">Catégorie</div>
|
|
|
|
|
<div class="flex items-center gap-1.5">
|
|
|
|
|
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-purple-100 dark:bg-purple-900/30 text-purple-700 dark:text-purple-300" id="streamGame">{{ game_name or 'N/A' }}</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<!-- Viewers -->
|
|
|
|
|
<div>
|
|
|
|
|
<div class="text-xs text-gray-500 dark:text-gray-400 mb-1">Viewers</div>
|
|
|
|
|
<div class="text-2xl font-bold text-purple-600 dark:text-purple-400" id="streamViewers">{{ viewer_count }}</div>
|
|
|
|
|
</div>
|
|
|
|
|
<!-- Uptime -->
|
|
|
|
|
<div>
|
|
|
|
|
<div class="text-xs text-gray-500 dark:text-gray-400 mb-1">Uptime</div>
|
|
|
|
|
<div class="text-sm font-mono font-medium text-gray-900 dark:text-white" id="streamUptime">--:--:--</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<a href="https://www.twitch.tv/{{ twitch_channel }}" target="_blank" class="block w-full px-3 py-2 bg-purple-600 hover:bg-purple-700 text-white rounded-lg transition-colors font-medium text-sm text-center">
|
|
|
|
|
Voir sur Twitch
|
|
|
|
|
</a>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Ligne 2 : Chat + Sanctions (pleine largeur) -->
|
|
|
|
|
<!-- Ligne 2 : Chat (pleine largeur) -->
|
|
|
|
|
<div class="bg-white dark:bg-gray-800 rounded-xl shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden flex flex-col" style="height: 500px;">
|
|
|
|
|
{% else %}
|
|
|
|
|
<!-- ===== LAYOUT HORS LIVE ===== -->
|
|
|
|
|
<div class="grid lg:grid-cols-2 gap-4">
|
|
|
|
|
<!-- Formulaire d'ajout de commande -->
|
|
|
|
|
<div class="bg-white dark:bg-gray-800 rounded-xl shadow-sm border border-gray-200 dark:border-gray-700 p-4">
|
|
|
|
|
<h2 class="text-base font-semibold text-gray-900 dark:text-white mb-3 flex items-center gap-2">
|
|
|
|
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path></svg>
|
|
|
|
|
Ajouter une commande
|
|
|
|
|
</h2>
|
|
|
|
|
<form action="{{ url_for('add_twitch_commande') }}" method="POST" class="space-y-3">
|
|
|
|
|
<div class="grid grid-cols-2 gap-2">
|
|
|
|
|
<input type="text" name="trigger" placeholder="!commande" required
|
|
|
|
|
class="px-3 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 text-gray-900 dark:text-white focus:ring-2 focus:ring-purple-500 text-sm">
|
|
|
|
|
<select name="twitch_permission"
|
|
|
|
|
class="px-3 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 text-gray-900 dark:text-white focus:ring-2 focus:ring-purple-500 text-sm">
|
|
|
|
|
{% for value, label in twitch_permissions.items() %}
|
|
|
|
|
<option value="{{ value }}">{{ label }}</option>
|
|
|
|
|
{% endfor %}
|
|
|
|
|
</select>
|
|
|
|
|
<!-- Player Twitch (offline) + infos -->
|
|
|
|
|
<div class="bg-white dark:bg-gray-800 rounded-xl shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden">
|
|
|
|
|
<div class="aspect-video bg-gray-900">
|
|
|
|
|
<iframe
|
|
|
|
|
src="https://player.twitch.tv/?channel={{ twitch_channel }}&enableExtensions=true&muted=true&parent={{ embed_parent }}&player=popout&quality=auto&volume=0"
|
|
|
|
|
style="width: 100%; height: 100%; border: none;"
|
|
|
|
|
allowfullscreen>
|
|
|
|
|
</iframe>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="p-3 bg-gray-50 dark:bg-gray-700 flex items-center justify-between">
|
|
|
|
|
<div class="flex items-center gap-2">
|
|
|
|
|
<span class="relative inline-flex rounded-full h-2 w-2 bg-gray-400"></span>
|
|
|
|
|
<span class="text-sm font-medium text-gray-500 dark:text-gray-400" id="liveStatusLabel">HORS LIGNE</span>
|
|
|
|
|
</div>
|
|
|
|
|
<textarea name="response" rows="2" placeholder="Réponse du bot... ({user} = mention)" required
|
|
|
|
|
class="w-full px-3 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 text-gray-900 dark:text-white focus:ring-2 focus:ring-purple-500 text-sm resize-none"></textarea>
|
|
|
|
|
<button type="submit" class="w-full px-3 py-2 bg-purple-600 hover:bg-purple-700 text-white rounded-lg transition-colors font-medium text-sm">Ajouter</button>
|
|
|
|
|
</form>
|
|
|
|
|
<a href="https://www.twitch.tv/{{ twitch_channel }}" target="_blank" class="text-xs text-purple-600 dark:text-purple-400 hover:underline flex items-center gap-1">
|
|
|
|
|
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"></path></svg>
|
|
|
|
|
Ouvrir sur Twitch
|
|
|
|
|
</a>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Chat (1/2) -->
|
|
|
|
@@ -402,8 +416,12 @@
|
|
|
|
|
|
|
|
|
|
<!-- Commandes personnalisées Twitch -->
|
|
|
|
|
<div class="bg-white dark:bg-gray-800 rounded-xl shadow-sm border border-gray-200 dark:border-gray-700 overflow-hidden">
|
|
|
|
|
<div class="px-4 py-3 bg-gray-50 dark:bg-gray-700 border-b border-gray-200 dark:border-gray-600">
|
|
|
|
|
<div class="px-4 py-3 bg-gray-50 dark:bg-gray-700 border-b border-gray-200 dark:border-gray-600 flex items-center justify-between">
|
|
|
|
|
<h3 class="font-semibold text-gray-900 dark:text-white">Commandes personnalisées Twitch (<span id="customCmdCount">{{ custom_commands|length }}</span>)</h3>
|
|
|
|
|
<button onclick="openAddCommandModal()" class="px-3 py-1.5 bg-purple-600 hover:bg-purple-700 text-white rounded-lg transition-colors font-medium text-xs flex items-center gap-1.5">
|
|
|
|
|
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path></svg>
|
|
|
|
|
Ajouter
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="overflow-x-auto">
|
|
|
|
|
<table class="w-full text-sm" id="customCommandsTable">
|
|
|
|
@@ -512,6 +530,17 @@
|
|
|
|
|
<div>
|
|
|
|
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Réponse</label>
|
|
|
|
|
<textarea id="editResponse" rows="3" class="w-full px-3 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 text-gray-900 dark:text-white focus:ring-2 focus:ring-purple-500 text-sm resize-none"></textarea>
|
|
|
|
|
<div class="mt-2">
|
|
|
|
|
<div class="text-xs text-gray-500 dark:text-gray-400 mb-1.5">Variables disponibles <span class="text-gray-400">(cliquer pour insérer)</span></div>
|
|
|
|
|
<div class="flex flex-wrap gap-1">
|
|
|
|
|
<button type="button" onclick="insertVariable('editResponse','{user}')" class="px-1.5 py-0.5 bg-gray-100 dark:bg-gray-700 text-purple-600 dark:text-purple-400 rounded text-xs font-mono hover:bg-purple-100 dark:hover:bg-purple-900/30 transition-colors" title="Nom de l'utilisateur">{user}</button>
|
|
|
|
|
<button type="button" onclick="insertVariable('editResponse','{channel}')" class="px-1.5 py-0.5 bg-gray-100 dark:bg-gray-700 text-purple-600 dark:text-purple-400 rounded text-xs font-mono hover:bg-purple-100 dark:hover:bg-purple-900/30 transition-colors" title="Nom de la chaîne">{channel}</button>
|
|
|
|
|
<button type="button" onclick="insertVariable('editResponse','{title}')" class="px-1.5 py-0.5 bg-gray-100 dark:bg-gray-700 text-purple-600 dark:text-purple-400 rounded text-xs font-mono hover:bg-purple-100 dark:hover:bg-purple-900/30 transition-colors" title="Titre du stream">{title}</button>
|
|
|
|
|
<button type="button" onclick="insertVariable('editResponse','{game}')" class="px-1.5 py-0.5 bg-gray-100 dark:bg-gray-700 text-purple-600 dark:text-purple-400 rounded text-xs font-mono hover:bg-purple-100 dark:hover:bg-purple-900/30 transition-colors" title="Jeu / catégorie">{game}</button>
|
|
|
|
|
<button type="button" onclick="insertVariable('editResponse','{uptime}')" class="px-1.5 py-0.5 bg-gray-100 dark:bg-gray-700 text-purple-600 dark:text-purple-400 rounded text-xs font-mono hover:bg-purple-100 dark:hover:bg-purple-900/30 transition-colors" title="Durée du live">{uptime}</button>
|
|
|
|
|
<button type="button" onclick="insertVariable('editResponse','{viewers}')" class="px-1.5 py-0.5 bg-gray-100 dark:bg-gray-700 text-purple-600 dark:text-purple-400 rounded text-xs font-mono hover:bg-purple-100 dark:hover:bg-purple-900/30 transition-colors" title="Nombre de viewers">{viewers}</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="px-5 py-4 border-t border-gray-200 dark:border-gray-700 flex justify-end gap-2">
|
|
|
|
@@ -521,6 +550,56 @@
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Modal d'ajout de commande -->
|
|
|
|
|
<div id="addCommandModal" class="hidden fixed inset-0 z-50 flex items-center justify-center bg-black/50" onclick="if(event.target===this)closeAddCommandModal()">
|
|
|
|
|
<div class="bg-white dark:bg-gray-800 rounded-xl shadow-xl border border-gray-200 dark:border-gray-700 w-full max-w-md mx-4 animate-fade-in">
|
|
|
|
|
<div class="px-5 py-4 border-b border-gray-200 dark:border-gray-700 flex items-center justify-between">
|
|
|
|
|
<h3 class="font-semibold text-gray-900 dark:text-white">Ajouter une commande</h3>
|
|
|
|
|
<button onclick="closeAddCommandModal()" class="text-gray-400 hover:text-gray-600 dark:hover:text-gray-300">
|
|
|
|
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path></svg>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
<form action="{{ url_for('add_twitch_commande') }}" method="POST">
|
|
|
|
|
<div class="p-5 space-y-4">
|
|
|
|
|
<div>
|
|
|
|
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Commande</label>
|
|
|
|
|
<input type="text" name="trigger" placeholder="!commande" required
|
|
|
|
|
class="w-full px-3 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 text-gray-900 dark:text-white focus:ring-2 focus:ring-purple-500 text-sm">
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Permission</label>
|
|
|
|
|
<select name="twitch_permission"
|
|
|
|
|
class="w-full px-3 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 text-gray-900 dark:text-white focus:ring-2 focus:ring-purple-500 text-sm">
|
|
|
|
|
{% for value, label in twitch_permissions.items() %}
|
|
|
|
|
<option value="{{ value }}">{{ label }}</option>
|
|
|
|
|
{% endfor %}
|
|
|
|
|
</select>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Réponse</label>
|
|
|
|
|
<textarea name="response" id="addResponse" rows="3" placeholder="Réponse du bot..." required
|
|
|
|
|
class="w-full px-3 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-800 text-gray-900 dark:text-white focus:ring-2 focus:ring-purple-500 text-sm resize-none"></textarea>
|
|
|
|
|
<div class="mt-2">
|
|
|
|
|
<div class="text-xs text-gray-500 dark:text-gray-400 mb-1.5">Variables disponibles <span class="text-gray-400">(cliquer pour insérer)</span></div>
|
|
|
|
|
<div class="flex flex-wrap gap-1">
|
|
|
|
|
<button type="button" onclick="insertVariable('addResponse','{user}')" class="px-1.5 py-0.5 bg-gray-100 dark:bg-gray-700 text-purple-600 dark:text-purple-400 rounded text-xs font-mono hover:bg-purple-100 dark:hover:bg-purple-900/30 transition-colors" title="Nom de l'utilisateur">{user}</button>
|
|
|
|
|
<button type="button" onclick="insertVariable('addResponse','{channel}')" class="px-1.5 py-0.5 bg-gray-100 dark:bg-gray-700 text-purple-600 dark:text-purple-400 rounded text-xs font-mono hover:bg-purple-100 dark:hover:bg-purple-900/30 transition-colors" title="Nom de la chaîne">{channel}</button>
|
|
|
|
|
<button type="button" onclick="insertVariable('addResponse','{title}')" class="px-1.5 py-0.5 bg-gray-100 dark:bg-gray-700 text-purple-600 dark:text-purple-400 rounded text-xs font-mono hover:bg-purple-100 dark:hover:bg-purple-900/30 transition-colors" title="Titre du stream">{title}</button>
|
|
|
|
|
<button type="button" onclick="insertVariable('addResponse','{game}')" class="px-1.5 py-0.5 bg-gray-100 dark:bg-gray-700 text-purple-600 dark:text-purple-400 rounded text-xs font-mono hover:bg-purple-100 dark:hover:bg-purple-900/30 transition-colors" title="Jeu / catégorie">{game}</button>
|
|
|
|
|
<button type="button" onclick="insertVariable('addResponse','{uptime}')" class="px-1.5 py-0.5 bg-gray-100 dark:bg-gray-700 text-purple-600 dark:text-purple-400 rounded text-xs font-mono hover:bg-purple-100 dark:hover:bg-purple-900/30 transition-colors" title="Durée du live">{uptime}</button>
|
|
|
|
|
<button type="button" onclick="insertVariable('addResponse','{viewers}')" class="px-1.5 py-0.5 bg-gray-100 dark:bg-gray-700 text-purple-600 dark:text-purple-400 rounded text-xs font-mono hover:bg-purple-100 dark:hover:bg-purple-900/30 transition-colors" title="Nombre de viewers">{viewers}</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="px-5 py-4 border-t border-gray-200 dark:border-gray-700 flex justify-end gap-2">
|
|
|
|
|
<button type="button" onclick="closeAddCommandModal()" class="px-4 py-2 text-sm text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors">Annuler</button>
|
|
|
|
|
<button type="submit" class="px-4 py-2 text-sm bg-purple-600 hover:bg-purple-700 text-white rounded-lg transition-colors font-medium">Ajouter</button>
|
|
|
|
|
</div>
|
|
|
|
|
</form>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
(function() {
|
|
|
|
|
// --- Recherche commandes de modération ---
|
|
|
|
@@ -1088,5 +1167,87 @@ setInterval(fetchShoutbox, 3000);
|
|
|
|
|
fetchShoutbox();
|
|
|
|
|
setInterval(shoutboxHeartbeat, 10000);
|
|
|
|
|
shoutboxHeartbeat();
|
|
|
|
|
|
|
|
|
|
// =============================
|
|
|
|
|
// Modal ajout de commande
|
|
|
|
|
// =============================
|
|
|
|
|
function openAddCommandModal() {
|
|
|
|
|
document.getElementById('addCommandModal').classList.remove('hidden');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function closeAddCommandModal() {
|
|
|
|
|
document.getElementById('addCommandModal').classList.add('hidden');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// =============================
|
|
|
|
|
// Insertion de variables dans les textareas
|
|
|
|
|
// =============================
|
|
|
|
|
function insertVariable(textareaId, variable) {
|
|
|
|
|
var textarea = document.getElementById(textareaId);
|
|
|
|
|
if (!textarea) return;
|
|
|
|
|
var start = textarea.selectionStart;
|
|
|
|
|
var end = textarea.selectionEnd;
|
|
|
|
|
var text = textarea.value;
|
|
|
|
|
textarea.value = text.substring(0, start) + variable + text.substring(end);
|
|
|
|
|
textarea.selectionStart = textarea.selectionEnd = start + variable.length;
|
|
|
|
|
textarea.focus();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
document.addEventListener('keydown', function(e) {
|
|
|
|
|
if (e.key === 'Escape') closeAddCommandModal();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// =============================
|
|
|
|
|
// Polling infos stream dynamique
|
|
|
|
|
// =============================
|
|
|
|
|
var _streamStartedAt = {{ "'" ~ started_at ~ "'" if started_at else 'null' }};
|
|
|
|
|
var _uptimeInterval = null;
|
|
|
|
|
|
|
|
|
|
function updateUptime() {
|
|
|
|
|
var el = document.getElementById('streamUptime');
|
|
|
|
|
if (!el || !_streamStartedAt) return;
|
|
|
|
|
var start = new Date(_streamStartedAt);
|
|
|
|
|
var now = new Date();
|
|
|
|
|
var diff = Math.max(0, Math.floor((now - start) / 1000));
|
|
|
|
|
var h = Math.floor(diff / 3600);
|
|
|
|
|
var m = Math.floor((diff % 3600) / 60);
|
|
|
|
|
var s = diff % 60;
|
|
|
|
|
el.textContent = (h > 0 ? h + 'h ' : '') + (m < 10 && h > 0 ? '0' : '') + m + 'min ' + (s < 10 ? '0' : '') + s + 's';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function fetchStreamInfo() {
|
|
|
|
|
fetch('{{ url_for("twitch_stream_info") }}')
|
|
|
|
|
.then(function(r) { return r.json(); })
|
|
|
|
|
.then(function(data) {
|
|
|
|
|
var titleEl = document.getElementById('streamTitle');
|
|
|
|
|
var gameEl = document.getElementById('streamGame');
|
|
|
|
|
var viewersEl = document.getElementById('streamViewers');
|
|
|
|
|
var playerViewersEl = document.getElementById('playerViewerCount');
|
|
|
|
|
|
|
|
|
|
if (titleEl) titleEl.textContent = data.title || 'N/A';
|
|
|
|
|
if (gameEl) gameEl.textContent = data.game_name || 'N/A';
|
|
|
|
|
if (viewersEl) viewersEl.textContent = data.viewer_count;
|
|
|
|
|
if (playerViewersEl) playerViewersEl.innerHTML = '• ' + data.viewer_count + ' viewers';
|
|
|
|
|
|
|
|
|
|
if (data.started_at) {
|
|
|
|
|
_streamStartedAt = data.started_at;
|
|
|
|
|
if (!_uptimeInterval) {
|
|
|
|
|
_uptimeInterval = setInterval(updateUptime, 1000);
|
|
|
|
|
}
|
|
|
|
|
updateUptime();
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.catch(function(e) { console.error('Erreur stream info:', e); });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{% if is_live %}
|
|
|
|
|
if (_streamStartedAt) {
|
|
|
|
|
_uptimeInterval = setInterval(updateUptime, 1000);
|
|
|
|
|
updateUptime();
|
|
|
|
|
}
|
|
|
|
|
{% endif %}
|
|
|
|
|
|
|
|
|
|
setInterval(fetchStreamInfo, 15000);
|
|
|
|
|
fetchStreamInfo();
|
|
|
|
|
</script>
|
|
|
|
|
{% endblock %}
|
|
|
|
|