]> littlesong.place Git - littlesongplace.git/commitdiff
More work on push notifications
authorChris Fulljames <christianfulljames@gmail.com>
Sat, 19 Jul 2025 13:20:12 +0000 (09:20 -0400)
committerChris Fulljames <christianfulljames@gmail.com>
Sat, 23 Aug 2025 11:30:17 +0000 (07:30 -0400)
src/littlesongplace/__init__.py
src/littlesongplace/comments.py
src/littlesongplace/push_notifications.py
src/littlesongplace/songs.py
src/littlesongplace/static/service.js

index 8153ff1c3bf899dfe7b152442b8fe145e15ddd1c..d9dbf1bcd8a4709cf5c2c1d12bdfd90ea96c585e 100644 (file)
@@ -38,6 +38,7 @@ app.register_blueprint(profiles.bp)
 app.register_blueprint(push_notifications.bp)
 app.register_blueprint(songs.bp)
 db.init_app(app)
+push_notifications.init_app(app)
 
 if "DATA_DIR" in os.environ:
     # Running on server behind proxy
index f42a63ccf949645166018b92442ebc334973aef3..5ba38afab985fec2f5211027c200ba309633026e 100644 (file)
@@ -188,7 +188,10 @@ def comment():
 
             # Send push notifications
             push_notifications.notify(
-                    notification_targets, f"Comment from {g.username}", content)
+                    notification_targets,
+                    title=f"Comment from {g.username}",
+                    body=content,
+                    url="/activity")
 
         db.commit()
 
index 1cd1960617f42913ff3ec1fc2db61504971524ad..6e29ff503f6ce04dce2df86a5ecb54da8ae02307 100644 (file)
@@ -1,11 +1,13 @@
 import json
 import threading
 import enum
+from datetime import datetime, timedelta, timezone
 
+import click
 import pywebpush
 from flask import Blueprint, current_app, g, request
 
-from . import auth, datadir, db
+from . import auth, datadir, db, songs
 
 bp = Blueprint("push-notifications", __name__, url_prefix="/push-notifications")
 
@@ -123,19 +125,19 @@ def get_user_subscriptions(userid):
             current_app.logger.error(f"Invalid subscription: {s}")
     return subs
 
-def notify_all(title, body, _except=None):
+def notify_all(title, body, url, _except=None):
     # Notify all users (who have notifications enabled)
     rows = db.query("SELECT * FROM users")
     userids = [r["userid"] for r in rows]
     if _except in userids:
         userids.remove(_except)
-    notify(userids, title, body)
+    notify(userids, title, body, url)
 
-def notify(userids, title, body):
+def notify(userids, title, body, url):
     # Send push notifications in background thread (could take a while)
     thread = threading.Thread(
             target=_do_push,
-            args=(current_app._get_current_object(), userids, title, body))
+            args=(current_app._get_current_object(), userids, title, body, url))
     push_threads.append(thread)
     thread.start()
 
@@ -144,8 +146,8 @@ def wait_all():
     for thread in push_copy:
         thread.join()
 
-def _do_push(app, userids, title, body):
-    data = {"title": title, "body": body}
+def _do_push(app, userids, title, body, url):
+    data = {"title": title, "body": body, "url": url}
     data_str = json.dumps(data)
 
     private_key_path = datadir.get_vapid_private_key_path()
@@ -178,3 +180,26 @@ def _do_push(app, userids, title, body):
 
     push_threads.remove(threading.current_thread())
 
+@click.command("notify-new-songs")
+def notify_new_songs_cmd():
+    """Notify subscribed users that new songs have been uploaded"""
+    with current_app.app_context():
+        one_day = timedelta(days=1)
+        yesterday = (datetime.now(timezone.utc) - one_day).isoformat()
+        new_songs = songs.get_uploaded_since(yesterday)
+        unique_users = sorted(set(s.username for s in new_songs))
+
+        title = None
+        _except = None
+        if len(new_songs) == 1:
+            title = f"New song from {unique_users[0]}"
+            _except = new_songs[0].userid
+        elif len(new_songs) > 1:
+            title = f"New songs from {', '.join(unique_users)}"
+        
+        if title:
+            print(title)
+            notify_all(title, body=None, url="/", _except=_except)
+
+def init_app(app):
+    app.cli.add_command(notify_new_songs_cmd)
index 89ee4a7a8f9552a3e98b419c6033f70d626f43aa..a2ed3f6ae21afea5e12d029fd6c87d8096475345 100644 (file)
@@ -14,7 +14,7 @@ from flask import Blueprint, current_app, g, render_template, request, redirect,
 from yt_dlp import YoutubeDL
 from yt_dlp.utils import DownloadError
 
-from . import auth, comments, colors, datadir, db, push_notifications, users
+from . import auth, comments, colors, datadir, db, users
 from .sanitize import sanitize_user_text
 from .logutils import flash_and_log
 
@@ -132,6 +132,9 @@ def get_for_playlist(playlistid):
 def get_for_event(eventid):
     return _from_db("SELECT * FROM songs_view WHERE eventid = ?", [eventid])
 
+def get_uploaded_since(timestamp):
+    return _from_db("SELECT * FROM songs_view WHERE created > ?", [timestamp])
+
 def _from_db(query, args=()):
     songs_data = db.query(query, args)
     songs = []
@@ -401,10 +404,6 @@ def create_song():
 
             flash_and_log(f"Successfully uploaded '{title}'", "success")
 
-            # Send push notifications to all other users
-            push_notifications.notify_all(
-                    f"New song from {g.username}", title, _except=g.userid)
-
             return False  # No error
 
 def convert_song(tmp_file, request_file, yt_url):
index f1e53e222b08f5fd7e8bed2b876bf68096519d39..8f7ee6ec19193c113052fdbc8ee50574a3e65885 100644 (file)
@@ -18,7 +18,7 @@ self.addEventListener("pushsubscriptionchanged", (event) => {
                 headers: {"Content-Type": "application/json"},
                 body: JSON.stringify(subscription)
             });
-        });
+        })
     );
 });