From a8d2a0e0636e47f8db38c26d38965c4658c3c1cc Mon Sep 17 00:00:00 2001 From: Mow910 Date: Sun, 25 Jan 2026 17:45:59 +0100 Subject: [PATCH] =?UTF-8?q?Ajout=20de=20nouvelles=20colonnes=20pour=20la?= =?UTF-8?q?=20personnalisation=20des=20notifications=20YouTube=20dans=20la?= =?UTF-8?q?=20table=20`youtube=5Fnotification`,=20y=20compris=20le=20titre?= =?UTF-8?q?,=20la=20description,=20la=20couleur,=20le=20pied=20de=20page,?= =?UTF-8?q?=20le=20nom=20et=20l'ic=C3=B4ne=20de=20l'auteur,=20ainsi=20que?= =?UTF-8?q?=20des=20options=20pour=20afficher=20la=20miniature=20et=20l'im?= =?UTF-8?q?age.=20Mise=20=C3=A0=20jour=20de=20l'interface=20web=20pour=20p?= =?UTF-8?q?ermettre=20la=20configuration=20de=20ces=20options=20et=20ajout?= =?UTF-8?q?=20d'une=20pr=C3=A9visualisation=20de=20l'embed=20Discord.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- database/__init__.py | 27 ++++ database/models.py | 16 ++- database/schema.sql | 10 +- discordbot/youtube.py | 63 ++++++++-- webapp/templates/youtube.html | 226 +++++++++++++++++++++++++++------- webapp/youtube.py | 26 +++- 6 files changed, 306 insertions(+), 62 deletions(-) diff --git a/database/__init__.py b/database/__init__.py index 9d1d48e..444d20f 100644 --- a/database/__init__.py +++ b/database/__init__.py @@ -33,7 +33,13 @@ def _set_sqlite_pragma(dbapi_connection, connection_record): except Exception: pass +def _tableExists(table_name:str, cursor:Cursor) -> bool: + cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name=?", (table_name,)) + return cursor.fetchone() is not None + def _tableHaveColumn(table_name:str, column_name:str, cursor:Cursor) -> bool: + if not _tableExists(table_name, cursor): + return False cursor.execute(f'PRAGMA table_info({table_name})') columns = cursor.fetchall() return any(col[1] == column_name for col in columns) @@ -64,6 +70,27 @@ def _doPostImportMigration(cursor:Cursor): cursor.execute('INSERT INTO game_bundle(url, name, json) VALUES (?, ?, ?)', (url, name, json.dumps(json_data))) logging.info("suppression de la table temporaire game_bundle_old") _dropTable('game_bundle_old', cursor) + + if _tableExists('youtube_notification', cursor): + logging.info("Migration de la table youtube_notification: ajout des colonnes d'embed") + embed_columns = [ + ('embed_title', 'VARCHAR(256)'), + ('embed_description', 'VARCHAR(2000)'), + ('embed_color', 'VARCHAR(8) DEFAULT "FF0000"'), + ('embed_footer', 'VARCHAR(2048)'), + ('embed_author_name', 'VARCHAR(256)'), + ('embed_author_icon', 'VARCHAR(512)'), + ('embed_thumbnail', 'BOOLEAN DEFAULT 1'), + ('embed_image', 'BOOLEAN DEFAULT 1') + ] + for col_name, col_type in embed_columns: + if not _tableHaveColumn('youtube_notification', col_name, cursor): + try: + cursor.execute(f'ALTER TABLE youtube_notification ADD COLUMN {col_name} {col_type}') + logging.info(f"Colonne {col_name} ajoutée à youtube_notification") + except Exception as e: + logging.error(f"Impossible d'ajouter la colonne {col_name}: {e}") + raise with webapp.app_context(): with open('database/schema.sql', 'r') as f: diff --git a/database/models.py b/database/models.py index e174fce..1562652 100644 --- a/database/models.py +++ b/database/models.py @@ -65,9 +65,17 @@ class YouTubeNotification(db.Model): __tablename__ = 'youtube_notification' id = db.Column(db.Integer, primary_key=True) enable = db.Column(db.Boolean, default=True) - channel_id = db.Column(db.String(128)) # ID de la chaîne YouTube - notify_channel = db.Column(db.Integer) # ID du canal Discord + channel_id = db.Column(db.String(128)) + notify_channel = db.Column(db.Integer) message = db.Column(db.String(2000)) - video_type = db.Column(db.String(16), default='all') # 'all', 'video', 'short' - last_video_id = db.Column(db.String(128)) # ID de la dernière vidéo notifiée + video_type = db.Column(db.String(16), default='all') + last_video_id = db.Column(db.String(128)) + embed_title = db.Column(db.String(256)) + embed_description = db.Column(db.String(2000)) + embed_color = db.Column(db.String(8), default='FF0000') + embed_footer = db.Column(db.String(2048)) + embed_author_name = db.Column(db.String(256)) + embed_author_icon = db.Column(db.String(512)) + embed_thumbnail = db.Column(db.Boolean, default=True) + embed_image = db.Column(db.Boolean, default=True) diff --git a/database/schema.sql b/database/schema.sql index 4f36e26..0af5439 100644 --- a/database/schema.sql +++ b/database/schema.sql @@ -84,5 +84,13 @@ CREATE TABLE IF NOT EXISTS `youtube_notification` ( `notify_channel` INTEGER NOT NULL, `message` VARCHAR(2000) NOT NULL, `video_type` VARCHAR(16) NOT NULL DEFAULT 'all', - `last_video_id` VARCHAR(128) + `last_video_id` VARCHAR(128), + `embed_title` VARCHAR(256), + `embed_description` VARCHAR(2000), + `embed_color` VARCHAR(8) NOT NULL DEFAULT 'FF0000', + `embed_footer` VARCHAR(2048), + `embed_author_name` VARCHAR(256), + `embed_author_icon` VARCHAR(512), + `embed_thumbnail` BOOLEAN NOT NULL DEFAULT TRUE, + `embed_image` BOOLEAN NOT NULL DEFAULT TRUE ); diff --git a/discordbot/youtube.py b/discordbot/youtube.py index 7211fca..aa78962 100644 --- a/discordbot/youtube.py +++ b/discordbot/youtube.py @@ -149,31 +149,76 @@ async def _notifyVideo(notification: YouTubeNotification, video_data: dict, vide message = f"🎥 Nouvelle vidéo de {channel_name}: [{video_title}]({video_url})" logger.info(f"Envoi de notification YouTube: {message}") - bot.loop.create_task(_sendMessage(notification.notify_channel, message, video_url, thumbnail, video_title, channel_name)) + bot.loop.create_task(_sendMessage(notification, message, video_url, thumbnail, video_title, channel_name, video_id, published_at, is_short)) except Exception as e: logger.error(f"Erreur lors de la notification: {e}") -async def _sendMessage(channel_id: int, message: str, video_url: str, thumbnail: str, video_title: str, channel_name: str): +def _format_embed_text(text: str, channel_name: str, video_title: str, video_url: str, video_id: str, thumbnail: str, published_at: str, is_short: bool) -> str: + """Formate un texte d'embed avec les variables disponibles""" + if not text: + return None + try: + return text.format( + channel_name=channel_name or 'Inconnu', + video_title=video_title or 'Sans titre', + video_url=video_url, + video_id=video_id, + thumbnail=thumbnail or '', + published_at=published_at or '', + is_short=is_short + ) + except KeyError: + return text + + +async def _sendMessage(notification: YouTubeNotification, message: str, video_url: str, thumbnail: str, video_title: str, channel_name: str, video_id: str, published_at: str, is_short: bool): from discordbot import bot try: - discord_channel = bot.get_channel(channel_id) + discord_channel = bot.get_channel(notification.notify_channel) if not discord_channel: - logger.error(f"Canal Discord {channel_id} introuvable") + logger.error(f"Canal Discord {notification.notify_channel} introuvable") return import discord + + embed_title = _format_embed_text(notification.embed_title, channel_name, video_title, video_url, video_id, thumbnail, published_at, is_short) if notification.embed_title else video_title + embed_description = _format_embed_text(notification.embed_description, channel_name, video_title, video_url, video_id, thumbnail, published_at, is_short) if notification.embed_description else None + + try: + embed_color = int(notification.embed_color or 'FF0000', 16) + except ValueError: + embed_color = 0xFF0000 + embed = discord.Embed( - title=video_title, + title=embed_title, url=video_url, - color=0xFF0000 + color=embed_color ) - embed.set_author(name=channel_name, icon_url="https://www.youtube.com/img/desktop/yt_1200.png") - if thumbnail: + + if embed_description: + embed.description = embed_description + + author_name = _format_embed_text(notification.embed_author_name, channel_name, video_title, video_url, video_id, thumbnail, published_at, is_short) if notification.embed_author_name else channel_name + author_icon = notification.embed_author_icon if notification.embed_author_icon else "https://www.youtube.com/img/desktop/yt_1200.png" + embed.set_author(name=author_name, icon_url=author_icon) + + if notification.embed_thumbnail and thumbnail: + embed.set_thumbnail(url=thumbnail) + + if notification.embed_image and thumbnail: embed.set_image(url=thumbnail) - await discord_channel.send(message, embed=embed) + if notification.embed_footer: + footer_text = _format_embed_text(notification.embed_footer, channel_name, video_title, video_url, video_id, thumbnail, published_at, is_short) + if footer_text: + embed.set_footer(text=footer_text) + + if message and message.strip(): + await discord_channel.send(message, embed=embed) + else: + await discord_channel.send(embed=embed) logger.info(f"Notification YouTube envoyée avec succès") except Exception as e: diff --git a/webapp/templates/youtube.html b/webapp/templates/youtube.html index 66d2241..e36fdef 100644 --- a/webapp/templates/youtube.html +++ b/webapp/templates/youtube.html @@ -62,52 +62,184 @@ {% endif %}

{{ 'Editer une notification' if notification else 'Ajouter une notification YouTube' }}

-
- - - - - - - - - -

- Vous pouvez coller directement le lien de la chaîne YouTube dans n'importe quel format : -

- Le système extraira automatiquement l'ID de la chaîne. -

- Note : Les notifications utilisent le flux RSS YouTube, aucune clé API n'est nécessaire ! -

-

- Pour le message vous avez accès à ces variables : -

- Le message est au format common-mark dans la limite de ce que - support Discord. - Exemple : 🎥 Nouvelle vidéo de {channel_name} : [{video_title}]({video_url}) -

-
+ +
+
+
+
+ Configuration de base + + + + + + + + + + + +
+ +
+ Personnalisation de l'embed Discord + + + + Variables: {video_title}, {channel_name}, {video_url}, {video_id} + + + + Variables: {video_title}, {channel_name}, {video_url}, {published_at}, {is_short} + + + + + Format: FF0000 (rouge YouTube par défaut) + + + + + + + + + + + + + +
+ + +
+
+ +
+

Prévisualisation de l'embed Discord

+
+
+ + Nom de la chaîne +
+ Titre de la vidéo +
+
+ +
+
+ +
+ +
+ Cette prévisualisation est approximative. L'apparence réelle sur Discord peut varier légèrement. +
+
+ + + +

+ Variables disponibles pour l'embed : +

+

{% endblock %} diff --git a/webapp/youtube.py b/webapp/youtube.py index 0e70118..6f8ae7b 100644 --- a/webapp/youtube.py +++ b/webapp/youtube.py @@ -93,12 +93,24 @@ def addYouTube(): except ValueError: return redirect(url_for("openYouTube") + "?" + urlencode({'msg': "Canal Discord invalide.", 'type': 'error'})) + embed_color = request.form.get('embed_color', 'FF0000').strip().lstrip('#') + if len(embed_color) != 6: + embed_color = 'FF0000' + notification = YouTubeNotification( enable=True, channel_id=channel_id, notify_channel=notify_channel, message=request.form.get('message'), - video_type=request.form.get('video_type', 'all') + video_type=request.form.get('video_type', 'all'), + embed_title=request.form.get('embed_title') or None, + embed_description=request.form.get('embed_description') or None, + embed_color=embed_color, + embed_footer=request.form.get('embed_footer') or None, + embed_author_name=request.form.get('embed_author_name') or None, + embed_author_icon=request.form.get('embed_author_icon') or None, + embed_thumbnail=request.form.get('embed_thumbnail') == 'on', + embed_image=request.form.get('embed_image') == 'on' ) db.session.add(notification) db.session.commit() @@ -141,10 +153,22 @@ def submitEditYouTube(id): except ValueError: return redirect(url_for("openEditYouTube", id=id) + "?" + urlencode({'msg': "Canal Discord invalide.", 'type': 'error'})) + embed_color = request.form.get('embed_color', 'FF0000').strip().lstrip('#') + if len(embed_color) != 6: + embed_color = 'FF0000' + notification.channel_id = channel_id notification.notify_channel = notify_channel notification.message = request.form.get('message') notification.video_type = request.form.get('video_type', 'all') + notification.embed_title = request.form.get('embed_title') or None + notification.embed_description = request.form.get('embed_description') or None + notification.embed_color = embed_color + notification.embed_footer = request.form.get('embed_footer') or None + notification.embed_author_name = request.form.get('embed_author_name') or None + notification.embed_author_icon = request.form.get('embed_author_icon') or None + notification.embed_thumbnail = request.form.get('embed_thumbnail') == 'on' + notification.embed_image = request.form.get('embed_image') == 'on' db.session.commit() return redirect(url_for("openYouTube") + "?" + urlencode({'msg': "Notification modifiée avec succès", 'type': 'success'}))