feat: Add sorting by name for soundboard sounds and improve socket emission logging
This commit is contained in:
@@ -1,6 +1,17 @@
|
||||
"""Main routes for the application."""
|
||||
|
||||
from flask import Blueprint
|
||||
from datetime import datetime, timedelta
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
from flask import Blueprint, request
|
||||
from sqlalchemy import desc, func
|
||||
|
||||
from app.database import db
|
||||
from app.models.playlist import Playlist
|
||||
from app.models.sound import Sound
|
||||
from app.models.sound_played import SoundPlayed
|
||||
from app.models.user import User
|
||||
from app.services.decorators import require_auth
|
||||
|
||||
bp = Blueprint("main", __name__)
|
||||
|
||||
@@ -9,3 +20,213 @@ bp = Blueprint("main", __name__)
|
||||
def health() -> dict[str, str]:
|
||||
"""Health check endpoint."""
|
||||
return {"status": "ok"}
|
||||
|
||||
|
||||
def get_period_filter(period: str) -> datetime | None:
|
||||
"""Get the start date for the specified period."""
|
||||
now = datetime.now(tz=ZoneInfo("UTC"))
|
||||
|
||||
if period == "today":
|
||||
return now.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
if period == "week":
|
||||
return now - timedelta(days=7)
|
||||
if period == "month":
|
||||
return now - timedelta(days=30)
|
||||
if period == "year":
|
||||
return now - timedelta(days=365)
|
||||
if period == "all":
|
||||
return None
|
||||
# Default to all time
|
||||
return None
|
||||
|
||||
|
||||
@bp.route("/dashboard/stats")
|
||||
@require_auth
|
||||
def dashboard_stats() -> dict:
|
||||
"""Get dashboard statistics."""
|
||||
# Count soundboard sounds (type = SDB)
|
||||
soundboard_count = Sound.query.filter_by(type="SDB").count()
|
||||
|
||||
# Count tracks (type = STR)
|
||||
track_count = Sound.query.filter_by(type="STR").count()
|
||||
|
||||
# Count playlists
|
||||
playlist_count = Playlist.query.count()
|
||||
|
||||
# Calculate total size of all sounds (original + normalized)
|
||||
total_size_result = db.session.query(
|
||||
func.sum(Sound.size).label("original_size"),
|
||||
func.sum(Sound.normalized_size).label("normalized_size"),
|
||||
).first()
|
||||
|
||||
original_size = getattr(total_size_result, "original_size", 0) or 0
|
||||
normalized_size = getattr(total_size_result, "normalized_size", 0) or 0
|
||||
total_size = original_size + normalized_size
|
||||
|
||||
return {
|
||||
"soundboard_sounds": soundboard_count,
|
||||
"tracks": track_count,
|
||||
"playlists": playlist_count,
|
||||
"total_size": total_size,
|
||||
"original_size": original_size,
|
||||
"normalized_size": normalized_size,
|
||||
}
|
||||
|
||||
|
||||
@bp.route("/dashboard/top-sounds")
|
||||
@require_auth
|
||||
def top_sounds() -> dict:
|
||||
"""Get top played sounds for a specific period."""
|
||||
period = request.args.get("period", "all")
|
||||
limit = int(request.args.get("limit", 5))
|
||||
|
||||
period_start = get_period_filter(period)
|
||||
|
||||
# Base query for soundboard sounds with play counts
|
||||
query = (
|
||||
db.session.query(
|
||||
Sound.id,
|
||||
Sound.name,
|
||||
Sound.filename,
|
||||
Sound.thumbnail,
|
||||
Sound.type,
|
||||
func.count(SoundPlayed.id).label("play_count"),
|
||||
)
|
||||
.outerjoin(SoundPlayed, Sound.id == SoundPlayed.sound_id)
|
||||
.filter(Sound.type == "SDB") # Only soundboard sounds
|
||||
.group_by(
|
||||
Sound.id,
|
||||
Sound.name,
|
||||
Sound.filename,
|
||||
Sound.thumbnail,
|
||||
Sound.type,
|
||||
)
|
||||
)
|
||||
|
||||
# Apply period filter if specified
|
||||
if period_start:
|
||||
query = query.filter(SoundPlayed.played_at >= period_start)
|
||||
|
||||
# Order by play count and limit results
|
||||
results = query.order_by(desc("play_count")).limit(limit).all()
|
||||
|
||||
# Convert to list of dictionaries
|
||||
top_sounds_list = [
|
||||
{
|
||||
"id": result.id,
|
||||
"name": result.name,
|
||||
"filename": result.filename,
|
||||
"thumbnail": result.thumbnail,
|
||||
"type": result.type,
|
||||
"play_count": result.play_count,
|
||||
}
|
||||
for result in results
|
||||
]
|
||||
|
||||
return {
|
||||
"period": period,
|
||||
"sounds": top_sounds_list,
|
||||
}
|
||||
|
||||
|
||||
@bp.route("/dashboard/top-tracks")
|
||||
@require_auth
|
||||
def top_tracks() -> dict:
|
||||
"""Get top played tracks for a specific period."""
|
||||
period = request.args.get("period", "all")
|
||||
limit = int(request.args.get("limit", 10))
|
||||
|
||||
period_start = get_period_filter(period)
|
||||
|
||||
# Base query for tracks with play counts
|
||||
query = (
|
||||
db.session.query(
|
||||
Sound.id,
|
||||
Sound.name,
|
||||
Sound.filename,
|
||||
Sound.thumbnail,
|
||||
Sound.type,
|
||||
func.count(SoundPlayed.id).label("play_count"),
|
||||
)
|
||||
.outerjoin(SoundPlayed, Sound.id == SoundPlayed.sound_id)
|
||||
.filter(Sound.type == "STR") # Only tracks
|
||||
.group_by(
|
||||
Sound.id,
|
||||
Sound.name,
|
||||
Sound.filename,
|
||||
Sound.thumbnail,
|
||||
Sound.type,
|
||||
)
|
||||
)
|
||||
|
||||
# Apply period filter if specified
|
||||
if period_start:
|
||||
query = query.filter(SoundPlayed.played_at >= period_start)
|
||||
|
||||
# Order by play count and limit results
|
||||
results = query.order_by(desc("play_count")).limit(limit).all()
|
||||
|
||||
# Convert to list of dictionaries
|
||||
top_tracks_list = [
|
||||
{
|
||||
"id": result.id,
|
||||
"name": result.name,
|
||||
"filename": result.filename,
|
||||
"thumbnail": result.thumbnail,
|
||||
"type": result.type,
|
||||
"play_count": result.play_count,
|
||||
}
|
||||
for result in results
|
||||
]
|
||||
|
||||
return {
|
||||
"period": period,
|
||||
"tracks": top_tracks_list,
|
||||
}
|
||||
|
||||
|
||||
@bp.route("/dashboard/top-users")
|
||||
@require_auth
|
||||
def top_users() -> dict:
|
||||
"""Get top users by play count for a specific period."""
|
||||
period = request.args.get("period", "all")
|
||||
limit = int(request.args.get("limit", 10))
|
||||
|
||||
period_start = get_period_filter(period)
|
||||
|
||||
# Base query for users with play counts
|
||||
query = (
|
||||
db.session.query(
|
||||
User.id,
|
||||
User.name,
|
||||
User.email,
|
||||
User.picture,
|
||||
func.count(SoundPlayed.id).label("play_count"),
|
||||
)
|
||||
.outerjoin(SoundPlayed, User.id == SoundPlayed.user_id)
|
||||
.group_by(User.id, User.name, User.email, User.picture)
|
||||
)
|
||||
|
||||
# Apply period filter if specified
|
||||
if period_start:
|
||||
query = query.filter(SoundPlayed.played_at >= period_start)
|
||||
|
||||
# Order by play count and limit results
|
||||
results = query.order_by(desc("play_count")).limit(limit).all()
|
||||
|
||||
# Convert to list of dictionaries
|
||||
top_users_list = [
|
||||
{
|
||||
"id": result.id,
|
||||
"name": result.name,
|
||||
"email": result.email,
|
||||
"picture": result.picture,
|
||||
"play_count": result.play_count,
|
||||
}
|
||||
for result in results
|
||||
]
|
||||
|
||||
return {
|
||||
"period": period,
|
||||
"users": top_users_list,
|
||||
}
|
||||
|
||||
@@ -29,6 +29,9 @@ def get_sounds():
|
||||
# Get sounds from database
|
||||
sounds = Sound.find_by_type(sound_type)
|
||||
|
||||
# Order by name
|
||||
sounds = sorted(sounds, key=lambda s: s.name.lower())
|
||||
|
||||
# Convert to dict format
|
||||
sounds_data = [sound.to_dict() for sound in sounds]
|
||||
|
||||
@@ -65,13 +68,19 @@ def play_sound(sound_id: int):
|
||||
# Emit sound_changed event to all connected clients
|
||||
try:
|
||||
from app.services.socketio_service import SocketIOService
|
||||
SocketIOService.emit_sound_play_count_changed(sound_id, sound.play_count)
|
||||
|
||||
SocketIOService.emit_sound_play_count_changed(
|
||||
sound_id, sound.play_count
|
||||
)
|
||||
except Exception as e:
|
||||
# Don't fail the request if socket emission fails
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.warning(f"Failed to emit sound_play_count_changed event: {e}")
|
||||
|
||||
logger.warning(
|
||||
f"Failed to emit sound_play_count_changed event: {e}"
|
||||
)
|
||||
|
||||
return jsonify({"message": "Sound playing", "sound_id": sound_id})
|
||||
return (
|
||||
jsonify({"error": "Sound not found or cannot be played"}),
|
||||
|
||||
Reference in New Issue
Block a user