Files
digiserver-v2/app/blueprints/playlist.py
2025-11-15 01:26:12 +02:00

277 lines
9.9 KiB
Python

"""Playlist blueprint for managing player playlists."""
from flask import (Blueprint, render_template, request, redirect, url_for,
flash, jsonify, current_app)
from flask_login import login_required
from sqlalchemy import desc, update
import os
from app.extensions import db, cache
from app.models import Player, Content, Playlist
from app.models.playlist import playlist_content
from app.utils.logger import log_action
playlist_bp = Blueprint('playlist', __name__, url_prefix='/playlist')
@playlist_bp.route('/<int:player_id>')
@login_required
def manage_playlist(player_id: int):
"""Manage playlist for a specific player."""
player = Player.query.get_or_404(player_id)
# Get content from player's assigned playlist
playlist_items = []
if player.playlist_id:
playlist = Playlist.query.get(player.playlist_id)
if playlist:
playlist_items = playlist.get_content_ordered()
# Get available content (all content not in current playlist)
all_content = Content.query.all()
playlist_content_ids = {item.id for item in playlist_items}
available_content = [c for c in all_content if c.id not in playlist_content_ids]
return render_template('playlist/manage_playlist.html',
player=player,
playlist_content=playlist_items,
available_content=available_content)
@playlist_bp.route('/<int:player_id>/add', methods=['POST'])
@login_required
def add_to_playlist(player_id: int):
"""Add content to player's playlist."""
player = Player.query.get_or_404(player_id)
if not player.playlist_id:
flash('Player has no playlist assigned.', 'warning')
return redirect(url_for('playlist.manage_playlist', player_id=player_id))
try:
content_id = request.form.get('content_id', type=int)
duration = request.form.get('duration', type=int, default=10)
if not content_id:
flash('Please select content.', 'warning')
return redirect(url_for('playlist.manage_playlist', player_id=player_id))
content = Content.query.get_or_404(content_id)
playlist = Playlist.query.get(player.playlist_id)
# Get max position
from sqlalchemy import select, func
max_pos = db.session.execute(
select(func.max(playlist_content.c.position)).where(
playlist_content.c.playlist_id == playlist.id
)
).scalar() or 0
# Add to playlist_content association table
stmt = playlist_content.insert().values(
playlist_id=playlist.id,
content_id=content.id,
position=max_pos + 1,
duration=duration
)
db.session.execute(stmt)
# Increment playlist version
playlist.increment_version()
db.session.commit()
cache.clear()
log_action('info', f'Added "{content.filename}" to playlist for player "{player.name}"')
flash(f'Added "{content.filename}" to playlist.', 'success')
except Exception as e:
db.session.rollback()
log_action('error', f'Error adding to playlist: {str(e)}')
flash('Error adding to playlist.', 'danger')
return redirect(url_for('playlist.manage_playlist', player_id=player_id))
@playlist_bp.route('/<int:player_id>/remove/<int:content_id>', methods=['POST'])
@login_required
def remove_from_playlist(player_id: int, content_id: int):
"""Remove content from player's playlist."""
player = Player.query.get_or_404(player_id)
if not player.playlist_id:
flash('Player has no playlist assigned.', 'danger')
return redirect(url_for('playlist.manage_playlist', player_id=player_id))
try:
content = Content.query.get_or_404(content_id)
playlist = Playlist.query.get(player.playlist_id)
filename = content.filename
# Remove from playlist_content association table
from sqlalchemy import delete
stmt = delete(playlist_content).where(
(playlist_content.c.playlist_id == playlist.id) &
(playlist_content.c.content_id == content_id)
)
db.session.execute(stmt)
# Reorder remaining content
from sqlalchemy import select
remaining = db.session.execute(
select(playlist_content.c.content_id, playlist_content.c.position).where(
playlist_content.c.playlist_id == playlist.id
).order_by(playlist_content.c.position)
).fetchall()
for idx, row in enumerate(remaining, start=1):
stmt = update(playlist_content).where(
(playlist_content.c.playlist_id == playlist.id) &
(playlist_content.c.content_id == row.content_id)
).values(position=idx)
db.session.execute(stmt)
# Increment playlist version
playlist.increment_version()
db.session.commit()
cache.clear()
log_action('info', f'Removed "{filename}" from playlist for player "{player.name}"')
flash(f'Removed "{filename}" from playlist.', 'success')
except Exception as e:
db.session.rollback()
log_action('error', f'Error removing from playlist: {str(e)}')
flash('Error removing from playlist.', 'danger')
return redirect(url_for('playlist.manage_playlist', player_id=player_id))
@playlist_bp.route('/<int:player_id>/reorder', methods=['POST'])
@login_required
def reorder_playlist(player_id: int):
"""Reorder playlist items."""
player = Player.query.get_or_404(player_id)
if not player.playlist_id:
return jsonify({'success': False, 'message': 'Player has no playlist'}), 400
try:
playlist = Playlist.query.get(player.playlist_id)
# Get new order from JSON
data = request.get_json()
content_ids = data.get('content_ids', [])
if not content_ids:
return jsonify({'success': False, 'message': 'No content IDs provided'}), 400
# Update positions in association table
for idx, content_id in enumerate(content_ids, start=1):
stmt = update(playlist_content).where(
(playlist_content.c.playlist_id == playlist.id) &
(playlist_content.c.content_id == content_id)
).values(position=idx)
db.session.execute(stmt)
# Increment playlist version
playlist.increment_version()
db.session.commit()
cache.clear()
log_action('info', f'Reordered playlist for player "{player.name}" (version {playlist.version})')
return jsonify({
'success': True,
'message': 'Playlist reordered successfully',
'version': playlist.version
})
except Exception as e:
db.session.rollback()
log_action('error', f'Error reordering playlist: {str(e)}')
return jsonify({'success': False, 'message': str(e)}), 500
@playlist_bp.route('/<int:player_id>/update-duration/<int:content_id>', methods=['POST'])
@login_required
def update_duration(player_id: int, content_id: int):
"""Update content duration in playlist."""
player = Player.query.get_or_404(player_id)
if not player.playlist_id:
return jsonify({'success': False, 'message': 'Player has no playlist'}), 400
try:
playlist = Playlist.query.get(player.playlist_id)
content = Content.query.get_or_404(content_id)
duration = request.form.get('duration', type=int)
if not duration or duration < 1:
return jsonify({'success': False, 'message': 'Invalid duration'}), 400
# Update duration in association table
stmt = update(playlist_content).where(
(playlist_content.c.playlist_id == playlist.id) &
(playlist_content.c.content_id == content_id)
).values(duration=duration)
db.session.execute(stmt)
# Increment playlist version
playlist.increment_version()
db.session.commit()
cache.clear()
log_action('info', f'Updated duration for "{content.filename}" in player "{player.name}" playlist')
return jsonify({
'success': True,
'message': 'Duration updated',
'version': playlist.version
})
except Exception as e:
db.session.rollback()
log_action('error', f'Error updating duration: {str(e)}')
return jsonify({'success': False, 'message': str(e)}), 500
@playlist_bp.route('/<int:player_id>/clear', methods=['POST'])
@login_required
def clear_playlist(player_id: int):
"""Clear all content from player's playlist."""
player = Player.query.get_or_404(player_id)
if not player.playlist_id:
flash('Player has no playlist assigned.', 'warning')
return redirect(url_for('playlist.manage_playlist', player_id=player_id))
try:
playlist = Playlist.query.get(player.playlist_id)
# Delete all content from playlist
from sqlalchemy import delete
stmt = delete(playlist_content).where(
playlist_content.c.playlist_id == playlist.id
)
db.session.execute(stmt)
# Increment playlist version
playlist.increment_version()
db.session.commit()
cache.clear()
log_action('info', f'Cleared playlist for player "{player.name}"')
flash('Playlist cleared successfully.', 'success')
except Exception as e:
db.session.rollback()
log_action('error', f'Error clearing playlist: {str(e)}')
flash('Error clearing playlist.', 'danger')
return redirect(url_for('playlist.manage_playlist', player_id=player_id))