Add comprehensive edited media management with expandable cards UI

- Optimized delete modal for light/dark modes with modern gradients
- Added edit_count tracking to media library with warnings in delete confirmation
- Enhanced PlayerEdit model with CASCADE delete on foreign keys
- Improved player management page to show latest 3 edited files with image previews
- Created new edited_media route and template with full version history
- Implemented horizontal expandable cards with two-column layout
- Added interactive version selection with thumbnail grid
- Included original file in versions list with source badge
- Fixed deletion workflow to clean up PlayerEdit records and edited_media folders
- Enhanced UI with smooth animations, hover effects, and dark mode support
This commit is contained in:
DigiServer Developer
2025-12-06 19:17:48 +02:00
parent ff14e8defb
commit 328edebe3c
7 changed files with 1003 additions and 115 deletions

View File

@@ -426,6 +426,16 @@ def delete_leftover_images():
if os.path.exists(file_path):
os.remove(file_path)
# Delete edited media archive folder if it exists
import shutil
edited_media_dir = os.path.join(current_app.config['UPLOAD_FOLDER'], 'edited_media', str(content.id))
if os.path.exists(edited_media_dir):
shutil.rmtree(edited_media_dir)
# Delete associated player edit records first
from app.models.player_edit import PlayerEdit
PlayerEdit.query.filter_by(content_id=content.id).delete()
# Delete database record
db.session.delete(content)
deleted_count += 1
@@ -472,6 +482,16 @@ def delete_leftover_videos():
if os.path.exists(file_path):
os.remove(file_path)
# Delete edited media archive folder if it exists
import shutil
edited_media_dir = os.path.join(current_app.config['UPLOAD_FOLDER'], 'edited_media', str(content.id))
if os.path.exists(edited_media_dir):
shutil.rmtree(edited_media_dir)
# Delete associated player edit records first
from app.models.player_edit import PlayerEdit
PlayerEdit.query.filter_by(content_id=content.id).delete()
# Delete database record
db.session.delete(content)
deleted_count += 1
@@ -505,6 +525,16 @@ def delete_single_leftover(content_id):
if os.path.exists(file_path):
os.remove(file_path)
# Delete edited media archive folder if it exists
import shutil
edited_media_dir = os.path.join(current_app.config['UPLOAD_FOLDER'], 'edited_media', str(content.id))
if os.path.exists(edited_media_dir):
shutil.rmtree(edited_media_dir)
# Delete associated player edit records first
from app.models.player_edit import PlayerEdit
PlayerEdit.query.filter_by(content_id=content.id).delete()
# Delete database record
db.session.delete(content)
db.session.commit()

View File

@@ -39,8 +39,14 @@ def content_list():
@login_required
def media_library():
"""View all media files in the library."""
from app.models.player_edit import PlayerEdit
media_files = Content.query.order_by(Content.uploaded_at.desc()).all()
# Add edit count to each media item
for media in media_files:
media.edit_count = PlayerEdit.query.filter_by(content_id=media.id).count()
# Group by content type
images = [m for m in media_files if m.content_type == 'image']
videos = [m for m in media_files if m.content_type == 'video']
@@ -74,6 +80,21 @@ def delete_media(media_id: int):
os.remove(file_path)
log_action('info', f'Deleted physical file: {filename}')
# Delete edited media archive folder if it exists
import shutil
edited_media_dir = os.path.join(current_app.config['UPLOAD_FOLDER'], 'edited_media', str(media.id))
if os.path.exists(edited_media_dir):
shutil.rmtree(edited_media_dir)
log_action('info', f'Deleted edited media archive for content ID {media.id}')
# Delete associated player edit records first
from app.models.player_edit import PlayerEdit
edit_records = PlayerEdit.query.filter_by(content_id=media.id).all()
if edit_records:
for edit in edit_records:
db.session.delete(edit)
log_action('info', f'Deleted {len(edit_records)} edit record(s) for content: {filename}')
# Remove from all playlists (this will cascade properly)
db.session.delete(media)

View File

@@ -334,6 +334,37 @@ def manage_player(player_id: int):
status_info=status_info)
@players_bp.route('/<int:player_id>/edited-media')
@login_required
def edited_media(player_id: int):
"""Display all edited media files from this player."""
try:
player = Player.query.get_or_404(player_id)
# Get all edited media history from player
from app.models.player_edit import PlayerEdit
edited_media = PlayerEdit.query.filter_by(player_id=player_id)\
.order_by(PlayerEdit.created_at.desc())\
.all()
# Get original content files for each edited media
content_files = {}
for edit in edited_media:
if edit.content_id not in content_files:
content = Content.query.get(edit.content_id)
if content:
content_files[edit.content_id] = content
return render_template('players/edited_media.html',
player=player,
edited_media=edited_media,
content_files=content_files)
except Exception as e:
log_action('error', f'Error loading edited media for player {player_id}: {str(e)}')
flash('Error loading edited media.', 'danger')
return redirect(url_for('players.manage_player', player_id=player_id))
@players_bp.route('/<int:player_id>/fullscreen')
def player_fullscreen(player_id: int):
"""Display player fullscreen view (no authentication required for players)."""