355 lines
11 KiB
Python
355 lines
11 KiB
Python
from models import Player, Group, Content
|
|
from extensions import db
|
|
from utils.logger import (
|
|
log_group_created, log_group_edited, log_group_deleted,
|
|
log_player_created, log_player_edited, log_player_deleted,
|
|
log_player_added_to_group, log_player_removed_from_group,
|
|
log_player_unlocked, log_content_reordered,
|
|
log_content_duration_changed, log_content_added
|
|
)
|
|
|
|
def create_group(name, player_ids):
|
|
"""
|
|
Create a new group with the given name and add selected players to it.
|
|
Clears individual playlists of players and locks them to the group.
|
|
"""
|
|
new_group = Group(name=name)
|
|
db.session.add(new_group)
|
|
db.session.flush() # Get the group ID
|
|
|
|
# Add players to the group and lock them
|
|
for player_id in player_ids:
|
|
player = Player.query.get(player_id)
|
|
if player:
|
|
# Add player to group
|
|
new_group.players.append(player)
|
|
|
|
# Delete player's individual playlist
|
|
Content.query.filter_by(player_id=player.id).delete()
|
|
|
|
# Lock player to this group
|
|
player.locked_to_group_id = new_group.id
|
|
|
|
db.session.commit()
|
|
log_group_created(name)
|
|
return new_group
|
|
|
|
def edit_group(group_id, name, player_ids):
|
|
"""
|
|
Edit an existing group, updating its name and players.
|
|
Handles locking/unlocking players appropriately.
|
|
"""
|
|
group = Group.query.get_or_404(group_id)
|
|
old_name = group.name # Store old name in case it changes
|
|
group.name = name
|
|
|
|
# Get current players in the group
|
|
current_player_ids = [player.id for player in group.players]
|
|
|
|
# Determine players to add and remove
|
|
players_to_add = [pid for pid in player_ids if pid not in current_player_ids]
|
|
players_to_remove = [pid for pid in current_player_ids if pid not in player_ids]
|
|
|
|
# Handle players to add
|
|
for player_id in players_to_add:
|
|
player = Player.query.get(player_id)
|
|
if player:
|
|
# Add to group
|
|
group.players.append(player)
|
|
|
|
# Delete individual playlist
|
|
Content.query.filter_by(player_id=player.id).delete()
|
|
|
|
# Lock to group
|
|
player.locked_to_group_id = group.id
|
|
|
|
# Log this action
|
|
log_player_added_to_group(player.username, name)
|
|
|
|
# Handle players to remove
|
|
for player_id in players_to_remove:
|
|
player = Player.query.get(player_id)
|
|
if player:
|
|
# Remove from group
|
|
group.players.remove(player)
|
|
|
|
# Unlock from group
|
|
player.locked_to_group_id = None
|
|
|
|
# Log this action
|
|
log_player_removed_from_group(player.username, name)
|
|
log_player_unlocked(player.username)
|
|
|
|
db.session.commit()
|
|
|
|
# Log the group edit
|
|
if old_name != name:
|
|
log_group_edited(f"{old_name} → {name}")
|
|
else:
|
|
log_group_edited(name)
|
|
|
|
return group
|
|
|
|
def delete_group(group_id):
|
|
"""
|
|
Delete a group and unlock all associated players.
|
|
"""
|
|
group = Group.query.get_or_404(group_id)
|
|
group_name = group.name
|
|
|
|
# Unlock all players in the group
|
|
for player in group.players:
|
|
player.locked_to_group_id = None
|
|
log_player_unlocked(player.username)
|
|
|
|
db.session.delete(group)
|
|
db.session.commit()
|
|
log_group_deleted(group_name)
|
|
|
|
def add_player(username, hostname, password, quickconnect_password):
|
|
"""
|
|
Add a new player with the given details.
|
|
"""
|
|
from flask_bcrypt import Bcrypt
|
|
bcrypt = Bcrypt()
|
|
|
|
hashed_password = bcrypt.generate_password_hash(password).decode('utf-8')
|
|
hashed_quickconnect = bcrypt.generate_password_hash(quickconnect_password).decode('utf-8')
|
|
|
|
new_player = Player(
|
|
username=username,
|
|
hostname=hostname,
|
|
password=hashed_password,
|
|
quickconnect_password=hashed_quickconnect
|
|
)
|
|
|
|
db.session.add(new_player)
|
|
db.session.commit()
|
|
log_player_created(username, hostname)
|
|
return new_player
|
|
|
|
def edit_player(player_id, username, hostname, password=None, quickconnect_password=None):
|
|
"""
|
|
Edit an existing player's details.
|
|
"""
|
|
from flask_bcrypt import Bcrypt
|
|
bcrypt = Bcrypt()
|
|
|
|
player = Player.query.get_or_404(player_id)
|
|
player.username = username
|
|
player.hostname = hostname
|
|
|
|
if password:
|
|
player.password = bcrypt.generate_password_hash(password).decode('utf-8')
|
|
|
|
if quickconnect_password:
|
|
player.quickconnect_password = bcrypt.generate_password_hash(quickconnect_password).decode('utf-8')
|
|
|
|
db.session.commit()
|
|
log_player_edited(username)
|
|
return player
|
|
|
|
def delete_player(player_id):
|
|
"""
|
|
Delete a player and all its content.
|
|
"""
|
|
player = Player.query.get_or_404(player_id)
|
|
username = player.username
|
|
|
|
# Delete all media related to the player
|
|
Content.query.filter_by(player_id=player_id).delete()
|
|
|
|
# Delete the player
|
|
db.session.delete(player)
|
|
db.session.commit()
|
|
log_player_deleted(username)
|
|
|
|
def get_group_content(group_id):
|
|
"""
|
|
Get content for all players in a group, ordered by position.
|
|
"""
|
|
from models import Group, Content
|
|
|
|
group = Group.query.get_or_404(group_id)
|
|
|
|
# Get all player IDs in the group
|
|
player_ids = [player.id for player in group.players]
|
|
|
|
# Get unique content based on file_name, preserving position
|
|
unique_content = {}
|
|
|
|
# For each player, get their content
|
|
for player_id in player_ids:
|
|
# Get content for this player, ordered by position
|
|
player_content = Content.query.filter_by(player_id=player_id).order_by(Content.position).all()
|
|
|
|
for content in player_content:
|
|
if content.file_name not in unique_content:
|
|
unique_content[content.file_name] = content
|
|
|
|
# Sort the unique content by position
|
|
return sorted(unique_content.values(), key=lambda c: c.position)
|
|
|
|
def get_player_content(player_id):
|
|
"""
|
|
Get content for a specific player, ordered by position.
|
|
"""
|
|
from models import Content
|
|
return Content.query.filter_by(player_id=player_id).order_by(Content.position).all()
|
|
|
|
def update_player_content_order(player_id, items):
|
|
"""
|
|
Update the order of content items for a player.
|
|
|
|
Args:
|
|
player_id (int): ID of the player
|
|
items (list): List of items with id and position
|
|
|
|
Returns:
|
|
tuple: (success, error_message, new_version)
|
|
"""
|
|
from models import Player, Content
|
|
from extensions import db
|
|
|
|
player = Player.query.get_or_404(player_id)
|
|
|
|
try:
|
|
# Update the position field for each content item
|
|
for item in items:
|
|
content_id = int(item['id'])
|
|
position = int(item['position'])
|
|
content = Content.query.get_or_404(content_id)
|
|
if content.player_id != player_id:
|
|
continue # Skip if not for this player
|
|
content.position = position
|
|
|
|
# Force increment the playlist version to trigger client refresh
|
|
player.playlist_version = (player.playlist_version or 0) + 1
|
|
|
|
db.session.commit()
|
|
|
|
# Log the reordering action
|
|
log_content_reordered("player", player.username)
|
|
|
|
return True, None, player.playlist_version
|
|
except Exception as e:
|
|
db.session.rollback()
|
|
return False, str(e), None
|
|
|
|
def update_group_content_order(group_id, items):
|
|
"""
|
|
Update the order of content items for all players in a group.
|
|
|
|
Args:
|
|
group_id (int): ID of the group
|
|
items (list): List of items with id and position
|
|
|
|
Returns:
|
|
tuple: (success, error_message)
|
|
"""
|
|
from models import Group, Content
|
|
from extensions import db
|
|
|
|
group = Group.query.get_or_404(group_id)
|
|
|
|
try:
|
|
# Get file names corresponding to the content IDs
|
|
content_files = {}
|
|
for item in items:
|
|
content_id = int(item['id'])
|
|
position = int(item['position'])
|
|
content = Content.query.get_or_404(content_id)
|
|
content_files[content.file_name] = position
|
|
|
|
# Update all content items for all players in this group
|
|
for player in group.players:
|
|
for content in Content.query.filter_by(player_id=player.id).all():
|
|
if content.file_name in content_files:
|
|
content.position = content_files[content.file_name]
|
|
|
|
# Force increment the playlist version to trigger client refresh
|
|
player.playlist_version = (player.playlist_version or 0) + 1
|
|
|
|
db.session.commit()
|
|
|
|
# Log the reordering action
|
|
log_content_reordered("group", group.name)
|
|
|
|
return True, None
|
|
except Exception as e:
|
|
db.session.rollback()
|
|
return False, str(e)
|
|
|
|
def edit_group_media(group_id, content_id, new_duration):
|
|
"""
|
|
Update the duration for all instances of a media item across all players in a group.
|
|
|
|
Args:
|
|
group_id (int): ID of the group
|
|
content_id (int): ID of the content item
|
|
new_duration (int): New duration in seconds
|
|
|
|
Returns:
|
|
bool: Success or failure
|
|
"""
|
|
from models import Group, Content
|
|
from extensions import db
|
|
|
|
group = Group.query.get_or_404(group_id)
|
|
content = Content.query.get(content_id)
|
|
file_name = content.file_name
|
|
old_duration = content.duration
|
|
|
|
try:
|
|
# Update the duration for all players in the group
|
|
for player in group.players:
|
|
content = Content.query.filter_by(player_id=player.id, file_name=file_name).first()
|
|
if content:
|
|
content.duration = new_duration
|
|
|
|
db.session.commit()
|
|
|
|
# Log the duration change
|
|
log_content_duration_changed(file_name, old_duration, new_duration, "group", group.name)
|
|
|
|
return True
|
|
except Exception as e:
|
|
db.session.rollback()
|
|
return False
|
|
|
|
def delete_group_media(group_id, content_id):
|
|
"""
|
|
Delete a media item from all players in a group.
|
|
|
|
Args:
|
|
group_id (int): ID of the group
|
|
content_id (int): ID of the content item
|
|
|
|
Returns:
|
|
bool: Success or failure
|
|
"""
|
|
from models import Group, Content
|
|
from extensions import db
|
|
|
|
group = Group.query.get_or_404(group_id)
|
|
content = Content.query.get(content_id)
|
|
file_name = content.file_name
|
|
|
|
try:
|
|
# Delete the media for all players in the group
|
|
count = 0
|
|
for player in group.players:
|
|
content = Content.query.filter_by(player_id=player.id, file_name=file_name).first()
|
|
if content:
|
|
db.session.delete(content)
|
|
count += 1
|
|
|
|
db.session.commit()
|
|
|
|
# Log the content deletion
|
|
log_content_deleted(file_name, "group", group.name)
|
|
|
|
return True
|
|
except Exception as e:
|
|
db.session.rollback()
|
|
return False |