# -*- coding: utf-8 -*- """ Een Flask-applicatie die elke Discord-webhook op een dynamisch pad kan ontvangen, weergeeft als HTML, en doorstuurt naar een dynamisch gegenereerde URL op basis van een .env configuratie. Vereisten: pip install Flask python-dotenv requests Markdown waitress jinja2 Hoe te gebruiken: 1. Maak een `.env` bestand aan in dezelfde map. 2. Definieer 'OUTGOING_WEBHOOK_BASE_URL' en optioneel 'OUTGOING_WEBHOOK_PARAMS'. 3. Sla dit bestand op als `app.py`. 4. Voer het uit vanuit je terminal: `python app.py` 5. Stuur een POST-verzoek naar een willekeurig endpoint, bijv. http://127.0.0.1:5001/webhook/any-string-you-want """ import os import datetime import markdown import requests import json from flask import Flask, request, render_template, jsonify, abort, url_for from dotenv import load_dotenv from jinja2 import DictLoader # Laad de omgevingsvariabelen uit het .env-bestand load_dotenv() # Initialiseer de Flask-applicatie app = Flask(__name__) # Lees de configuratie uit de omgevingsvariabelen. OUTGOING_WEBHOOK_BASE_URL = os.getenv('OUTGOING_WEBHOOK_BASE_URL') OUTGOING_WEBHOOK_PARAMS = os.getenv('OUTGOING_WEBHOOK_PARAMS', '') # Standaard lege string if not OUTGOING_WEBHOOK_BASE_URL: print("WAARSCHUWING: OUTGOING_WEBHOOK_BASE_URL niet gevonden in .env. Doorsturen van webhooks is uitgeschakeld.") # In-memory opslag voor de laatst ontvangen webhook-data per ID. # Deze wordt dynamisch gevuld als er nieuwe webhooks binnenkomen. webhook_data_store = {} # --- HTML TEMPLATES (ongewijzigd) --- BASE_TEMPLATE = """ Discord Webhook Weergave
{% block content %}{% endblock %}
""" HOME_TEMPLATE = """ {% extends "base.html" %} {% block content %}

Ontvangen Webhooks

Hieronder staat een lijst van alle webhooks die ten minste één keer een bericht hebben ontvangen. Klik op een webhook om de laatste data te zien.

Inkomende URL's hebben de vorm /webhook/<naam>.

Uitgaande URL: {{ base_url or 'Niet geconfigureerd' }}<naam>{{ params }}

{% endblock %} """ FORWARD_WEBHOOK_TEMPLATE = """ {% if data and data.username != 'Nog geen data' %}
Avatar
{{ data.username or 'Onbekende Bot' }} {{ data.received_at }}
{% if data.content %}
{{ data.content }}
{% endif %} {% for embed in data.embeds %}
{% if embed.author %}
{% if embed.author.icon_url %}{% endif %}{% if embed.author.url %}{{ embed.author.name }}{% else %}{{ embed.author.name }}{% endif %}
{% endif %} {% if embed.title %}
{% if embed.url %}{{ embed.title }}{% else %}{{ embed.title }}{% endif %}
{% endif %} {% if embed.description %}
{{ embed.description | markdown }}
{% endif %} {% if embed.fields %}
{% for field in embed.fields %}
{{ field.name }}
{{ field.value | markdown }}
{% endfor %}
{% endif %}
{% if embed.thumbnail and embed.thumbnail.url %}
Thumbnail
{% endif %} {% if embed.image and embed.image.url %}
Embed Image
{% endif %} {% if embed.footer %} {% endif %}
{% endfor %}
{% else %}

{{ data.content }}

{% endif %} """ UI_WEBHOOK_VIEW_TEMPLATE = """ {% extends "base.html" %} {% block content %} ← Terug naar overzicht

Laatste bericht voor: {{ webhook_id | capitalize }}

{{ content | safe }} {% endblock %} """ # Configureer de Jinja2 loader app.jinja_loader = DictLoader({ 'base.html': BASE_TEMPLATE, 'home.html': HOME_TEMPLATE, 'forward_webhook.html': FORWARD_WEBHOOK_TEMPLATE, 'ui_webhook_view.html': UI_WEBHOOK_VIEW_TEMPLATE, }) @app.template_filter('markdown') def markdown_filter(s): """Rendert markdown en verwijdert de omringende

tags.""" if not s: return "" html = markdown.markdown(s, extensions=['fenced_code', 'nl2br']) if html.startswith('

') and html.endswith('

'): html = html[3:-4] return html def forward_webhook(data, target_url, webhook_id): """Genereert simpele HTML en stuurt dit door naar de opgegeven target_url.""" if not target_url: print(f"Skipping forwarding voor webhook '{webhook_id}': geen uitgaande URL geconfigureerd.") return try: html_parts = [] for embed in data.get('embeds', []): if embed.get('author') and embed.get('author').get('name'): html_parts.append(f"{embed.get('author').get('name')}") if embed.get('title'): title, url = embed.get('title'), embed.get('url') html_parts.append(f"{title}" if url else f"{title}") if embed.get('description'): html_parts.append(markdown_filter(embed.get('description'))) if embed.get('fields'): for field in embed.get('fields'): html_parts.append(f"
{field.get('name', '')}
{markdown_filter(field.get('value', ''))}") if embed.get('image') and embed.get('image').get('url'): html_parts.append(f"
Embed Image") html_content = "
".join(html_parts) plain_text_parts = [] if data.get('username'): plain_text_parts.append(data.get('username')) if data.get('content'): plain_text_parts.append(data.get('content')) for embed in data.get('embeds', []): if embed.get('title'): plain_text_parts.append(embed.get('title')) if embed.get('description'): plain_text_parts.append(embed.get('description')) if embed.get('fields'): for field in embed.get('fields'): plain_text_parts.append(f"{field.get('name', '')}: {field.get('value', '')}") plain_text_body = "\n".join(plain_text_parts) simple_payload = {"text": plain_text_body, "html": html_content, "username": data.get('username')} headers = {'Content-Type': 'application/json'} response = requests.post(target_url, json=simple_payload, headers=headers, timeout=10) response.raise_for_status() print(f"Webhook '{webhook_id}' succesvol doorgestuurd als VEREENVOUDIGDE JSON naar {target_url}. Status: {response.status_code}") except Exception as e: print(f"FOUT: Kon webhook '{webhook_id}' niet doorsturen. Error: {e}") @app.route('/') def list_webhooks(): """Toont de lijst met ontvangen webhooks.""" return render_template( 'home.html', webhooks=webhook_data_store, base_url=OUTGOING_WEBHOOK_BASE_URL, params=OUTGOING_WEBHOOK_PARAMS ) @app.route('/view/') def display_webhook(webhook_id): """Toont de laatst ontvangen data voor een specifieke webhook.""" data = webhook_data_store.get(webhook_id) if not data: # Toon een wacht-bericht als er nog nooit data is ontvangen voor deze ID data = { "username": "Nog geen data", "content": f"Wacht op de eerste webhook op /webhook/{webhook_id}...", "embeds": [], "received_at": "Nooit" } content = render_template('forward_webhook.html', data=data) return render_template('ui_webhook_view.html', content=content, webhook_id=webhook_id) @app.route('/webhook/', methods=['POST']) def receive_webhook(webhook_id): """Ontvangt de JSON-payload, slaat deze op en stuurt deze door.""" if not request.is_json: return jsonify({"error": "Request must be JSON"}), 400 data = request.json data['received_at'] = datetime.datetime.now().strftime('%d-%m-%Y %H:%M:%S') data['webhook_id'] = webhook_id # Sla de data op in de store. Nieuwe ID's worden automatisch toegevoegd. webhook_data_store[webhook_id] = data # Bouw de uitgaande URL dynamisch op, alleen als de base URL is geconfigureerd. if OUTGOING_WEBHOOK_BASE_URL: # Zorg ervoor dat er maar één slash tussen de base url en de id zit. target_url = f"{OUTGOING_WEBHOOK_BASE_URL.rstrip('/')}/{webhook_id}{OUTGOING_WEBHOOK_PARAMS}" forward_webhook(data, target_url, webhook_id) return jsonify({"status": "succes"}), 200 if __name__ == '__main__': port = 5001 print(f"Server wordt gestart op http://127.0.0.1:{port}") print("De app accepteert nu POST-verzoeken op ELK pad onder /webhook/...") print("Bijvoorbeeld: http://127.0.0.1:5001/webhook/jellyfin") print("Druk op CTRL+C om te stoppen.") from waitress import serve serve(app, host='0.0.0.0', port=port)