Pārlūkot izejas kodu

Added custom font functions to alerts page

deadtom 1 nedēļu atpakaļ
vecāks
revīzija
7e743704d2
5 mainītis faili ar 221 papildinājumiem un 72 dzēšanām
  1. 62 5
      ownchatbot/templates/mgmt.html
  2. 51 5
      ownchatbot/web_panels.py
  3. 104 60
      ownchatbot/webhooks.py
  4. 2 1
      pyproject.toml
  5. 2 1
      setup.py

+ 62 - 5
ownchatbot/templates/mgmt.html

@@ -126,7 +126,6 @@
     </div>
     
     <div id='accounts' class="tabcontent">
-
         <body>
             <h3>Manage Viewer Accounts</h3>
             {% if users %}
@@ -465,7 +464,7 @@
     
     <div id='alerts' class="tabcontent">
         <body>
-        <h1>Customize Your Alerts</h1>
+        <h2>Customize Your Alerts</h2>
         <table>
             <thead>
                 <tr style="border-bottom: none;">
@@ -549,8 +548,66 @@
                         <a href="{{ url_for('web_panels.del_alert', alert_type='DONATION_ALERT') }}"><button class="button button2" onclick="openTab(event, 'alerts')"><span style="color: red;">Clear</span></button></a></td>
                     <td>/ocbalert/donation_alert</td>
                 </tr>
+                <tr>
+                    <form id="nd_upload" action="/mgmt/alertupload/SUBSCRIBER_ALERT" method="post" enctype="multipart/form-data">
+                    <td>Subscriber:</td>
+                    {% set subscriber_alert = alerts_dict["SUBSCRIBER_ALERT"] %}
+                    {% if subscriber_alert %}
+                        {% if "webm" in subscriber_alert %}
+                            <td><video height="100" autoplay loop><source src="{{ url_for('web_panels.alerts', alert_name=subscriber_alert) }}" type="video/webm"></video></td>
+                        {% else %}
+                            <td><img src="{{ url_for('web_panels.alerts', alert_name=subscriber_alert) }}"></td>
+                        {% endif %}
+                    {% else %}
+                        <td>Empty</td>
+                    {% endif %}
+                    <td><input type="file" name="SUBSCRIBER_ALERT" accept=".gif, .jpg, .jpeg, .png, .webm" required></td>
+                    <td><button id="nd_upload" class="button button2" type="submit">Upload</button></form>&nbsp
+                        <a href="{{ url_for('web_panels.del_alert', alert_type='SUBSCRIBER_ALERT') }}"><button class="button button2" onclick="openTab(event, 'alerts')"><span style="color: red;">Clear</span></button></a></td>
+                    <td>/ocbalert/subscriber_alert</td>
+                </tr>
         </table>
-        <br><br>
-    </div>    
-    
+        <h2>Alert Message Font</h2>
+        <table>
+            <thead>
+                <tr style="border-bottom: none;">
+                    <th style="width: 40%;"></th>
+                    <th style="width: 20%;"></th>
+                    <th></th>
+                </tr>
+            </thead>
+                {% if alert_font %}
+                <tr>
+                    <td>Current font:  </td>
+                    <td>{{ alert_font }}</td>
+                </tr>
+                {% endif %}
+                <tr>
+                    <form id="font" action="/mgmt/fontupload" method="post" enctype="multipart/form-data">
+                    <td><label for="font">Choose a font:</label></td>
+                    <td>
+                    <select name="font" id="font" onchange="updateFont()">
+                        <option value="Arial">Arial</option>
+                        <option value="Georgia">Georgia</option>
+                        <option value="Times New Roman">Times New Roman</option>
+                        <option value="Courier New">Courier New</option>
+                    </select>
+                    </td>
+                </tr>
+                <tr>
+                    <td>Or upload a custom font file (TTF/OTF):</td>
+                    <td><input type="file" id="font" name="custom_font" accept=".ttf,.otf"></td>
+                </tr>
+                <tr>
+                    <td></td>
+                    <td></td>
+                    <td><button id="font" class="button button2" type="submit">Submit</button></form></td>
+                </tr>
+        </table>
+        </body>
+    </div>
+    <script>
+        document.getElementById('custom_font').value = ''; // Clear file input
+    </script>
+    <br><br>
 </html>

+ 51 - 5
ownchatbot/web_panels.py

@@ -13,6 +13,7 @@ import pkce
 import requests
 from functools import wraps
 import os
+from fontTools.ttLib import TTFont
 
 ocb = Blueprint('web_panels', __name__)
 
@@ -141,6 +142,7 @@ def mgmt():
                            items=todolist_items,
                            todo_css=todo_css,
                            alerts_dict=alerts_dict,
+                           alert_font=alerts_dict['alert_font'],
                            activeTab=active_tab)
 
 
@@ -657,18 +659,62 @@ def del_alert(alert_type):
     return redirect(url_for('web_panels.mgmt', activeTab='alerts'))
 
 
-@ocb.route('/alerts/<alert_name>')  # Route for alerts overlay
+@ocb.route('/alerts/<alert_name>')  # Route for displaying alert images
 def alerts(alert_name):
     return send_from_directory(current_app.config['ALERTS_FOLDER'], alert_name)
 
 
 @ocb.route('/ocbalert/<alert_type>')  # Route for alerts overlay
-def ocb_alerts(alert_type):
+def ocb_alert(alert_type):
     alert_type = alert_type.upper()
     alerts_dict = current_app.config['ALERTS']
-    alert_name = alerts_dict[alert_type]
-    return render_template('ocbalert.html',
-                           alert_name=alert_name)
+    try:
+        alert_name = alerts_dict[alert_type]
+    except KeyError:
+        current_app.logger.info(f'No {alert_type} alert set. Nothing to do.')
+        return f'You have not configured alert type \"{alert_type}\"'
+    if alert_type == 'FOLLOWER_ALERT':
+        return render_template('follower.html',
+                               alert_name=alert_name)
+    elif alert_type == 'DONATION_ALERT':
+        return render_template('donation.html',
+                               alert_name=alert_name)
+    elif alert_type == 'SUBSCRIBER_ALERT':
+        return render_template('subscriber.html',
+                               alert_name=alert_name)
+    else:
+        return render_template('ocbalert.html',
+                               alert_name=alert_name)
+
+
+@ocb.route('/mgmt/fontupload', methods=['GET', 'POST'])
+def font_upload():
+    alerts_dict = current_app.config['ALERTS']
+    if request.method == 'POST':
+        selected_font = request.form.get('font')
+        uploaded_file = request.files.get('custom_font')
+        current_app.logger.info(f"Selected font: {selected_font}")
+        alerts_dict['alert_font'] = selected_font
+        if save_alerts(alerts_dict):  # Save new alerts.py
+            current_app.logger.info(f'Added {selected_font} font to alerts.py.')
+        if uploaded_file:
+            uploaded_path = os.path.join(current_app.config['ALERTS_FOLDER'], uploaded_file.filename)
+            uploaded_file.save(uploaded_path)
+            try:
+                font = TTFont(uploaded_path)
+                name_table = font['name']
+                for record in name_table.names:
+                    if record.nameID == 1:  # The nameID for the font family
+                        selected_font = record.toStr()
+                        current_app.logger.info(f"Uploaded font: {selected_font}")
+                        alerts_dict['alert_font'] = selected_font
+                        if save_alerts(alerts_dict):  # Save new alerts.py
+                            current_app.logger.info(f'Added {selected_font} font to alerts.py.')
+            except Exception as gfnerror:
+                current_app.logger.error(f"Error reading font file: {gfnerror}")
+        return redirect(url_for('web_panels.mgmt', activeTab='alerts'))
+
+    return redirect(url_for('web_panels.mgmt', activeTab='alerts'))
 
 
 @ocb.route('/goals', methods=['GET'])  # Route for goals overlay

+ 104 - 60
ownchatbot/webhooks.py

@@ -12,63 +12,16 @@ import random
 ocb = Blueprint('webhooks', __name__)
 
 
+followers = []
+donations = []
+subscribers = []
+
+
 def format(rawjson):  # Make data legible
     formatted_data = json.dumps(rawjson, indent=4)
     return formatted_data
 
 
-@ocb.route('/kofiHook', methods=["POST"])
-def kofiHook():
-    current_app.logger.info(f'----------------------------------------------------------------------------')
-    current_app.logger.info(f'Kofi request')
-    if request.content_type == 'application/x-www-form-urlencoded':
-        raw_data = request.form.get('data')  # Get the kofi data
-        if raw_data:
-            raw_data = json.loads(raw_data)
-            is_authed = raw_data['verification_token']
-            if is_authed == current_app.config['KOFI_TOKEN']:
-                type = raw_data['type']
-                is_public = raw_data['is_public']
-                new_sub = raw_data['is_first_subscription_payment']
-                message = raw_data['message']
-                shop_items = raw_data['shop_items']
-                from_name = raw_data['from_name']
-                email = raw_data['email']
-                amount = raw_data['amount']
-                sub_payment = raw_data['is_subscription_payment']
-                first_sub = raw_data['is_first_subscription_payment']
-                tier_name = raw_data['tier_name']
-                if type == 'Shop Order':
-                    current_app.logger.info(f'{from_name} purchased {format(shop_items)}\nMessage: {message}\n')
-                if type == 'Donation':
-                    donation_info = [is_public, from_name, email, amount, message]
-                    donation_points = current_app.config['KOFI_SETTINGS']['donation_points']
-                    accept_donation(donation_info, donation_points)
-                if type == 'Subscription':
-                    if current_app.config['KOFI_SETTINGS']['subs']:  # Check that subscriptions are enabled
-                        if first_sub:
-                            if tier_name:
-                                current_app.logger.info(f'{from_name} <{email}> subscribed as a {tier_name} tier member.')
-                            else:
-                                current_app.logger.info(f'{from_name} <{email}> subscribed.')
-                        else:
-                            if tier_name:
-                                current_app.logger.info(f'{from_name} <{email}> renewed their {tier_name} tier membership.')
-                            else:
-                                current_app.logger.info(f'{from_name} <{email}> renewed their membership.')
-
-                        sub_info = [is_public, from_name, email, amount, message, first_sub, tier_name]
-                        sub_points = current_app.config['KOFI_SETTINGS']['sub_points']
-                        accept_sub(sub_info, sub_points)
-                    else:
-                        current_app.logger.info(f'Kofi membership received, but subscriptions are not enabled. Doing nothing.')
-
-                return jsonify({'status': 'success'}), 200
-            else:
-                current_app.logger.info(f'Token invalid. Rejecting.')
-                return jsonify({'status': 'unauthorized'}), 401
-
-
 @ocb.route('/chatHook', methods=['POST'])
 def chat_hook():
     prefix = current_app.config['PREFIX']
@@ -141,16 +94,107 @@ def chat_hook():
 
         elif lowercase_msg.startswith(f'{prefix}'):  # Send to handle rewards
             do_reward(lowercase_msg, user_id)
-
     return data
 
 
-@ocb.route('/newFollow', methods=['POST'])  # Nothing implemented here, YET.
-def new_follow():
+@ocb.route('/followHook', methods=['POST'])  # Called by Owncast when someone follows
+def follow_hook():
     data = request.json
-    current_app.logger.info(f'\n\n{format(data)}\n\n')
-    db = get_db()
-    user_id = data['eventData']['id']
-    display_name = data['eventData']['name']
-
+    current_app.logger.debug(f'\n\n_______________\n/newFollow triggered!\n_______________')
+    followers.append(data)
     return jsonify({'status': 'success'}), 200
+
+
+@ocb.route('/kofiHook', methods=["POST"])
+def kofi_hook():
+    current_app.logger.info(f'----------------------------------------------------------------------------')
+    current_app.logger.info(f'Kofi request')
+    if request.content_type == 'application/x-www-form-urlencoded':
+        raw_data = request.form.get('data')  # Get the kofi data
+        if raw_data:
+            raw_data = json.loads(raw_data)
+            is_authed = raw_data['verification_token']
+            if is_authed == current_app.config['KOFI_TOKEN']:
+                type = raw_data['type']
+                is_public = raw_data['is_public']
+                new_sub = raw_data['is_first_subscription_payment']
+                message = raw_data['message']
+                shop_items = raw_data['shop_items']
+                from_name = raw_data['from_name']
+                email = raw_data['email']
+                amount = raw_data['amount']
+                sub_payment = raw_data['is_subscription_payment']
+                first_sub = raw_data['is_first_subscription_payment']
+                tier_name = raw_data['tier_name']
+                if type == 'Shop Order':
+                    current_app.logger.info(f'{from_name} purchased {format(shop_items)}\nMessage: {message}\n')
+                if type == 'Donation':
+                    donation_info = [is_public, from_name, email, amount, message]
+                    donation_points = current_app.config['KOFI_SETTINGS']['donation_points']
+                    accept_donation(donation_info, donation_points)
+                    if is_public:
+                        alert_info = {'name': from_name, 'amount': amount}
+                    else:
+                        alert_info = {'name': 'Anonymous Hero', 'amount': amount}
+                    donations.append(alert_info)  # Append info to be displayed in alert
+                if type == 'Subscription':
+                    if current_app.config['KOFI_SETTINGS']['subs']:  # Check that subscriptions are enabled
+                        if first_sub:
+                            if tier_name:
+                                current_app.logger.info(f'{from_name} <{email}> subscribed as a {tier_name} tier member.')
+                            else:
+                                current_app.logger.info(f'{from_name} <{email}> subscribed.')
+                        else:
+                            if tier_name:
+                                current_app.logger.info(f'{from_name} <{email}> renewed their {tier_name} tier membership.')
+                            else:
+                                current_app.logger.info(f'{from_name} <{email}> renewed their membership.')
+
+                        sub_info = [is_public, from_name, email, amount, message, first_sub, tier_name]
+                        sub_points = current_app.config['KOFI_SETTINGS']['sub_points']
+                        accept_sub(sub_info, sub_points)
+                        if is_public:
+                            alert_info = {'name': from_name, 'tiername': tier_name}
+                        else:
+                            alert_info = {'name': 'Anonymous Hero', 'teirname': tier_name}
+                        subscribers.append(alert_info)  # Append info to be displayed in alert
+                    else:
+                        current_app.logger.info(f'Kofi membership received, but subscriptions are not enabled. Doing nothing.')
+
+                return jsonify({'status': 'success'}), 200
+            else:
+                current_app.logger.info(f'Token invalid. Rejecting.')
+                return jsonify({'status': 'unauthorized'}), 401
+
+
+@ocb.route('/checkFollows')  # Polled by follower.html template to check for new followers
+def check_follows():
+    if followers:
+        current_app.logger.debug(f'\n\n{format(followers[0])}\n\n')
+        last_follower = followers.pop(0)
+        return jsonify(last_follower)
+    else:
+        current_app.logger.info(f'No new followers')
+    return jsonify(None)
+
+
+@ocb.route('/checkDonations')  # Polled by follower.html template to check for new followers
+def check_donations():
+    if donations:
+        current_app.logger.info(f'\n\n{format(donations[0])}\n\n')
+        last_donation = donations.pop(0)
+        return jsonify(last_donation)
+    else:
+        current_app.logger.info(f'No new donations')
+    return jsonify(None)
+
+
+@ocb.route('/checkSubscribers')  # Polled by subscriber.html template to check for new followers
+def check_subscribers():
+    if subscribers:
+        current_app.logger.info(f'\n\n{format(subscribers[0])}\n\n')
+        last_subscriber = subscribers.pop(0)
+        return jsonify(last_subscriber)
+    else:
+        current_app.logger.info(f'No new subscribers')
+    return jsonify(None)

+ 2 - 1
pyproject.toml

@@ -22,7 +22,8 @@ dependencies = [
         'emoji',
         'apscheduler',
         'pkce',
-        'flask-cors'
+        'flask-cors',
+        'fonttools'
 ]
 keywords = ["streaming", "chatbot", "owncast"]
 

+ 2 - 1
setup.py

@@ -11,6 +11,7 @@ setup(
         'emoji',
         'apscheduler',
         'pkce',
-        'flask-cors'
+        'flask-cors',
+        'fonttools'
     ],
 )