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")
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()
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()
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)
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
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 = []
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):