Merge branch 'main' into youtube-notif

This commit is contained in:
Mow910
2026-02-01 13:03:29 +01:00
committed by GitHub
8 changed files with 696 additions and 1067 deletions

View File

@@ -1,55 +1,101 @@
{% extends "template.html" %}
{% block content %}
<h1>Commandes de Mamie</h1>
<p>Gérez les commandes personnalisées du bot. Ces commandes peuvent être activées sur Discord et/ou Twitch selon vos besoins.</p>
<table>
<thead>
<tr>
<th>Commande</th>
<th>Réponse</th>
<th>Discord</th>
<th>Twitch</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for commande in commandes %}
<tr>
<td>{{ commande.trigger }}</td>
<td>{{ commande.response }}</td>
<td>
<a href="{{ url_for('toggle_discord_commande', commande_id = commande.id) }}" class="icon">
{{ '✅' if commande.discord_enable else '❌' }}
</a>
</td>
<td>
<a href="{{ url_for('toggle_twitch_commande', commande_id = commande.id) }}" class="icon">
{{ '✅' if commande.twitch_enable else '❌' }}
</a>
</td>
<td>
<a href="{{ url_for('delete_commande', commande_id = commande.id) }}" onclick="return confirm('Êtes-vous sûr de vouloir supprimer cette commande ?')">Supprimer</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="mb-6">
<h1 class="text-2xl font-semibold text-slate-800 dark:text-white mb-1">Commandes</h1>
<p class="text-sm text-slate-600 dark:text-slate-400">
Gérez les commandes personnalisées du bot. Ces commandes peuvent être activées sur Discord et/ou Twitch.
</p>
</div>
<h2>Ajouter une commande</h2>
<form action="{{ url_for('add_commande') }}" method="POST">
<label for="trigger">Commande</label>
<input name="trigger" type="text" />
<label for="response">Réponse</label>
<textarea name="response" rows="5" cols="50"></textarea>
<div>
<label for="discord_enable">Discord</label>
<input name="discord_enable" type="checkbox" checked />
<div class="bg-white dark:bg-slate-800 rounded-lg border border-slate-200 dark:border-slate-700 overflow-hidden mb-6">
<div class="overflow-x-auto">
<table class="w-full">
<thead>
<tr class="bg-slate-50 dark:bg-slate-700/50 border-b border-slate-200 dark:border-slate-700">
<th class="px-4 py-3 text-left text-xs font-medium text-slate-500 dark:text-slate-400 uppercase">Commande</th>
<th class="px-4 py-3 text-left text-xs font-medium text-slate-500 dark:text-slate-400 uppercase">Réponse</th>
<th class="px-4 py-3 text-center text-xs font-medium text-slate-500 dark:text-slate-400 uppercase">Discord</th>
<th class="px-4 py-3 text-center text-xs font-medium text-slate-500 dark:text-slate-400 uppercase">Twitch</th>
<th class="px-4 py-3 text-right text-xs font-medium text-slate-500 dark:text-slate-400 uppercase">Actions</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-200 dark:divide-slate-700">
{% for commande in commandes %}
<tr class="hover:bg-slate-50 dark:hover:bg-slate-700/30 transition-colors">
<td class="px-4 py-3">
<code class="px-1.5 py-0.5 bg-slate-100 dark:bg-slate-700 text-slate-700 dark:text-slate-300 rounded text-xs font-mono">{{ commande.trigger }}</code>
</td>
<td class="px-4 py-3 text-slate-600 dark:text-slate-400 text-sm max-w-xs">
<div class="line-clamp-2">{{ commande.response }}</div>
</td>
<td class="px-4 py-3 text-center">
<a href="{{ url_for('toggle_discord_commande', commande_id = commande.id) }}" class="inline-flex" title="{{ 'Désactiver' if commande.discord_enable else 'Activer' }}">
{% if commande.discord_enable %}
<span class="w-5 h-5 text-green-600 dark:text-green-500"></span>
{% else %}
<span class="w-5 h-5 text-slate-400"></span>
{% endif %}
</a>
</td>
<td class="px-4 py-3 text-center">
<a href="{{ url_for('toggle_twitch_commande', commande_id = commande.id) }}" class="inline-flex" title="{{ 'Désactiver' if commande.twitch_enable else 'Activer' }}">
{% if commande.twitch_enable %}
<span class="w-5 h-5 text-green-600 dark:text-green-500"></span>
{% else %}
<span class="w-5 h-5 text-slate-400"></span>
{% endif %}
</a>
</td>
<td class="px-4 py-3 text-right">
<a href="{{ url_for('delete_commande', commande_id = commande.id) }}" onclick="return confirm('Êtes-vous sûr de vouloir supprimer cette commande ?')" class="text-sm text-slate-500 hover:text-red-600 dark:hover:text-red-400 transition-colors">
Supprimer
</a>
</td>
</tr>
{% else %}
<tr>
<td colspan="5" class="px-4 py-8 text-center text-sm text-slate-500 dark:text-slate-400">
Aucune commande configurée
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div>
<label for="twitch_enable">Twitch</label>
<input name="twitch_enable" type="checkbox" unchecked />
</div>
<input type="Submit" value="Ajouter">
</form>
{% endblock %}
</div>
<div class="bg-white dark:bg-slate-800 rounded-lg border border-slate-200 dark:border-slate-700 p-5">
<h2 class="text-lg font-medium text-slate-800 dark:text-white mb-5">Ajouter une commande</h2>
<form action="{{ url_for('add_commande') }}" method="POST" class="space-y-6">
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label for="trigger" class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">Commande</label>
<input type="text" name="trigger" id="trigger" placeholder="!macommande" class="w-full px-3 py-2 bg-slate-50 dark:bg-slate-700 border border-slate-300 dark:border-slate-600 rounded-lg text-sm text-slate-900 dark:text-white placeholder-slate-500 dark:placeholder-slate-400 focus:ring-2 focus:ring-slate-500 focus:border-transparent transition-all">
</div>
<div class="flex items-end gap-6">
<label class="flex items-center gap-3 cursor-pointer">
<input type="checkbox" name="discord_enable" checked class="w-4 h-4 text-slate-600 bg-slate-100 dark:bg-slate-700 border-slate-300 dark:border-slate-600 rounded focus:ring-slate-500 focus:ring-2">
<span class="text-sm text-slate-700 dark:text-slate-300">Discord</span>
</label>
<label class="flex items-center gap-3 cursor-pointer">
<input type="checkbox" name="twitch_enable" class="w-4 h-4 text-slate-600 bg-slate-100 dark:bg-slate-700 border-slate-300 dark:border-slate-600 rounded focus:ring-slate-500 focus:ring-2">
<span class="text-sm text-slate-700 dark:text-slate-300">Twitch</span>
</label>
</div>
</div>
<div>
<label for="response" class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">Réponse</label>
<textarea name="response" id="response" rows="4" placeholder="Le message que le bot enverra..." class="w-full px-3 py-2 bg-slate-50 dark:bg-slate-700 border border-slate-300 dark:border-slate-600 rounded-lg text-sm text-slate-900 dark:text-white placeholder-slate-500 dark:placeholder-slate-400 focus:ring-2 focus:ring-slate-500 focus:border-transparent transition-all resize-none"></textarea>
</div>
<div class="flex justify-end">
<button type="submit" class="px-4 py-2 bg-slate-800 hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600 text-white text-sm font-medium rounded-lg transition-colors">
Ajouter
</button>
</div>
</form>
</div>
{% endblock %}

View File

@@ -1,240 +1,251 @@
{% extends "template.html" %}
{% block content %}
<h1>Configuration de Mamie</h1>
<p>Configurez les tokens Discord, les notifications Humble Bundle et l'API Twitch.</p>
<div class="mb-6">
<h1 class="text-2xl font-semibold text-slate-800 dark:text-white mb-1">Configurations</h1>
<p class="text-sm text-slate-600 dark:text-slate-400">
Paramètres Discord, Twitch et Humble Bundle.
</p>
</div>
<h2>Discord</h2>
<form action="{{ url_for('updateConfiguration') }}" method="POST">
<fieldset>
<legend>API Discord</legend>
<label for="discord_token">Token Discord (caché)</label>
<input name="discord_token" type="password" placeholder="Votre token Discord" />
<small>Nécessite un redémarrage après modification</small>
</fieldset>
<fieldset>
<legend>Messages de bienvenue</legend>
<label for="welcome_enable">
<input type="checkbox" name="welcome_enable" {% if configuration.getValue('welcome_enable') %}checked="checked"{% endif %}>
Activer le message de bienvenue pour les nouveaux membres
</label>
<label for="welcome_channel_id">Canal de bienvenue</label>
<select name="welcome_channel_id">
{% for channel in channels %}
<option value="{{channel.id}}" {% if configuration.getIntValue('welcome_channel_id')==channel.id %}selected="selected"{% endif %}>
{{channel.name}}
</option>
{% endfor %}
</select>
<label for="welcome_message">Message personnalisé de bienvenue</label>
<textarea name="welcome_message" rows="3" placeholder="Bienvenue {member.mention} sur le serveur !">{{ configuration.getValue('welcome_message') }}</textarea>
<small>
<strong>Syntaxes disponibles :</strong><br>
<code>{member.mention}</code> - Mentionne l'utilisateur (@NomUtilisateur)<br>
<code>{member.name}</code> - Nom d'utilisateur (sans mention)<br>
<code>{member.display_name}</code> - Surnom sur le serveur<br>
<code>{member.id}</code> - ID de l'utilisateur<br>
<code>{server.name}</code> - Nom du serveur<br>
<code>{server.member_count}</code> - Nombre total de membres<br>
<code>&lt;#ID_DU_CHANNEL&gt;</code> - Mentionne un salon (ex: &lt;#123456789012345678&gt;)
</small>
</fieldset>
<fieldset>
<legend>Messages de départ</legend>
<label for="leave_enable">
<input type="checkbox" name="leave_enable" {% if configuration.getValue('leave_enable') %}checked="checked"{% endif %}>
Activer le message de départ quand un membre quitte le serveur
</label>
<label for="leave_channel_id">Canal de départ</label>
<select name="leave_channel_id">
{% for channel in channels %}
<option value="{{channel.id}}" {% if configuration.getIntValue('leave_channel_id')==channel.id %}selected="selected"{% endif %}>
{{channel.name}}
</option>
{% endfor %}
</select>
<label for="leave_message">Message personnalisé de départ</label>
<textarea name="leave_message" rows="3" placeholder="{member.mention} a quitté le serveur.">{{ configuration.getValue('leave_message') }}</textarea>
<small>
<strong>Syntaxes disponibles :</strong><br>
<code>{member.mention}</code> - Mentionne l'utilisateur (@NomUtilisateur)<br>
<code>{member.name}</code> - Nom d'utilisateur (sans mention)<br>
<code>{member.display_name}</code> - Surnom sur le serveur<br>
<code>{member.id}</code> - ID de l'utilisateur<br>
<code>{server.name}</code> - Nom du serveur<br>
<code>{server.member_count}</code> - Nombre total de membres<br>
<code>&lt;#ID_DU_CHANNEL&gt;</code> - Mentionne un salon (ex: &lt;#123456789012345678&gt;)
</small>
</fieldset>
<fieldset>
<legend>Modération</legend>
<label for="moderation_enable">
<input type="checkbox" name="moderation_enable" {% if configuration.getValue('moderation_enable') %}checked="checked"{% endif %}>
Activer les commandes d'avertissement (!warn, !unwarn, !inspect)
</label>
<label for="moderation_ban_enable">
<input type="checkbox" name="moderation_ban_enable" {% if configuration.getValue('moderation_ban_enable') %}checked="checked"{% endif %}>
Activer les commandes de bannissement (!ban, !unban)
</label>
<label for="moderation_kick_enable">
<input type="checkbox" name="moderation_kick_enable" {% if configuration.getValue('moderation_kick_enable') %}checked="checked"{% endif %}>
Activer la commande d'expulsion (!kick)
</label>
<label for="moderation_log_channel_id">Canal de logs de modération</label>
<select name="moderation_log_channel_id">
{% for channel in channels %}
<option value="{{channel.id}}" {% if configuration.getIntValue('moderation_log_channel_id')==channel.id %}selected="selected"{% endif %}>
{{channel.name}}
</option>
{% endfor %}
</select>
<small>Toutes les actions de modération seront notifiées dans ce canal</small>
<label>Rôles Staff autorisés</label>
{% set selected_roles = (configuration.getValue('moderation_staff_role_ids') or '').split(',') %}
{% if roles|length > 1 %}
<div class="tabs">
{% for guild_data in roles %}
<button type="button" class="tab-button" onclick="openTab(event, 'guild-{{guild_data.guild_id}}')" {% if loop.first %}id="defaultOpen"{% endif %}>
{{ guild_data.guild_name }}
</button>
{% endfor %}
<div class="bg-white dark:bg-slate-800 rounded-lg border border-slate-200 dark:border-slate-700 mb-6 overflow-hidden">
<div class="px-5 py-4 border-b border-slate-200 dark:border-slate-700">
<h2 class="text-lg font-medium text-slate-800 dark:text-white">Discord</h2>
</div>
<form action="{{ url_for('updateConfiguration') }}" method="POST" class="p-5 space-y-6">
<div>
<label for="discord_token" class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">Token Discord</label>
<input type="password" name="discord_token" id="discord_token" placeholder="Votre token Discord (caché)" class="w-full px-3 py-2 bg-slate-50 dark:bg-slate-700 border border-slate-300 dark:border-slate-600 rounded-lg text-sm text-slate-900 dark:text-white placeholder-slate-500 dark:placeholder-slate-400 focus:ring-2 focus:ring-slate-500 focus:border-transparent transition-all">
<p class="mt-1 text-xs text-amber-600 dark:text-amber-400">Nécessite un redémarrage après modification</p>
</div>
{% endif %}
{% for guild_data in roles %}
<div id="guild-{{guild_data.guild_id}}" class="tab-content" {% if not loop.first %}style="display: none;"{% endif %}>
<div style="max-height: 300px; overflow-y: auto; border: 1px solid #ccc; padding: 10px; border-radius: 5px;">
{% for role in guild_data.roles %}
<label style="display: block; margin: 5px 0;">
<input type="checkbox" name="moderation_staff_role_ids" value="{{role.id}}" {% if role.id|string in selected_roles %}checked="checked"{% endif %}>
{% if role.color.value != 0 %}
<span style="color:#{{ '%06x' % role.color.value }}"></span>
{% else %}
<span></span>
{% endif %}
{{role.name}}
<div class="pt-4 border-t border-slate-200 dark:border-slate-700">
<h3 class="text-sm font-medium text-slate-800 dark:text-white mb-4">Messages de bienvenue</h3>
<label class="flex items-center gap-3 cursor-pointer mb-4">
<input type="checkbox" name="welcome_enable" {% if configuration.getValue('welcome_enable') %}checked{% endif %} class="w-4 h-4 text-slate-600 bg-slate-100 dark:bg-slate-700 border-slate-300 dark:border-slate-600 rounded focus:ring-slate-500">
<span class="text-sm text-slate-700 dark:text-slate-300">Activer le message de bienvenue</span>
</label>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
<div>
<label for="welcome_channel_id" class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">Canal de bienvenue</label>
<select name="welcome_channel_id" id="welcome_channel_id" class="w-full px-3 py-2 bg-slate-50 dark:bg-slate-700 border border-slate-300 dark:border-slate-600 rounded-lg text-sm text-slate-900 dark:text-white focus:ring-2 focus:ring-slate-500 focus:border-transparent transition-all">
{% for channel in channels %}
<option value="{{ channel.id }}" {% if configuration.getIntValue('welcome_channel_id') == channel.id %}selected{% endif %}>{{ channel.name }}</option>
{% endfor %}
</select>
</div>
</div>
<div>
<label for="welcome_message" class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">Message personnalisé</label>
<textarea name="welcome_message" id="welcome_message" rows="2" placeholder="Bienvenue {member.mention} sur le serveur !" class="w-full px-3 py-2 bg-slate-50 dark:bg-slate-700 border border-slate-300 dark:border-slate-600 rounded-lg text-sm text-slate-900 dark:text-white placeholder-slate-500 dark:placeholder-slate-400 focus:ring-2 focus:ring-slate-500 focus:border-transparent transition-all resize-none">{{ configuration.getValue('welcome_message') }}</textarea>
</div>
<div class="mt-3 bg-slate-50 dark:bg-slate-700/50 rounded-lg p-3">
<p class="text-xs font-medium text-slate-600 dark:text-slate-400 mb-2">Variables :</p>
<div class="flex flex-wrap gap-2 text-xs">
<code class="px-1.5 py-0.5 bg-slate-200 dark:bg-slate-600 rounded">{member.mention}</code>
<code class="px-1.5 py-0.5 bg-slate-200 dark:bg-slate-600 rounded">{member.name}</code>
<code class="px-1.5 py-0.5 bg-slate-200 dark:bg-slate-600 rounded">{server.name}</code>
<code class="px-1.5 py-0.5 bg-slate-200 dark:bg-slate-600 rounded">{server.member_count}</code>
</div>
</div>
</div>
<div class="pt-4 border-t border-slate-200 dark:border-slate-700">
<h3 class="text-sm font-medium text-slate-800 dark:text-white mb-4">Messages de départ</h3>
<label class="flex items-center gap-3 cursor-pointer mb-4">
<input type="checkbox" name="leave_enable" {% if configuration.getValue('leave_enable') %}checked{% endif %} class="w-4 h-4 text-slate-600 bg-slate-100 dark:bg-slate-700 border-slate-300 dark:border-slate-600 rounded focus:ring-slate-500">
<span class="text-sm text-slate-700 dark:text-slate-300">Activer le message de départ</span>
</label>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
<div>
<label for="leave_channel_id" class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">Canal de départ</label>
<select name="leave_channel_id" id="leave_channel_id" class="w-full px-3 py-2 bg-slate-50 dark:bg-slate-700 border border-slate-300 dark:border-slate-600 rounded-lg text-sm text-slate-900 dark:text-white focus:ring-2 focus:ring-slate-500 focus:border-transparent transition-all">
{% for channel in channels %}
<option value="{{ channel.id }}" {% if configuration.getIntValue('leave_channel_id') == channel.id %}selected{% endif %}>{{ channel.name }}</option>
{% endfor %}
</select>
</div>
</div>
<div>
<label for="leave_message" class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">Message personnalisé</label>
<textarea name="leave_message" id="leave_message" rows="2" placeholder="{member.mention} a quitté le serveur." class="w-full px-3 py-2 bg-slate-50 dark:bg-slate-700 border border-slate-300 dark:border-slate-600 rounded-lg text-sm text-slate-900 dark:text-white placeholder-slate-500 dark:placeholder-slate-400 focus:ring-2 focus:ring-slate-500 focus:border-transparent transition-all resize-none">{{ configuration.getValue('leave_message') }}</textarea>
</div>
</div>
<div class="pt-4 border-t border-slate-200 dark:border-slate-700">
<h3 class="text-sm font-medium text-slate-800 dark:text-white mb-4">Modération</h3>
<div class="space-y-3 mb-4">
<label class="flex items-center gap-3 cursor-pointer">
<input type="checkbox" name="moderation_enable" {% if configuration.getValue('moderation_enable') %}checked{% endif %} class="w-4 h-4 text-slate-600 bg-slate-100 dark:bg-slate-700 border-slate-300 dark:border-slate-600 rounded focus:ring-slate-500">
<span class="text-sm text-slate-700 dark:text-slate-300">Activer les commandes d'avertissement</span>
</label>
<label class="flex items-center gap-3 cursor-pointer">
<input type="checkbox" name="moderation_ban_enable" {% if configuration.getValue('moderation_ban_enable') %}checked{% endif %} class="w-4 h-4 text-slate-600 bg-slate-100 dark:bg-slate-700 border-slate-300 dark:border-slate-600 rounded focus:ring-slate-500">
<span class="text-sm text-slate-700 dark:text-slate-300">Activer les commandes de bannissement</span>
</label>
<label class="flex items-center gap-3 cursor-pointer">
<input type="checkbox" name="moderation_kick_enable" {% if configuration.getValue('moderation_kick_enable') %}checked{% endif %} class="w-4 h-4 text-slate-600 bg-slate-100 dark:bg-slate-700 border-slate-300 dark:border-slate-600 rounded focus:ring-slate-500">
<span class="text-sm text-slate-700 dark:text-slate-300">Activer la commande d'expulsion</span>
</label>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
<div>
<label for="moderation_log_channel_id" class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">Canal de logs</label>
<select name="moderation_log_channel_id" id="moderation_log_channel_id" class="w-full px-3 py-2 bg-slate-50 dark:bg-slate-700 border border-slate-300 dark:border-slate-600 rounded-lg text-sm text-slate-900 dark:text-white focus:ring-2 focus:ring-slate-500 focus:border-transparent transition-all">
{% for channel in channels %}
<option value="{{ channel.id }}" {% if configuration.getIntValue('moderation_log_channel_id') == channel.id %}selected{% endif %}>{{ channel.name }}</option>
{% endfor %}
</select>
</div>
<div>
<label for="moderation_embed_delete_delay" class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">Délai suppression (sec)</label>
<input type="number" name="moderation_embed_delete_delay" id="moderation_embed_delete_delay" value="{{ configuration.getValue('moderation_embed_delete_delay') or '0' }}" min="0" class="w-full px-3 py-2 bg-slate-50 dark:bg-slate-700 border border-slate-300 dark:border-slate-600 rounded-lg text-sm text-slate-900 dark:text-white focus:ring-2 focus:ring-slate-500 focus:border-transparent transition-all">
</div>
</div>
<div>
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-3">Rôles Staff autorisés</label>
{% set selected_roles = (configuration.getValue('moderation_staff_role_ids') or '').split(',') %}
{% if roles|length > 1 %}
<div class="flex flex-wrap gap-2 mb-3">
{% for guild_data in roles %}
<button type="button" onclick="openTab(event, 'guild-{{ guild_data.guild_id }}')" class="tab-button px-3 py-1.5 text-sm rounded-lg bg-slate-100 dark:bg-slate-700 text-slate-700 dark:text-slate-300 hover:bg-slate-200 dark:hover:bg-slate-600 transition-colors {% if loop.first %}active bg-slate-200 dark:bg-slate-600{% endif %}">
{{ guild_data.guild_name }}
</button>
{% endfor %}
</div>
{% endif %}
{% for guild_data in roles %}
<div id="guild-{{ guild_data.guild_id }}" class="tab-content {% if not loop.first %}hidden{% endif %}">
<div class="max-h-48 overflow-y-auto bg-slate-50 dark:bg-slate-700/50 rounded-lg p-3 space-y-1">
{% for role in guild_data.roles %}
<label class="flex items-center gap-3 cursor-pointer p-2 rounded hover:bg-slate-100 dark:hover:bg-slate-600/50 transition-colors">
<input type="checkbox" name="moderation_staff_role_ids" value="{{ role.id }}" {% if role.id|string in selected_roles %}checked{% endif %} class="w-4 h-4 text-slate-600 bg-slate-100 dark:bg-slate-700 border-slate-300 dark:border-slate-600 rounded focus:ring-slate-500">
{% if role.color.value != 0 %}
<span style="color:#{{ '%06x' % role.color.value }}"></span>
{% else %}
<span class="text-slate-400"></span>
{% endif %}
<span class="text-sm text-slate-700 dark:text-slate-300">{{ role.name }}</span>
</label>
{% endfor %}
</div>
</div>
{% endfor %}
</div>
</div>
{% endfor %}
<div class="pt-4 border-t border-slate-200 dark:border-slate-700">
<button type="submit" class="px-4 py-2 bg-slate-800 hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600 text-white text-sm font-medium rounded-lg transition-colors">
Enregistrer
</button>
</div>
</form>
</div>
<div class="bg-white dark:bg-slate-800 rounded-lg border border-slate-200 dark:border-slate-700 mb-6 overflow-hidden">
<div class="px-5 py-4 border-b border-slate-200 dark:border-slate-700">
<h2 class="text-lg font-medium text-slate-800 dark:text-white">API Twitch</h2>
</div>
<form action="{{ url_for('updateConfiguration') }}" method="POST" class="p-5 space-y-6">
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label for="twitch_client_id" class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">Client ID</label>
<input type="text" name="twitch_client_id" id="twitch_client_id" value="{{ configuration.getValue('twitch_client_id') }}" class="w-full px-3 py-2 bg-slate-50 dark:bg-slate-700 border border-slate-300 dark:border-slate-600 rounded-lg text-sm text-slate-900 dark:text-white focus:ring-2 focus:ring-slate-500 focus:border-transparent transition-all">
</div>
<div>
<label for="twitch_client_secret" class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">Client Secret</label>
<input type="text" name="twitch_client_secret" id="twitch_client_secret" value="{{ configuration.getValue('twitch_client_secret') }}" class="w-full px-3 py-2 bg-slate-50 dark:bg-slate-700 border border-slate-300 dark:border-slate-600 rounded-lg text-sm text-slate-900 dark:text-white focus:ring-2 focus:ring-slate-500 focus:border-transparent transition-all">
</div>
</div>
<small>Sélectionnez un ou plusieurs rôles qui peuvent utiliser les commandes de modération</small>
<div>
<label for="twitch_channel" class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">Chaîne à rejoindre</label>
<input type="text" name="twitch_channel" id="twitch_channel" value="{{ configuration.getValue('twitch_channel') }}" placeholder="#machinTruc" class="w-full px-3 py-2 bg-slate-50 dark:bg-slate-700 border border-slate-300 dark:border-slate-600 rounded-lg text-sm text-slate-900 dark:text-white placeholder-slate-500 dark:placeholder-slate-400 focus:ring-2 focus:ring-slate-500 focus:border-transparent transition-all">
</div>
{% if configuration.getValue('twitch_client_secret') and configuration.getValue('twitch_client_id') %}
<div>
<a href="{{ url_for('twitchRequestToken') }}" class="text-sm text-slate-600 dark:text-slate-400 hover:underline">
Obtenir token et refresh token
</a>
</div>
<script>
function openTab(evt, tabName) {
var i, tabcontent, tabbuttons;
tabcontent = document.getElementsByClassName("tab-content");
for (i = 0; i < tabcontent.length; i++) {
tabcontent[i].style.display = "none";
}
tabbuttons = document.getElementsByClassName("tab-button");
for (i = 0; i < tabbuttons.length; i++) {
tabbuttons[i].className = tabbuttons[i].className.replace(" active", "");
}
document.getElementById(tabName).style.display = "block";
evt.currentTarget.className += " active";
}
document.getElementById("defaultOpen")?.click();
</script>
<style>
.tabs {
overflow: hidden;
border-bottom: 2px solid #ccc;
margin-bottom: 10px;
}
.tab-button {
background-color: #f1f1f1;
border: none;
outline: none;
cursor: pointer;
padding: 10px 20px;
transition: 0.3s;
font-size: 14px;
margin-right: 2px;
}
.tab-button:hover {
background-color: #ddd;
}
.tab-button.active {
background-color: #ccc;
font-weight: bold;
}
.tab-content {
animation: fadeEffect 0.3s;
}
@keyframes fadeEffect {
from {opacity: 0;}
to {opacity: 1;}
}
</style>
<label for="moderation_embed_delete_delay">Délai de suppression des embeds (en secondes)</label>
<input name="moderation_embed_delete_delay" type="number" value="{{ configuration.getValue('moderation_embed_delete_delay') or '0' }}" placeholder="0" min="0" />
<small>Mettre 0 pour ne pas supprimer automatiquement</small>
</fieldset>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label for="twitch_access_token" class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">Access Token</label>
<input type="text" name="twitch_access_token" id="twitch_access_token" value="{{ configuration.getValue('twitch_access_token') }}" readonly class="w-full px-3 py-2 bg-slate-100 dark:bg-slate-700 border border-slate-300 dark:border-slate-600 rounded-lg text-sm text-slate-500 dark:text-slate-400 font-mono">
</div>
<div>
<label for="twitch_refresh_token" class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">Refresh Token</label>
<input type="text" name="twitch_refresh_token" id="twitch_refresh_token" value="{{ configuration.getValue('twitch_refresh_token') }}" readonly class="w-full px-3 py-2 bg-slate-100 dark:bg-slate-700 border border-slate-300 dark:border-slate-600 rounded-lg text-sm text-slate-500 dark:text-slate-400 font-mono">
</div>
</div>
<p class="text-xs text-amber-600 dark:text-amber-400">Nécessite un redémarrage après l'obtention des tokens</p>
{% endif %}
<input type="Submit" value="Enregistrer la configuration Discord">
</form>
<div class="flex items-center gap-4">
<button type="submit" class="px-4 py-2 bg-slate-800 hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600 text-white text-sm font-medium rounded-lg transition-colors">
Enregistrer
</button>
<a href="{{ url_for('twitchConfigurationHelp') }}" class="text-sm text-slate-600 dark:text-slate-400 hover:underline">Besoin d'aide ?</a>
</div>
</form>
</div>
<h2>API Twitch</h2>
<form action="{{ url_for('updateConfiguration') }}" method="POST">
<label for="twitch_client_id">Client ID</label>
<input name="twitch_client_id" type="text" value="{{ configuration.getValue('twitch_client_id') }}" />
<label for="twitch_client_secret">Client Secret</label>
<input name="twitch_client_secret" type="text" value="{{ configuration.getValue('twitch_client_secret') }}" />
<label for="twitch_channel">Chaîne à rejoindre</label>
<input name="twitch_channel" type="text" value="{{ configuration.getValue('twitch_channel') }}"
placeholder="#machinTruc" />
<input type="Submit" value="Enregistrer la configuration Twitch">
<p>
<a href="{{ url_for('twitchConfigurationHelp') }}">Aide</a>
</p>
{% if configuration.getValue('twitch_client_secret') and configuration.getValue('twitch_client_id') %}
<p>
<a href="{{ url_for('twitchRequestToken') }}">Obtenir token et refresh token</a>
</p>
<label for="twitch_access_token">Access Token</label>
<input name="twitch_access_token" type="text" value="{{ configuration.getValue('twitch_access_token') }}"
readonly="readonly" />
<label for="twitch_refresh_token">Refresh Token</label>
<input name="twitch_refresh_token" type="text" value="{{ configuration.getValue('twitch_refresh_token') }}"
readonly="readonly" />
<p>Nécessite un redémarrage après l'obtention des Tokens.</p>
{% endif %}
</form>
<div class="bg-white dark:bg-slate-800 rounded-lg border border-slate-200 dark:border-slate-700 overflow-hidden">
<div class="px-5 py-4 border-b border-slate-200 dark:border-slate-700">
<h2 class="text-lg font-medium text-slate-800 dark:text-white">Humble Bundle</h2>
</div>
<form action="{{ url_for('updateConfiguration') }}" method="POST" class="p-5 space-y-6">
<p class="text-sm text-slate-600 dark:text-slate-400">
Activez les notifications pour recevoir automatiquement les nouveaux packs sur Discord.
</p>
<h2>Humble Bundle</h2>
<form action="{{ url_for('updateConfiguration') }}" method="POST">
<p>Humble Bundle propose régulièrement des bundles de jeux vidéo à des prix réduits. Activez les notifications pour recevoir automatiquement les nouveaux packs disponibles sur votre serveur Discord.</p>
<label class="flex items-center gap-3 cursor-pointer">
<input type="checkbox" name="humble_bundle_enable" {% if configuration.getValue('humble_bundle_enable') %}checked{% endif %} class="w-4 h-4 text-slate-600 bg-slate-100 dark:bg-slate-700 border-slate-300 dark:border-slate-600 rounded focus:ring-slate-500">
<span class="text-sm text-slate-700 dark:text-slate-300">Activer les notifications Humble Bundle</span>
</label>
<label for="humble_bundle_enable">
<input type="checkbox" name="humble_bundle_enable" {% if configuration.getValue('humble_bundle_enable') %}checked="checked"{% endif %}>
Activer les notifications Humble Bundle
</label>
<div>
<label for="humble_bundle_channel" class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">Canal de notification</label>
<select name="humble_bundle_channel" id="humble_bundle_channel" class="w-full px-3 py-2 bg-slate-50 dark:bg-slate-700 border border-slate-300 dark:border-slate-600 rounded-lg text-sm text-slate-900 dark:text-white focus:ring-2 focus:ring-slate-500 focus:border-transparent transition-all">
{% for channel in channels %}
<option value="{{ channel.id }}" {% if configuration.getIntValue('humble_bundle_channel') == channel.id %}selected{% endif %}>{{ channel.name }}</option>
{% endfor %}
</select>
</div>
<label for="humble_bundle_channel">Canal de notification</label>
<select name="humble_bundle_channel">
{% for channel in channels %}
<option value="{{channel.id}}" {% if configuration.getIntValue('humble_bundle_channel')==channel.id %}selected="selected"{% endif %}>
{{channel.name}}
</option>
{% endfor %}
</select>
<button type="submit" class="px-4 py-2 bg-slate-800 hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600 text-white text-sm font-medium rounded-lg transition-colors">
Enregistrer
</button>
</form>
</div>
<input type="Submit" value="Enregistrer la configuration Humble Bundle">
</form>
{% endblock %}
<script>
function openTab(evt, tabName) {
document.querySelectorAll('.tab-content').forEach(el => el.classList.add('hidden'));
document.querySelectorAll('.tab-button').forEach(el => {
el.classList.remove('active', 'bg-slate-200', 'dark:bg-slate-600');
el.classList.add('bg-slate-100', 'dark:bg-slate-700');
});
document.getElementById(tabName).classList.remove('hidden');
evt.currentTarget.classList.add('active', 'bg-slate-200', 'dark:bg-slate-600');
evt.currentTarget.classList.remove('bg-slate-100', 'dark:bg-slate-700');
}
</script>
{% endblock %}

View File

@@ -1,29 +1,44 @@
{% extends "template.html" %}
{% block content %}
<h1>Humeurs de Mamie</h1>
<p>Définissez les statuts Discord qui changeront automatiquement toutes les 10 minutes pour donner de la personnalité à votre bot.</p>
<table>
<thead>
<tr>
<th>Texte</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{% for humeur in humeurs %}
<tr>
<td>{{humeur.text}}</td>
<td><a href="{{ url_for('delHumeur', id = humeur.id) }}" onclick="return confirm('Êtes-vous sûr de vouloir supprimer cette humeur ?')">Supprimer</a></td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="mb-6">
<h1 class="text-2xl font-semibold text-slate-800 dark:text-white mb-1">Humeurs</h1>
<p class="text-sm text-slate-600 dark:text-slate-400">
Statuts Discord qui changeront automatiquement toutes les 10 minutes.
</p>
</div>
<h2>Ajouter une humeur</h2>
<form action="{{ url_for('addHumeur') }}" method="POST">
<label for="text">Texte</label>
<input name="text" type="text" />
<input type="Submit" value="Ajouter">
</form>
{% endblock %}
<div class="bg-white dark:bg-slate-800 rounded-lg border border-slate-200 dark:border-slate-700 overflow-hidden mb-6">
{% if humeurs %}
<ul class="divide-y divide-slate-200 dark:divide-slate-700">
{% for humeur in humeurs %}
<li class="flex items-center justify-between px-4 py-3 hover:bg-slate-50 dark:hover:bg-slate-700/50 transition-colors group">
<span class="text-sm text-slate-700 dark:text-slate-300">{{ humeur.text }}</span>
<a href="{{ url_for('delHumeur', id = humeur.id) }}" onclick="return confirm('Êtes-vous sûr de vouloir supprimer cette humeur ?')" class="p-1.5 text-slate-400 hover:text-red-500 dark:hover:text-red-400 rounded opacity-0 group-hover:opacity-100 transition-all" title="Supprimer">
<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="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path></svg>
</a>
</li>
{% endfor %}
</ul>
{% else %}
<div class="px-4 py-8 text-center">
<p class="text-sm text-slate-500 dark:text-slate-400">Aucune humeur configurée</p>
</div>
{% endif %}
</div>
<div class="bg-white dark:bg-slate-800 rounded-lg border border-slate-200 dark:border-slate-700 p-5">
<h2 class="text-lg font-medium text-slate-800 dark:text-white mb-4">Ajouter une humeur</h2>
<form action="{{ url_for('addHumeur') }}" method="POST">
<div class="flex flex-col sm:flex-row gap-3">
<div class="flex-1">
<input type="text" name="text" id="text" placeholder="Joue à un super jeu..." class="w-full px-3 py-2 bg-slate-50 dark:bg-slate-700 border border-slate-300 dark:border-slate-600 rounded-lg text-sm text-slate-900 dark:text-white placeholder-slate-500 dark:placeholder-slate-400 focus:ring-2 focus:ring-slate-500 focus:border-transparent transition-all">
</div>
<button type="submit" class="px-4 py-2 bg-slate-800 hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600 text-white text-sm font-medium rounded-lg transition-colors whitespace-nowrap">
Ajouter
</button>
</div>
</form>
</div>
{% endblock %}

View File

@@ -1,76 +1,135 @@
{% extends "template.html" %}
{% block content %}
<h1>Alerte Live</h1>
<p>
Liste des chaines surveillées pour les alertes de live twitch.
Le bot vérifie toutes les 5 minutes qui est en live dans la liste en dessous.
Le bot enregistre le status de stream toutes les 5 minutes, quand le status pass de "hors-ligne" à "en ligne" alors
le bot le notifiera sur discord.
Ne peu surveiller qu'au maximum 100 chaines.
</p>
<div class="mb-6">
<h1 class="text-2xl font-semibold text-slate-800 dark:text-white mb-1">Alertes Live</h1>
<p class="text-sm text-slate-600 dark:text-slate-400">
Chaînes Twitch surveillées. Vérification toutes les 5 minutes, maximum 100 chaînes.
</p>
</div>
{% if not alert %}
<h2>Alertes</h2>
<table class="live-alert">
<thead>
<tr>
<th>Chaine</th>
<th>Canal</th>
<th>Message</th>
<th>#</th>
</tr>
</thead>
<tbody>
{% for alert in alerts %}
<tr>
<td>{{alert.login}}</td>
<td>{{alert.notify_channel_name}}</td>
<td>{{alert.message}}</td>
<td>
<a href="{{ url_for('toggleLiveAlert', id = alert.id) }}" class="icon">{{ '✅' if alert.enable else '❌' }}</a>
<a href="{{ url_for('openEditLiveAlert', id = alert.id) }}" class="icon"></a>
<a href="{{ url_for('delLiveAlert', id = alert.id) }}"
onclick="return confirm('Êtes-vous sûr de vouloir supprimer cette alerte ?')" class="icon">🗑</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="bg-white dark:bg-slate-800 rounded-lg border border-slate-200 dark:border-slate-700 overflow-hidden mb-6">
<div class="px-5 py-4 border-b border-slate-200 dark:border-slate-700">
<h2 class="text-lg font-medium text-slate-800 dark:text-white">Alertes configurées</h2>
</div>
<div class="overflow-x-auto">
<table class="w-full">
<thead>
<tr class="bg-slate-50 dark:bg-slate-700/50 border-b border-slate-200 dark:border-slate-700">
<th class="px-4 py-3 text-left text-xs font-medium text-slate-500 dark:text-slate-400 uppercase">Chaîne</th>
<th class="px-4 py-3 text-left text-xs font-medium text-slate-500 dark:text-slate-400 uppercase">Canal Discord</th>
<th class="px-4 py-3 text-left text-xs font-medium text-slate-500 dark:text-slate-400 uppercase">Message</th>
<th class="px-4 py-3 text-right text-xs font-medium text-slate-500 dark:text-slate-400 uppercase">Actions</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-200 dark:divide-slate-700">
{% for alert in alerts %}
<tr class="hover:bg-slate-50 dark:hover:bg-slate-700/30 transition-colors">
<td class="px-4 py-3">
<a href="https://www.twitch.tv/{{ alert.login }}" target="_blank" class="text-sm font-medium text-slate-700 dark:text-slate-300 hover:underline">{{ alert.login }}</a>
</td>
<td class="px-4 py-3">
<span class="text-sm text-slate-600 dark:text-slate-400">#{{ alert.notify_channel_name }}</span>
</td>
<td class="px-4 py-3 text-sm text-slate-600 dark:text-slate-400 max-w-xs">
<div class="line-clamp-2">{{ alert.message }}</div>
</td>
<td class="px-4 py-3">
<div class="flex items-center justify-end gap-2">
<a href="{{ url_for('toggleLiveAlert', id = alert.id) }}" class="text-sm text-slate-500 hover:text-slate-700 dark:hover:text-slate-300 transition-colors" title="{{ 'Désactiver' if alert.enable else 'Activer' }}">
{% if alert.enable %}
<span class="text-green-600 dark:text-green-500">Actif</span>
{% else %}
<span class="text-slate-400">Inactif</span>
{% endif %}
</a>
<a href="{{ url_for('openEditLiveAlert', id = alert.id) }}" class="text-sm text-slate-500 hover:text-slate-700 dark:hover:text-slate-300 transition-colors">
Modifier
</a>
<a href="{{ url_for('delLiveAlert', id = alert.id) }}" onclick="return confirm('Êtes-vous sûr de vouloir supprimer cette alerte ?')" class="text-sm text-slate-500 hover:text-red-600 dark:hover:text-red-400 transition-colors">
Supprimer
</a>
</div>
</td>
</tr>
{% else %}
<tr>
<td colspan="4" class="px-4 py-8 text-center text-sm text-slate-500 dark:text-slate-400">
Aucune alerte configurée
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endif %}
<h2>{{ 'Editer une alerte' if alert else 'Ajouter une alerte de Live' }}</h2>
<form action="{{ url_for('submitEditLiveAlert', id = alert.id) if alert else url_for('addLiveAlert') }}" method="POST">
<label for="login">Chaine</label>
<input name="login" type="text" maxlength="32" required="required" value="{{alert.login if alert}}"/>
<label for="notify_channel">Canal de Notification</label>
<select name="notify_channel">
{% for channel in channels %}
<option value="{{channel.id}}"{% if alert and alert.notify_channel == channel.id %}
selected="selected" {% endif %}>{{channel.name}}</option>
{% endfor %}
</select>
<label for="message">Message</label>
<textarea name="message" rows="5" cols="50" required="required">{{alert.message if alert}}</textarea>
<input type="Submit" value="Ajouter">
<p>
La chaine est le login de la chaine, par exemple <strong>chainesteve</strong> pour <strong>https://www.twitch.tv/chainesteve</strong>.
</p>
<p>
Pour le message vous avez acces à ces variables :
<ul>
<li>{0.user_login} : pour le lien vers la chaine</li>
<li>{0.user_name} : à priviligier pour le text</li>
<li>{0.game_name}</li>
<li>{0.title}</li>
<li>{0.language}</li>
</ul>
Le message est au format <a href="https://commonmark.org/" target="_blank">common-mark</a> dans la limite de ce que
support discord.
Pour mettre un lien vers la chaine : [description](https://www.twitch.tv/{0.user_login})
</p>
</form>
{% endblock %}
<div class="bg-white dark:bg-slate-800 rounded-lg border border-slate-200 dark:border-slate-700 p-5">
<h2 class="text-lg font-medium text-slate-800 dark:text-white mb-5">
{% if alert %}Modifier l'alerte{% else %}Ajouter une alerte{% endif %}
</h2>
<form action="{{ url_for('submitEditLiveAlert', id = alert.id) if alert else url_for('addLiveAlert') }}" method="POST" class="space-y-6">
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<label for="login" class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">Chaîne Twitch</label>
<input type="text" name="login" id="login" maxlength="32" required value="{{ alert.login if alert else '' }}" placeholder="chainesteve" class="w-full px-3 py-2 bg-slate-50 dark:bg-slate-700 border border-slate-300 dark:border-slate-600 rounded-lg text-sm text-slate-900 dark:text-white placeholder-slate-500 dark:placeholder-slate-400 focus:ring-2 focus:ring-slate-500 focus:border-transparent transition-all">
<p class="mt-1 text-xs text-slate-500 dark:text-slate-400">Le login de la chaîne, ex: chainesteve</p>
</div>
<div>
<label for="notify_channel" class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">Canal de Notification</label>
<select name="notify_channel" id="notify_channel" class="w-full px-3 py-2 bg-slate-50 dark:bg-slate-700 border border-slate-300 dark:border-slate-600 rounded-lg text-sm text-slate-900 dark:text-white focus:ring-2 focus:ring-slate-500 focus:border-transparent transition-all">
{% for channel in channels %}
<option value="{{ channel.id }}" {% if alert and alert.notify_channel == channel.id %}selected{% endif %}>{{ channel.name }}</option>
{% endfor %}
</select>
</div>
</div>
<div>
<label for="message" class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">Message de notification</label>
<textarea name="message" id="message" rows="4" required placeholder="🔴 **{0.user_name}** est en live !" class="w-full px-3 py-2 bg-slate-50 dark:bg-slate-700 border border-slate-300 dark:border-slate-600 rounded-lg text-sm text-slate-900 dark:text-white placeholder-slate-500 dark:placeholder-slate-400 focus:ring-2 focus:ring-slate-500 focus:border-transparent transition-all resize-none">{{ alert.message if alert else '' }}</textarea>
</div>
<div class="bg-slate-50 dark:bg-slate-700/50 rounded-lg p-4">
<p class="text-sm font-medium text-slate-700 dark:text-slate-300 mb-3">Variables disponibles :</p>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-2 text-sm">
<div class="flex items-center gap-2">
<code class="px-2 py-0.5 bg-slate-200 dark:bg-slate-600 rounded text-xs font-mono">{0.user_login}</code>
<span class="text-slate-600 dark:text-slate-400">Lien vers la chaîne</span>
</div>
<div class="flex items-center gap-2">
<code class="px-2 py-0.5 bg-slate-200 dark:bg-slate-600 rounded text-xs font-mono">{0.user_name}</code>
<span class="text-slate-600 dark:text-slate-400">Nom du streamer</span>
</div>
<div class="flex items-center gap-2">
<code class="px-2 py-0.5 bg-slate-200 dark:bg-slate-600 rounded text-xs font-mono">{0.game_name}</code>
<span class="text-slate-600 dark:text-slate-400">Jeu en cours</span>
</div>
<div class="flex items-center gap-2">
<code class="px-2 py-0.5 bg-slate-200 dark:bg-slate-600 rounded text-xs font-mono">{0.title}</code>
<span class="text-slate-600 dark:text-slate-400">Titre du stream</span>
</div>
<div class="flex items-center gap-2">
<code class="px-2 py-0.5 bg-slate-200 dark:bg-slate-600 rounded text-xs font-mono">{0.language}</code>
<span class="text-slate-600 dark:text-slate-400">Langue du stream</span>
</div>
</div>
</div>
<div class="flex items-center justify-end gap-3">
{% if alert %}
<a href="{{ url_for('openLiveAlert') }}" class="px-4 py-2 text-slate-700 dark:text-slate-300 text-sm font-medium rounded-lg hover:bg-slate-100 dark:hover:bg-slate-700 transition-colors">
Annuler
</a>
{% endif %}
<button type="submit" class="px-4 py-2 bg-slate-800 hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600 text-white text-sm font-medium rounded-lg transition-colors">
{% if alert %}Enregistrer{% else %}Ajouter{% endif %}
</button>
</div>
</form>
</div>
{% endblock %}

View File

@@ -1,61 +1,124 @@
{% extends "template.html" %}
{% block content %}
<h1>Proton DB</h1>
<p>ProtonDB évalue la compatibilité des jeux Windows sur Linux via Steam Play.</p>
<div class="mb-6">
<h1 class="text-2xl font-semibold text-slate-800 dark:text-white mb-1">ProtonDB</h1>
<p class="text-sm text-slate-600 dark:text-slate-400">
Compatibilité des jeux Windows sur Linux via Steam Play.
</p>
</div>
{% if configuration.getValue('proton_db_enable_enable') %}
<h2>Game alias</h2>
<table>
<thead>
<tr>
<th>Alias</th>
<th>Game</th>
<th>#</th>
</tr>
</thead>
<tbody>
{% for a in aliases %}
<tr>
<td>{{a.alias}}</td>
<td>{{a.name}}</td>
<td><a href="{{ url_for('delGameAlias', id = a.id) }}"
onclick="return confirm('Êtes-vous sûr de vouloir supprimer cet alias ?')">Supprimer</a></td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="bg-white dark:bg-slate-800 rounded-lg border border-slate-200 dark:border-slate-700 overflow-hidden mb-6">
<div class="px-5 py-4 border-b border-slate-200 dark:border-slate-700">
<h2 class="text-lg font-medium text-slate-800 dark:text-white">Alias de jeux</h2>
</div>
<div class="overflow-x-auto">
<table class="w-full">
<thead>
<tr class="bg-slate-50 dark:bg-slate-700/50 border-b border-slate-200 dark:border-slate-700">
<th class="px-4 py-3 text-left text-xs font-medium text-slate-500 dark:text-slate-400 uppercase">Alias</th>
<th class="px-4 py-3 text-left text-xs font-medium text-slate-500 dark:text-slate-400 uppercase">Nom du jeu</th>
<th class="px-4 py-3 text-right text-xs font-medium text-slate-500 dark:text-slate-400 uppercase">Actions</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-200 dark:divide-slate-700">
{% for a in aliases %}
<tr class="hover:bg-slate-50 dark:hover:bg-slate-700/30 transition-colors">
<td class="px-4 py-3">
<code class="px-1.5 py-0.5 bg-slate-100 dark:bg-slate-700 text-slate-700 dark:text-slate-300 rounded text-xs font-mono">{{ a.alias }}</code>
</td>
<td class="px-4 py-3 text-sm text-slate-600 dark:text-slate-400">
{{ a.name }}
</td>
<td class="px-4 py-3 text-right">
<a href="{{ url_for('delGameAlias', id = a.id) }}" onclick="return confirm('Êtes-vous sûr de vouloir supprimer cet alias ?')" class="text-sm text-slate-500 hover:text-red-600 dark:hover:text-red-400 transition-colors">
Supprimer
</a>
</td>
</tr>
{% else %}
<tr>
<td colspan="3" class="px-4 py-8 text-center text-sm text-slate-500 dark:text-slate-400">
Aucun alias configuré
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<h2>Ajouter un Alias</h2>
<form action="{{ url_for('addGameAlias') }}" method="POST">
<label for="alias">Alias</label>
<input name="alias" type="text" maxlength="32" required="required" />
<label for="name">Nom</label>
<input name="name" type="text" maxlength="256" required="required" />
<input type="Submit" value="Ajouter">
<p>Si vous créez un alias <strong>GTA : Grand Theft Auto</strong> alors si un utilisateur rentre la commande
<strong>!protondb GTA 5</strong> cela fera une recherche sur <strong>Grand Theft Auto 5</strong>.
</p>
</form>
<div class="bg-white dark:bg-slate-800 rounded-lg border border-slate-200 dark:border-slate-700 p-5 mb-6">
<h2 class="text-lg font-medium text-slate-800 dark:text-white mb-5">Ajouter un alias</h2>
<form action="{{ url_for('addGameAlias') }}" method="POST" class="space-y-6">
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label for="alias" class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">Alias</label>
<input type="text" name="alias" id="alias" maxlength="32" required placeholder="GTA" class="w-full px-3 py-2 bg-slate-50 dark:bg-slate-700 border border-slate-300 dark:border-slate-600 rounded-lg text-sm text-slate-900 dark:text-white placeholder-slate-500 dark:placeholder-slate-400 focus:ring-2 focus:ring-slate-500 focus:border-transparent transition-all">
</div>
<div>
<label for="name" class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">Nom complet</label>
<input type="text" name="name" id="name" maxlength="256" required placeholder="Grand Theft Auto" class="w-full px-3 py-2 bg-slate-50 dark:bg-slate-700 border border-slate-300 dark:border-slate-600 rounded-lg text-sm text-slate-900 dark:text-white placeholder-slate-500 dark:placeholder-slate-400 focus:ring-2 focus:ring-slate-500 focus:border-transparent transition-all">
</div>
</div>
<div class="flex justify-end">
<button type="submit" class="px-4 py-2 bg-slate-800 hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600 text-white text-sm font-medium rounded-lg transition-colors">
Ajouter
</button>
</div>
</form>
<div class="mt-5 bg-slate-50 dark:bg-slate-700/50 rounded-lg p-4">
<p class="text-sm text-slate-600 dark:text-slate-400">
<strong class="text-slate-800 dark:text-white">Exemple :</strong> Si vous créez un alias GTA → Grand Theft Auto, alors !protondb GTA 5 fera une recherche sur Grand Theft Auto 5.
</p>
</div>
</div>
{% endif %}
<h2>Configuration</h2>
<form action="{{ url_for('updateConfiguration') }}" method="POST">
<label for="proton_db_enable_enable">Activer</label>
<input type="checkbox" name="proton_db_enable_enable" {% if configuration.getValue('proton_db_enable_enable') %}
checked="checked" {% endif %}>
<label>Activer la commande Proton DB</label>
<label for="proton_db_api_id">API ID</label>
<input name="proton_db_api_id" type="text" value="{{ configuration.getValue('proton_db_api_id') }}" />
<label for="proton_db_api_key">Clé API</label>
<input name="proton_db_api_key" type="text" value="{{ configuration.getValue('proton_db_api_key') }}" />
<input type="Submit" value="Définir">
<p>Pour trouver les clés, dans votre navigateur avec l'outil d'inspection ouvert (F12 ou clic droit > Inspecter
l'élément dans Firefox/Chrome) faites une recherche de jeux sur protondb,
puis cherchez les clés dans les requêtes (onglet Réseau/Network),
<a href="/static/img/algolia-key.jpg" target="_blank">comme le montre cet exemple</a>
</p>
</form>
<div class="bg-white dark:bg-slate-800 rounded-lg border border-slate-200 dark:border-slate-700 overflow-hidden">
<div class="px-5 py-4 border-b border-slate-200 dark:border-slate-700">
<h2 class="text-lg font-medium text-slate-800 dark:text-white">Configuration</h2>
</div>
<form action="{{ url_for('updateConfiguration') }}" method="POST" class="p-5 space-y-6">
<label class="flex items-center gap-3 cursor-pointer">
<input type="checkbox" name="proton_db_enable_enable" {% if configuration.getValue('proton_db_enable_enable') %}checked{% endif %} class="w-4 h-4 text-slate-600 bg-slate-100 dark:bg-slate-700 border-slate-300 dark:border-slate-600 rounded focus:ring-slate-500">
<span class="text-sm text-slate-700 dark:text-slate-300">Activer la commande ProtonDB</span>
</label>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label for="proton_db_api_id" class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">API ID</label>
<input type="text" name="proton_db_api_id" id="proton_db_api_id" value="{{ configuration.getValue('proton_db_api_id') }}" class="w-full px-3 py-2 bg-slate-50 dark:bg-slate-700 border border-slate-300 dark:border-slate-600 rounded-lg text-sm text-slate-900 dark:text-white focus:ring-2 focus:ring-slate-500 focus:border-transparent transition-all">
</div>
<div>
<label for="proton_db_api_key" class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">Clé API</label>
<input type="text" name="proton_db_api_key" id="proton_db_api_key" value="{{ configuration.getValue('proton_db_api_key') }}" class="w-full px-3 py-2 bg-slate-50 dark:bg-slate-700 border border-slate-300 dark:border-slate-600 rounded-lg text-sm text-slate-900 dark:text-white focus:ring-2 focus:ring-slate-500 focus:border-transparent transition-all">
</div>
</div>
{% endblock %}
<button type="submit" class="px-4 py-2 bg-slate-800 hover:bg-slate-700 dark:bg-slate-700 dark:hover:bg-slate-600 text-white text-sm font-medium rounded-lg transition-colors">
Enregistrer
</button>
</form>
<div class="px-5 pb-5">
<div class="bg-slate-50 dark:bg-slate-700/50 rounded-lg p-4">
<p class="text-sm font-medium text-slate-800 dark:text-white mb-2">Comment trouver les clés API ?</p>
<ol class="list-decimal list-inside space-y-1 text-sm text-slate-600 dark:text-slate-400">
<li>Ouvrez l'outil d'inspection de votre navigateur (F12)</li>
<li>Allez dans l'onglet Réseau/Network</li>
<li>Faites une recherche de jeu sur ProtonDB</li>
<li>Cherchez les clés dans les requêtes réseau</li>
</ol>
<a href="/static/img/algolia-key.jpg" target="_blank" class="inline-block mt-3 text-sm text-slate-600 dark:text-slate-400 hover:underline">
Voir l'exemple en image
</a>
</div>
</div>
</div>
{% endblock %}

View File

@@ -1,35 +1,92 @@
{% extends "template.html" %}
{% block content %}
<h1>Procédure de configuration de Twitch</h1>
<p>
<strong>Avant toute chose, activez l'authentification à deux facteurs (2FA) :</strong>
<a href="https://help.twitch.tv/s/article/two-factor-authentication?language=en_US" target="_blank">Guide officiel
Twitch pour la 2FA</a>
</p>
<p>
Rendez-vous sur <a href="https://dev.twitch.tv/console" target="_blank">la console d'applications Twitch</a> et
ajoutez une application. Renseignez :
<ul>
<li>URL de redirection : {{token_redirect_url}}</li>
<li>Catégorie : Chat Bot</li>
</ul>
</p>
<div class="mb-6">
<h1 class="text-2xl font-semibold text-slate-800 dark:text-white mb-1">Configuration Twitch</h1>
<p class="text-sm text-slate-600 dark:text-slate-400">
Guide étape par étape pour configurer l'API Twitch.
</p>
</div>
<img src="/static/img/twitch-api-01.jpg">
<div class="space-y-4">
<div class="bg-white dark:bg-slate-800 rounded-lg border border-slate-200 dark:border-slate-700 overflow-hidden">
<div class="px-5 py-4 border-b border-slate-200 dark:border-slate-700">
<div class="flex items-center gap-3">
<span class="w-6 h-6 rounded-full bg-slate-200 dark:bg-slate-700 flex items-center justify-center text-slate-600 dark:text-slate-400 text-xs font-medium">1</span>
<h2 class="font-medium text-slate-800 dark:text-white">Activer l'authentification à deux facteurs (2FA)</h2>
</div>
</div>
<div class="p-5">
<p class="text-sm text-slate-600 dark:text-slate-400 mb-4">
Avant de créer une application Twitch, vous devez activer la 2FA sur votre compte.
</p>
<a href="https://help.twitch.tv/s/article/two-factor-authentication?language=en_US" target="_blank" class="inline-flex items-center gap-2 text-sm text-slate-600 dark:text-slate-400 hover:text-slate-800 dark:hover:text-white">
<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="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"></path></svg>
Guide officiel Twitch
</a>
</div>
</div>
<p>
Créez le bot. Puis, de retour à la liste, éditez-le en cliquant sur Gérer. Puis cliquez sur <strong>Nouveau
Secret</strong>. Vous trouverez ici le <strong>Client ID</strong> et le <strong>Client Secret</strong>.
</p>
<div class="bg-white dark:bg-slate-800 rounded-lg border border-slate-200 dark:border-slate-700 overflow-hidden">
<div class="px-5 py-4 border-b border-slate-200 dark:border-slate-700">
<div class="flex items-center gap-3">
<span class="w-6 h-6 rounded-full bg-slate-200 dark:bg-slate-700 flex items-center justify-center text-slate-600 dark:text-slate-400 text-xs font-medium">2</span>
<h2 class="font-medium text-slate-800 dark:text-white">Créer une application Twitch</h2>
</div>
</div>
<div class="p-5 space-y-4">
<p class="text-sm text-slate-600 dark:text-slate-400">
Rendez-vous sur la console Twitch et créez une nouvelle application :
</p>
<a href="https://dev.twitch.tv/console" target="_blank" class="inline-flex items-center gap-2 px-3 py-1.5 bg-slate-800 dark:bg-slate-700 text-white text-sm rounded-lg hover:bg-slate-700 dark:hover:bg-slate-600 transition-colors">
Console Twitch
</a>
<img src="/static/img/twitch-api-02.jpg">
<div class="bg-slate-50 dark:bg-slate-700/50 rounded-lg p-4 space-y-2 text-sm">
<div><span class="text-slate-500 dark:text-slate-400">URL de redirection :</span> <code class="ml-1 px-1.5 py-0.5 bg-slate-200 dark:bg-slate-600 rounded text-xs">{{ token_redirect_url }}</code></div>
<div><span class="text-slate-500 dark:text-slate-400">Catégorie :</span> <span class="ml-1 text-slate-800 dark:text-white">Chat Bot</span></div>
</div>
<p>
Ensuite, retournez sur la page de <a href="{{url_for('openConfigurations')}}">Configuration</a>, après avoir
enregistré le <strong>Client ID</strong> et le <strong>Client Secret</strong>, cliquez sur le lien <strong>Obtenir
token et refresh token</strong>. Si tout se passe bien les champs <strong>Access Token</strong> et
<strong>Refresh Token</strong> sont remplis.
</p>
<div class="rounded-lg overflow-hidden border border-slate-200 dark:border-slate-700">
<img src="/static/img/twitch-api-01.jpg" alt="Création d'application Twitch" class="w-full">
</div>
</div>
</div>
{% endblock %}
<div class="bg-white dark:bg-slate-800 rounded-lg border border-slate-200 dark:border-slate-700 overflow-hidden">
<div class="px-5 py-4 border-b border-slate-200 dark:border-slate-700">
<div class="flex items-center gap-3">
<span class="w-6 h-6 rounded-full bg-slate-200 dark:bg-slate-700 flex items-center justify-center text-slate-600 dark:text-slate-400 text-xs font-medium">3</span>
<h2 class="font-medium text-slate-800 dark:text-white">Récupérer les identifiants</h2>
</div>
</div>
<div class="p-5 space-y-4">
<p class="text-sm text-slate-600 dark:text-slate-400">
Cliquez sur <strong class="text-slate-800 dark:text-white">Gérer</strong> puis <strong class="text-slate-800 dark:text-white">Nouveau Secret</strong> pour obtenir le Client ID et Client Secret.
</p>
<div class="rounded-lg overflow-hidden border border-slate-200 dark:border-slate-700">
<img src="/static/img/twitch-api-02.jpg" alt="Récupération des identifiants" class="w-full">
</div>
</div>
</div>
<div class="bg-white dark:bg-slate-800 rounded-lg border border-slate-200 dark:border-slate-700 overflow-hidden">
<div class="px-5 py-4 border-b border-slate-200 dark:border-slate-700">
<div class="flex items-center gap-3">
<span class="w-6 h-6 rounded-full bg-slate-200 dark:bg-slate-700 flex items-center justify-center text-slate-600 dark:text-slate-400 text-xs font-medium">4</span>
<h2 class="font-medium text-slate-800 dark:text-white">Configurer Mamie Henriette</h2>
</div>
</div>
<div class="p-5 space-y-4">
<ol class="list-decimal list-inside space-y-1 text-sm text-slate-600 dark:text-slate-400">
<li>Entrez le Client ID et Client Secret</li>
<li>Cliquez sur Enregistrer</li>
<li>Cliquez sur "Obtenir token et refresh token"</li>
</ol>
<a href="{{ url_for('openConfigurations') }}" class="inline-flex items-center gap-2 px-3 py-1.5 bg-slate-800 dark:bg-slate-700 text-white text-sm rounded-lg hover:bg-slate-700 dark:hover:bg-slate-600 transition-colors">
Aller à la Configuration
</a>
</div>
</div>
</div>
{% endblock %}