154 lines
5.2 KiB
Python
154 lines
5.2 KiB
Python
"""
|
|
API routes for player clients
|
|
"""
|
|
|
|
from flask import Blueprint, request, jsonify, url_for
|
|
from app.models.player import Player
|
|
from app.models.content import Content
|
|
from app.extensions import bcrypt, db
|
|
|
|
bp = Blueprint('api', __name__)
|
|
|
|
@bp.route('/playlists', methods=['GET'])
|
|
def get_playlists():
|
|
"""Get playlist for a player"""
|
|
hostname = request.args.get('hostname')
|
|
quickconnect_code = request.args.get('quickconnect_code')
|
|
|
|
# Validate parameters
|
|
if not hostname or not quickconnect_code:
|
|
return jsonify({'error': 'Hostname and quick connect code are required'}), 400
|
|
|
|
# Find player and verify credentials
|
|
player = Player.query.filter_by(hostname=hostname).first()
|
|
if not player or not player.verify_quickconnect_code(quickconnect_code):
|
|
return jsonify({'error': 'Invalid hostname or quick connect code'}), 404
|
|
|
|
# Update last seen
|
|
player.last_seen = db.func.current_timestamp()
|
|
db.session.commit()
|
|
|
|
# Get content based on player's group status
|
|
if player.is_locked_to_group:
|
|
# Player is locked to a group - get shared content
|
|
group = player.locked_to_group
|
|
player_ids = [p.id for p in group.players]
|
|
|
|
# Get unique content by filename (first occurrence)
|
|
content_query = (
|
|
db.session.query(
|
|
Content.file_name,
|
|
db.func.min(Content.id).label('id'),
|
|
db.func.min(Content.duration).label('duration'),
|
|
db.func.min(Content.position).label('position'),
|
|
db.func.min(Content.content_type).label('content_type')
|
|
)
|
|
.filter(Content.player_id.in_(player_ids))
|
|
.group_by(Content.file_name)
|
|
)
|
|
|
|
content = db.session.query(Content).filter(
|
|
Content.id.in_([c.id for c in content_query])
|
|
).order_by(Content.position).all()
|
|
else:
|
|
# Individual player content
|
|
content = Content.query.filter_by(player_id=player.id).order_by(Content.position).all()
|
|
|
|
# Build playlist
|
|
playlist = []
|
|
for media in content:
|
|
playlist.append({
|
|
'file_name': media.file_name,
|
|
'url': url_for('content.media', filename=media.file_name, _external=True),
|
|
'duration': media.duration,
|
|
'content_type': media.content_type,
|
|
'position': media.position
|
|
})
|
|
|
|
return jsonify({
|
|
'playlist': playlist,
|
|
'playlist_version': player.playlist_version,
|
|
'hashed_quickconnect': player.quickconnect_password,
|
|
'player_id': player.id,
|
|
'player_name': player.username
|
|
})
|
|
|
|
@bp.route('/playlist_version', methods=['GET'])
|
|
def get_playlist_version():
|
|
"""Get playlist version for a player (for checking updates)"""
|
|
hostname = request.args.get('hostname')
|
|
quickconnect_code = request.args.get('quickconnect_code')
|
|
|
|
# Validate parameters
|
|
if not hostname or not quickconnect_code:
|
|
return jsonify({'error': 'Hostname and quick connect code are required'}), 400
|
|
|
|
# Find player and verify credentials
|
|
player = Player.query.filter_by(hostname=hostname).first()
|
|
if not player or not player.verify_quickconnect_code(quickconnect_code):
|
|
return jsonify({'error': 'Invalid hostname or quick connect code'}), 404
|
|
|
|
# Update last seen
|
|
player.last_seen = db.func.current_timestamp()
|
|
db.session.commit()
|
|
|
|
return jsonify({
|
|
'playlist_version': player.playlist_version,
|
|
'hashed_quickconnect': player.quickconnect_password
|
|
})
|
|
|
|
@bp.route('/player_status', methods=['POST'])
|
|
def update_player_status():
|
|
"""Update player status (heartbeat)"""
|
|
data = request.get_json()
|
|
|
|
if not data:
|
|
return jsonify({'error': 'JSON data required'}), 400
|
|
|
|
hostname = data.get('hostname')
|
|
quickconnect_code = data.get('quickconnect_code')
|
|
|
|
if not hostname or not quickconnect_code:
|
|
return jsonify({'error': 'Hostname and quick connect code are required'}), 400
|
|
|
|
# Find player and verify credentials
|
|
player = Player.query.filter_by(hostname=hostname).first()
|
|
if not player or not player.verify_quickconnect_code(quickconnect_code):
|
|
return jsonify({'error': 'Invalid hostname or quick connect code'}), 404
|
|
|
|
# Update player status
|
|
player.last_seen = db.func.current_timestamp()
|
|
player.is_active = True
|
|
|
|
# Optional: Update additional status info if provided
|
|
if 'status' in data:
|
|
# Could store additional status information in the future
|
|
pass
|
|
|
|
db.session.commit()
|
|
|
|
return jsonify({
|
|
'success': True,
|
|
'playlist_version': player.playlist_version,
|
|
'message': 'Status updated successfully'
|
|
})
|
|
|
|
@bp.route('/health', methods=['GET'])
|
|
def health_check():
|
|
"""Health check endpoint"""
|
|
return jsonify({
|
|
'status': 'healthy',
|
|
'service': 'SKE Digital Signage Server',
|
|
'version': '2.0.0'
|
|
})
|
|
|
|
@bp.errorhandler(404)
|
|
def api_not_found(error):
|
|
"""API 404 handler"""
|
|
return jsonify({'error': 'API endpoint not found'}), 404
|
|
|
|
@bp.errorhandler(500)
|
|
def api_internal_error(error):
|
|
"""API 500 handler"""
|
|
return jsonify({'error': 'Internal server error'}), 500
|