diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index 4e158b7..1f2aae8 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -2,7 +2,9 @@ name: Create and publish a Docker image on: push: - branches: ['*'] + branches: ['main'] + pull_request: + branches: ['main'] env: REGISTRY: ghcr.io @@ -34,9 +36,8 @@ jobs: tags: | type=ref,event=branch type=ref,event=pr - type=sha,prefix={{branch}}- + type=sha,prefix={{branch}}-,enable={{is_default_branch}} type=raw,value=latest,enable={{is_default_branch}} - type=raw,value={{branch}},enable=${{ github.ref_name != 'main' }} - name: Build and push Docker image uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4 diff --git a/database/models.py b/database/models.py index 1cfca05..ed24f51 100644 --- a/database/models.py +++ b/database/models.py @@ -19,6 +19,14 @@ class GameBundle(db.Model): name = db.Column(db.String(256)) json = db.Column(db.String(1024)) +class LiveAlert(db.Model): + id = db.Column(db.Integer, primary_key=True) + enable = db.Column(db.Boolean, default=True) + online = db.Column(db.Boolean, default=False) + login = db.Column(db.String(128)) + notify_channel = db.Column(db.Integer) + message = db.Column(db.String(2000)) + class Message(db.Model): id = db.Column(db.Integer, primary_key=True) enable = db.Column(db.Boolean, default=False) diff --git a/database/schema.sql b/database/schema.sql index 24ff873..2777bba 100644 --- a/database/schema.sql +++ b/database/schema.sql @@ -22,6 +22,15 @@ CREATE TABLE IF NOT EXISTS `humeur` ( `text` VARCHAR(256) NULL ); +CREATE TABLE IF NOT EXISTS live_alert ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + `enable` BOOLEAN NOT NULL DEFAULT TRUE, + `online` BOOLEAN NOT NULL DEFAULT FALSE, + `login` VARCHAR(128) UNIQUE NOT NULL, + `notify_channel` INTEGER NOT NULL, + `message` VARCHAR(2000) NOT NULL +); + CREATE TABLE IF NOT EXISTS `message` ( id INTEGER PRIMARY KEY AUTOINCREMENT, `enable` BOOLEAN NOT NULL DEFAULT FALSE, diff --git a/discordbot/__init__.py b/discordbot/__init__.py index 9b54326..837161c 100644 --- a/discordbot/__init__.py +++ b/discordbot/__init__.py @@ -6,7 +6,7 @@ import random from database import db from database.helpers import ConfigurationHelper from database.models import Configuration, Humeur, Commande -from discord import Message +from discord import Message, TextChannel from discordbot.humblebundle import checkHumbleBundleAndNotify from protondb import searhProtonDb @@ -36,6 +36,14 @@ class DiscordBot(discord.Client): # toutes les 30 minutes await asyncio.sleep(30*60) + def getAllTextChannel(self) -> list[TextChannel]: + channels = [] + for channel in self.get_all_channels(): + if isinstance(channel, TextChannel): + channels.append(channel) + return channels + + def begin(self) : token = Configuration.query.filter_by(key='discord_token').first() if token : diff --git a/twitchbot/__init__.py b/twitchbot/__init__.py index 7103c38..529bf0d 100644 --- a/twitchbot/__init__.py +++ b/twitchbot/__init__.py @@ -7,7 +7,7 @@ from twitchAPI.type import AuthScope, ChatEvent from twitchAPI.chat import Chat, ChatEvent, ChatMessage, EventData from database.helpers import ConfigurationHelper - +from twitchbot.live_alert import checkOnlineStreamer from webapp import webapp USER_SCOPE = [AuthScope.CHAT_READ, AuthScope.CHAT_EDIT] @@ -16,6 +16,8 @@ async def _onReady(ready_event: EventData): logging.info('Bot Twitch prêt') with webapp.app_context(): await ready_event.chat.join_room(ConfigurationHelper().getValue('twitch_channel')) + asyncio.get_event_loop().create_task(twitchBot._checkOnlineStreamers()) + async def _onMessage(msg: ChatMessage): logging.info(f'Dans {msg.room.name}, {msg.user.name} a dit : {msg.text}') @@ -48,6 +50,16 @@ class TwitchBot() : else: logging.info("Twitch n'est pas configuré") + async def _checkOnlineStreamers(self): + # pas bon faudrait faire un truc mieux + while True : + try: + await checkOnlineStreamer(self.twitch) + except Exception as e: + logging.error(f'Erreur lors lors du check des streamers online : {e}') + # toutes les 5 minutes + await asyncio.sleep(5*60) + def begin(self): asyncio.run(self._connect()) diff --git a/twitchbot/live_alert.py b/twitchbot/live_alert.py new file mode 100644 index 0000000..1292aa8 --- /dev/null +++ b/twitchbot/live_alert.py @@ -0,0 +1,36 @@ +from twitchAPI.twitch import Twitch +from twitchAPI.object.api import Stream + +from database import db +from database.models import LiveAlert +from discordbot import bot +from webapp import webapp + + +async def checkOnlineStreamer(twitch: Twitch) : + with webapp.app_context() : + alerts : list[LiveAlert] = LiveAlert.query.all() + streams = await _retreiveStreams(twitch, alerts) + for alert in alerts : + stream = next((s for s in streams if s.user_login == alert.login), None) + if stream : + if not alert.online and alert.enable : + await _notifyAlert(alert, stream) + alert.online = True + else : + alert.online = False + db.session.commit() + +async def _notifyAlert(alert : LiveAlert, stream : Stream): + message : str = alert.message.format(stream) + bot.loop.create_task(_sendMessage(alert.notify_channel, message)) + +async def _sendMessage(channel : int, message : str) : + await bot.get_channel(channel).send(message) + +async def _retreiveStreams(twitch: Twitch, alerts : list[LiveAlert]) -> list[Stream] : + streams : list[Stream] = [] + async for stream in twitch.get_streams(user_login = [alert.login for alert in alerts]): + streams.append(stream) + return streams + diff --git a/webapp/__init__.py b/webapp/__init__.py index c6f55d1..357676a 100644 --- a/webapp/__init__.py +++ b/webapp/__init__.py @@ -2,4 +2,4 @@ from flask import Flask webapp = Flask(__name__) -from webapp import commandes, configurations, index, humeurs, messages, moderation, protondb, twitch_auth +from webapp import commandes, configurations, index, humeurs, protondb, live_alert, twitch_auth diff --git a/webapp/configurations.py b/webapp/configurations.py index c795ad8..93d5d0b 100644 --- a/webapp/configurations.py +++ b/webapp/configurations.py @@ -3,15 +3,10 @@ from webapp import webapp from database import db from database.helpers import ConfigurationHelper from discordbot import bot -from discord import TextChannel @webapp.route("/configurations") def openConfigurations(): - channels = [] - for channel in bot.get_all_channels(): - if isinstance(channel, TextChannel): - channels.append(channel) - return render_template("configurations.html", configuration = ConfigurationHelper(), channels = channels) + return render_template("configurations.html", configuration = ConfigurationHelper(), channels = bot.getAllTextChannel()) @webapp.route("/configurations/update", methods=['POST']) def updateConfiguration(): diff --git a/webapp/live_alert.py b/webapp/live_alert.py new file mode 100644 index 0000000..bd365ff --- /dev/null +++ b/webapp/live_alert.py @@ -0,0 +1,54 @@ +from flask import render_template, request, redirect, url_for + +from webapp import webapp +from database import db +from database.models import LiveAlert +from discordbot import bot + + +@webapp.route("/live-alert") +def openLiveAlert(): + alerts : list[LiveAlert] = LiveAlert.query.all() + channels = bot.getAllTextChannel() + for alert in alerts : + for channel in channels: + if alert.notify_channel == channel.id : + alert.notify_channel_name = channel.name + return render_template("live-alert.html", alerts = alerts, channels = channels) + +@webapp.route("/live-alert/add", methods=['POST']) +def addLiveAlert(): + alert = LiveAlert(enable = True, login = request.form.get('login'), notify_channel = request.form.get('notify_channel'), message = request.form.get('message')) + db.session.add(alert) + db.session.commit() + return redirect(url_for("openLiveAlert")) + +@webapp.route("/live-alert/toggle/") +def toggleLiveAlert(id): + alert : LiveAlert = LiveAlert.query.get_or_404(id) + alert.enable = not alert.enable + db.session.commit() + return redirect(url_for("openLiveAlert")) + +@webapp.route("/live-alert/edit/") +def openEditLiveAlert(id): + alert = LiveAlert.query.get_or_404(id) + channels = bot.getAllTextChannel() + return render_template("live-alert.html", alert = alert, channels = channels) + +@webapp.route("/live-alert/edit/", methods=['POST']) +def submitEditLiveAlert(id): + alert : LiveAlert = LiveAlert.query.get_or_404(id) + alert.login = request.form.get('login') + alert.notify_channel = request.form.get('notify_channel') + alert.message = request.form.get('message') + db.session.commit() + return redirect(url_for("openLiveAlert")) + + +@webapp.route("/live-alert/del/") +def delLiveAlert(id): + alert = LiveAlert.query.get_or_404(id) + db.session.delete(alert) + db.session.commit() + return redirect(url_for("openLiveAlert")) diff --git a/webapp/messages.py b/webapp/messages.py deleted file mode 100644 index 3be8b4d..0000000 --- a/webapp/messages.py +++ /dev/null @@ -1,6 +0,0 @@ -from flask import render_template -from webapp import webapp - -@webapp.route("/messages") -def messages(): - return render_template("messages.html") diff --git a/webapp/moderation.py b/webapp/moderation.py deleted file mode 100644 index 7d59731..0000000 --- a/webapp/moderation.py +++ /dev/null @@ -1,6 +0,0 @@ -from flask import render_template -from webapp import webapp - -@webapp.route("/moderation") -def moderation(): - return render_template("moderation.html") diff --git a/webapp/static/css/style.css b/webapp/static/css/style.css index d546e72..25a3d21 100644 --- a/webapp/static/css/style.css +++ b/webapp/static/css/style.css @@ -7,7 +7,13 @@ table td { text-align: left; vertical-align: top; overflow: hidden; - text-overflow: ellipsis; white-space: normal; - max-width: 250px; } + +table.live-alert tr td:last-child { + white-space: nowrap; +} + +a.icon { + text-decoration: none; +} \ No newline at end of file diff --git a/webapp/templates/commandes.html b/webapp/templates/commandes.html index 99ac545..77568d8 100644 --- a/webapp/templates/commandes.html +++ b/webapp/templates/commandes.html @@ -19,12 +19,12 @@ {{ commande.trigger }} {{ commande.response }} - + {{ '✅' if commande.discord_enable else '❌' }} - + {{ '✅' if commande.twitch_enable else '❌' }} diff --git a/webapp/templates/live-alert.html b/webapp/templates/live-alert.html new file mode 100644 index 0000000..5122700 --- /dev/null +++ b/webapp/templates/live-alert.html @@ -0,0 +1,76 @@ +{% extends "template.html" %} + +{% block content %} +

Alerte Live

+ +

+ 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. +

+ +{% if not alert %} +

Alertes

+ + + + + + + + + + + {% for alert in alerts %} + + + + + + + {% endfor %} + +
ChaineCanalMessage#
{{alert.login}}{{alert.notify_channel_name}}{{alert.message}} + {{ '✅' if alert.enable else '❌' }} + + 🗑 +
+{% endif %} + +

{{ 'Editer une alerte' if alert else 'Ajouter une alerte de Live' }}

+
+ + + + + + + +

+ La chaine est le login de la chaine, par exemple chainesteve pour https://www.twitch.tv/chainesteve. +

+

+ Pour le message vous avez acces à ces variables : +

    +
  • {0.user_login} : pour le lien vers la chaine
  • +
  • {0.user_name} : à priviligier pour le text
  • +
  • {0.game_name}
  • +
  • {0.title}
  • +
  • {0.language}
  • +
+ Le message est au format common-mark dans la limite de ce que + support discord. + Pour mettre un lien vers la chaine : [description](https://www.twitch.fr/{0.user_login}) +

+
+ +{% endblock %} \ No newline at end of file diff --git a/webapp/templates/messages.html b/webapp/templates/messages.html deleted file mode 100644 index 5d5133f..0000000 --- a/webapp/templates/messages.html +++ /dev/null @@ -1,6 +0,0 @@ -{% extends "template.html" %} - -{% block content %} -

Messages de Mamie

-

TODO

-{% endblock %} \ No newline at end of file diff --git a/webapp/templates/moderation.html b/webapp/templates/moderation.html deleted file mode 100644 index 5b7e122..0000000 --- a/webapp/templates/moderation.html +++ /dev/null @@ -1,6 +0,0 @@ -{% extends "template.html" %} - -{% block content %} -

Modération

-

Outils de modération communautaire pour gérer votre serveur Discord (fonctionnalité en développement).

-{% endblock %} \ No newline at end of file diff --git a/webapp/templates/template.html b/webapp/templates/template.html index 628bf7f..beca4fe 100644 --- a/webapp/templates/template.html +++ b/webapp/templates/template.html @@ -18,10 +18,9 @@