Files
MamieHenriette/twitchbot/link_filter.py
T
Mow910andCursor b274dcaa51 Ajout de fonctionnalités majeures Twitch, Discord et interface web
Nouvelles fonctionnalités :
- Système de modération Twitch complet (bans, timeouts, avertissements)
- Filtre de liens intelligent pour Twitch avec whitelist/blacklist
- Notifications d'événements Twitch (follows, subs, raids, etc.)
- Système Freeloot Discord avec flux RSS dédié
- Salons automatiques Discord (création/suppression dynamique)
- Authentification utilisateur pour l'interface web (login/register)
- Gestion des utilisateurs et permissions
- Interface de modération Twitch dans la webapp
- Interface de gestion des événements Twitch
- Configuration des paramètres utilisateur
- Migration BDD pour les mots bannis

Améliorations de l'interface :
- Refonte complète des templates (configurations, commandes, humeurs, etc.)
- Nouvelle page de settings utilisateur
- Page de gestion des utilisateurs (admin)
- Page d'erreur 403 personnalisée
- Amélioration de la navigation et du design global
- Intégration de nouvelles sections dans le menu principal

Modifications techniques :
- Ajout de nouveaux modèles en base de données
- Extension des helpers database
- Mise à jour des dépendances (requirements.txt)
- Amélioration de la gestion des annonces Twitch
- Refactorisation du code pour meilleure maintenabilité

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 22:37:22 +01:00

167 lines
5.5 KiB
Python

import re
import logging
from datetime import datetime, timedelta
from twitchAPI.twitch import Twitch
from twitchAPI.chat import ChatMessage
from database import db
from database.models import TwitchLinkFilter, TwitchAllowedDomain, TwitchPermit, TwitchAllowedUser
from twitchbot.moderation import _log_action, _get_broadcaster_id, _get_moderator_id, _get_user_id, _is_moderator
from webapp import webapp
logger = logging.getLogger('twitch-link-filter')
logger.setLevel(logging.INFO)
URL_REGEX = re.compile(r'https?://[^\s]+|(?:www\.)?[a-zA-Z0-9-]+\.[a-zA-Z]{2,}(?:/[^\s]*)?')
def _get_filter_config():
"""Retourne un dictionnaire avec la config du filtre de liens"""
with webapp.app_context():
config = TwitchLinkFilter.query.first()
if not config:
config = TwitchLinkFilter(enabled=False)
db.session.add(config)
db.session.commit()
# Retourner un dict pour éviter DetachedInstanceError
return {
'enabled': config.enabled,
'allow_subscribers': config.allow_subscribers,
'allow_vips': config.allow_vips,
'allow_moderators': config.allow_moderators,
'timeout_duration': config.timeout_duration,
'warning_message': config.warning_message
}
def _get_allowed_domains():
with webapp.app_context():
return [d.domain.lower() for d in TwitchAllowedDomain.query.all()]
def _is_user_whitelisted(username: str) -> bool:
with webapp.app_context():
return TwitchAllowedUser.query.filter_by(username=username.lower()).first() is not None
def _has_valid_permit(username: str) -> bool:
with webapp.app_context():
permit = TwitchPermit.query.filter_by(username=username.lower()).first()
if permit and permit.expires_at > datetime.now():
return True
if permit and permit.expires_at <= datetime.now():
db.session.delete(permit)
db.session.commit()
return False
def _extract_domain(url: str) -> str:
url = url.lower()
url = re.sub(r'^https?://', '', url)
url = re.sub(r'^www\.', '', url)
return url.split('/')[0]
def _is_domain_allowed(url: str, allowed_domains: list) -> bool:
domain = _extract_domain(url)
for allowed in allowed_domains:
if domain == allowed or domain.endswith('.' + allowed):
return True
return False
async def check_message_for_links(msg: ChatMessage, twitch: Twitch) -> bool:
config = _get_filter_config()
if not config['enabled']:
return True
if config['allow_moderators'] and (msg.user.mod or msg.user.name.lower() == msg.room.name.lower()):
return True
if config['allow_vips'] and msg.user.vip:
return True
if config['allow_subscribers'] and msg.user.subscriber:
return True
if _is_user_whitelisted(msg.user.name):
return True
urls = URL_REGEX.findall(msg.text)
if not urls:
return True
if _has_valid_permit(msg.user.name):
with webapp.app_context():
permit = TwitchPermit.query.filter_by(username=msg.user.name.lower()).first()
if permit:
db.session.delete(permit)
db.session.commit()
return True
allowed_domains = _get_allowed_domains()
for url in urls:
if not _is_domain_allowed(url, allowed_domains):
await _handle_unauthorized_link(msg, twitch, config, url)
return False
return True
async def _handle_unauthorized_link(msg: ChatMessage, twitch: Twitch, config: dict, url: str):
broadcaster_id = await _get_broadcaster_id(twitch, msg.room.name)
moderator_id = await _get_moderator_id(twitch)
user_id = await _get_user_id(twitch, msg.user.name)
if user_id and config['timeout_duration'] > 0:
try:
await twitch.ban_user(broadcaster_id, moderator_id, user_id, reason="Lien non autorise", duration=config['timeout_duration'])
except Exception as e:
logger.error(f"Erreur timeout link filter: {e}")
try:
await twitch.delete_chat_messages(broadcaster_id, moderator_id, message_id=msg.id)
except Exception as e:
logger.error(f"Erreur suppression message: {e}")
if config['warning_message']:
await msg.reply(config['warning_message'])
_log_action("link_blocked", "AutoMod", msg.user.name, _extract_domain(url))
logger.info(f"Lien bloque de {msg.user.name}: {url}")
async def permit_command(msg: ChatMessage, twitch: Twitch):
if not _is_moderator(msg):
return
args = msg.text.split()[1:]
if len(args) < 1:
await msg.reply("Usage: !permit <viewer> [minutes]")
return
username = args[0].lstrip('@').lower()
duration = 60
if len(args) >= 2:
try:
duration = int(args[1]) * 60
except ValueError:
duration = 60
expires_at = datetime.now() + timedelta(seconds=duration)
with webapp.app_context():
existing = TwitchPermit.query.filter_by(username=username).first()
if existing:
existing.expires_at = expires_at
else:
permit = TwitchPermit(username=username, expires_at=expires_at)
db.session.add(permit)
db.session.commit()
_log_action("permit", msg.user.name, username, f"{duration}s")
await msg.reply(f"@{username} peut poster un lien pendant {duration // 60} minute(s)")
logger.info(f"Permit accorde a {username} par {msg.user.name}")