Replace emoji icons with local SVG files for consistent rendering
- Created 10 SVG icon files in app/static/icons/ (Feather Icons style) - Updated base.html with SVG icons in navigation and dark mode toggle - Updated dashboard.html with icons in stats cards and quick actions - Updated content_list_new.html (playlist management) with SVG icons - Updated upload_media.html with upload-related icons - Updated manage_player.html with player management icons - Icons use currentColor for automatic theme adaptation - Removed emoji dependency for better Raspberry Pi compatibility - Added ICON_INTEGRATION.md documentation
This commit is contained in:
252
app/templates/players/manage_player.html
Normal file
252
app/templates/players/manage_player.html
Normal file
@@ -0,0 +1,252 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Manage Player - {{ player.name }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div style="margin-bottom: 2rem;">
|
||||
<h1 style="display: inline-block; margin-right: 1rem; display: flex; align-items: center; gap: 0.5rem;">
|
||||
<img src="{{ url_for('static', filename='icons/monitor.svg') }}" alt="" style="width: 32px; height: 32px;">
|
||||
Manage Player: {{ player.name }}
|
||||
</h1>
|
||||
<a href="{{ url_for('players.list') }}" class="btn" style="float: right; display: inline-flex; align-items: center; gap: 0.5rem;">
|
||||
<img src="{{ url_for('static', filename='icons/monitor.svg') }}" alt="" style="width: 18px; height: 18px; filter: brightness(0) invert(1);">
|
||||
Back to Players
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Player Status Overview -->
|
||||
<div class="card" style="margin-bottom: 2rem; background: {% if player.status == 'online' %}#d4edda{% elif player.status == 'offline' %}#f8d7da{% else %}#fff3cd{% endif %};">
|
||||
<h3 style="display: flex; align-items: center; gap: 0.5rem;">
|
||||
Status:
|
||||
{% if player.status == 'online' %}
|
||||
<span style="color: #28a745; display: flex; align-items: center; gap: 0.3rem;">
|
||||
<img src="{{ url_for('static', filename='icons/info.svg') }}" alt="" style="width: 20px; height: 20px; color: #28a745;">
|
||||
Online
|
||||
</span>
|
||||
{% elif player.status == 'offline' %}
|
||||
<span style="color: #dc3545; display: flex; align-items: center; gap: 0.3rem;">
|
||||
<img src="{{ url_for('static', filename='icons/warning.svg') }}" alt="" style="width: 20px; height: 20px; color: #dc3545;">
|
||||
Offline
|
||||
</span>
|
||||
{% else %}
|
||||
<span style="color: #ffc107; display: flex; align-items: center; gap: 0.3rem;">
|
||||
<img src="{{ url_for('static', filename='icons/info.svg') }}" alt="" style="width: 20px; height: 20px; color: #ffc107;">
|
||||
{{ player.status|title }}
|
||||
</span>
|
||||
{% endif %}
|
||||
</h3>
|
||||
<p><strong>Hostname:</strong> {{ player.hostname }}</p>
|
||||
<p><strong>Last Seen:</strong>
|
||||
{% if player.last_seen %}
|
||||
{{ player.last_seen.strftime('%Y-%m-%d %H:%M:%S') }}
|
||||
{% else %}
|
||||
Never
|
||||
{% endif %}
|
||||
</p>
|
||||
<p><strong>Assigned Playlist:</strong>
|
||||
{% if current_playlist %}
|
||||
<span style="color: #28a745; font-weight: bold;">{{ current_playlist.name }} (v{{ current_playlist.version }})</span>
|
||||
{% else %}
|
||||
<span style="color: #dc3545;">No playlist assigned</span>
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Three Column Layout -->
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(350px, 1fr)); gap: 1.5rem;">
|
||||
|
||||
<!-- Card 1: Edit Credentials -->
|
||||
<div class="card">
|
||||
<h2 style="display: flex; align-items: center; gap: 0.5rem;">
|
||||
<img src="{{ url_for('static', filename='icons/edit.svg') }}" alt="" style="width: 24px; height: 24px;">
|
||||
Edit Credentials
|
||||
</h2>
|
||||
<form method="POST" style="margin-top: 1rem;">
|
||||
<input type="hidden" name="action" value="update_credentials">
|
||||
|
||||
<div style="margin-bottom: 1rem;">
|
||||
<label for="name" style="display: block; margin-bottom: 0.5rem; font-weight: bold;">Player Name *</label>
|
||||
<input type="text" id="name" name="name" value="{{ player.name }}"
|
||||
required minlength="3"
|
||||
style="width: 100%; padding: 0.5rem; border: 1px solid #ddd; border-radius: 4px;">
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 1rem;">
|
||||
<label for="location" style="display: block; margin-bottom: 0.5rem; font-weight: bold;">Location</label>
|
||||
<input type="text" id="location" name="location" value="{{ player.location or '' }}"
|
||||
placeholder="e.g., Main Lobby"
|
||||
style="width: 100%; padding: 0.5rem; border: 1px solid #ddd; border-radius: 4px;">
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 1rem;">
|
||||
<label for="orientation" style="display: block; margin-bottom: 0.5rem; font-weight: bold;">Orientation</label>
|
||||
<select id="orientation" name="orientation"
|
||||
style="width: 100%; padding: 0.5rem; border: 1px solid #ddd; border-radius: 4px;">
|
||||
<option value="Landscape" {% if player.orientation == 'Landscape' %}selected{% endif %}>Landscape</option>
|
||||
<option value="Portrait" {% if player.orientation == 'Portrait' %}selected{% endif %}>Portrait</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div style="padding: 1rem; background: #f8f9fa; border-radius: 4px; margin-bottom: 1rem;">
|
||||
<p style="margin: 0; font-size: 0.9rem;"><strong>Hostname:</strong> {{ player.hostname }}</p>
|
||||
<p style="margin: 0.5rem 0 0 0; font-size: 0.9rem;"><strong>Auth Code:</strong> <code>{{ player.auth_code }}</code></p>
|
||||
<p style="margin: 0.5rem 0 0 0; font-size: 0.9rem;"><strong>Quick Connect:</strong> {{ player.quickconnect_code or 'Not set' }}</p>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-success" style="width: 100%; display: flex; align-items: center; justify-content: center; gap: 0.5rem;">
|
||||
<img src="{{ url_for('static', filename='icons/edit.svg') }}" alt="" style="width: 18px; height: 18px; filter: brightness(0) invert(1);">
|
||||
Save Changes
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Card 2: Assign Playlist -->
|
||||
<div class="card">
|
||||
<h2 style="display: flex; align-items: center; gap: 0.5rem;">
|
||||
<img src="{{ url_for('static', filename='icons/playlist.svg') }}" alt="" style="width: 24px; height: 24px;">
|
||||
Assign Playlist
|
||||
</h2>
|
||||
<form method="POST" style="margin-top: 1rem;">
|
||||
<input type="hidden" name="action" value="assign_playlist">
|
||||
|
||||
<div style="margin-bottom: 1rem;">
|
||||
<label for="playlist_id" style="display: block; margin-bottom: 0.5rem; font-weight: bold;">Select Playlist</label>
|
||||
<select id="playlist_id" name="playlist_id"
|
||||
style="width: 100%; padding: 0.5rem; border: 1px solid #ddd; border-radius: 4px;">
|
||||
<option value="">-- No Playlist (Unassign) --</option>
|
||||
{% for playlist in playlists %}
|
||||
<option value="{{ playlist.id }}"
|
||||
{% if player.playlist_id == playlist.id %}selected{% endif %}>
|
||||
{{ playlist.name }} (v{{ playlist.version }}) - {{ playlist.contents.count() }} items
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{% if current_playlist %}
|
||||
<div style="padding: 1rem; background: #d4edda; border-radius: 4px; margin-bottom: 1rem;">
|
||||
<h4 style="margin: 0 0 0.5rem 0; color: #155724;">Currently Assigned:</h4>
|
||||
<p style="margin: 0;"><strong>{{ current_playlist.name }}</strong></p>
|
||||
<p style="margin: 0.25rem 0 0 0; font-size: 0.9rem;">Version: {{ current_playlist.version }}</p>
|
||||
<p style="margin: 0.25rem 0 0 0; font-size: 0.9rem;">Content Items: {{ current_playlist.contents.count() }}</p>
|
||||
<p style="margin: 0.25rem 0 0 0; font-size: 0.9rem; color: #6c757d;">
|
||||
Updated: {{ current_playlist.updated_at.strftime('%Y-%m-%d %H:%M') }}
|
||||
</p>
|
||||
</div>
|
||||
{% else %}
|
||||
<div style="padding: 1rem; background: #fff3cd; border-radius: 4px; margin-bottom: 1rem;">
|
||||
<p style="margin: 0; color: #856404; display: flex; align-items: center; gap: 0.5rem;">
|
||||
<img src="{{ url_for('static', filename='icons/warning.svg') }}" alt="" style="width: 18px; height: 18px;">
|
||||
No playlist currently assigned to this player.
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<button type="submit" class="btn btn-success" style="width: 100%; display: flex; align-items: center; justify-content: center; gap: 0.5rem;">
|
||||
<img src="{{ url_for('static', filename='icons/playlist.svg') }}" alt="" style="width: 18px; height: 18px; filter: brightness(0) invert(1);">
|
||||
Assign Playlist
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<div style="margin-top: 1.5rem; padding-top: 1.5rem; border-top: 1px solid #ddd;">
|
||||
<h4>Quick Actions:</h4>
|
||||
<a href="{{ url_for('content.content_list') }}" class="btn" style="width: 100%; margin-top: 0.5rem; display: flex; align-items: center; justify-content: center; gap: 0.5rem;">
|
||||
<img src="{{ url_for('static', filename='icons/playlist.svg') }}" alt="" style="width: 18px; height: 18px; filter: brightness(0) invert(1);">
|
||||
Create New Playlist
|
||||
</a>
|
||||
{% if current_playlist %}
|
||||
<a href="{{ url_for('content.manage_playlist_content', playlist_id=current_playlist.id) }}"
|
||||
class="btn" style="width: 100%; margin-top: 0.5rem; display: flex; align-items: center; justify-content: center; gap: 0.5rem;">
|
||||
<img src="{{ url_for('static', filename='icons/edit.svg') }}" alt="" style="width: 18px; height: 18px; filter: brightness(0) invert(1);">
|
||||
Edit Current Playlist
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Card 3: Player Logs -->
|
||||
<div class="card">
|
||||
<h2 style="display: flex; align-items: center; gap: 0.5rem;">
|
||||
<img src="{{ url_for('static', filename='icons/info.svg') }}" alt="" style="width: 24px; height: 24px;">
|
||||
Player Logs
|
||||
</h2>
|
||||
<p style="color: #6c757d; font-size: 0.9rem;">Recent feedback from the player device</p>
|
||||
|
||||
<div style="max-height: 500px; overflow-y: auto; margin-top: 1rem;">
|
||||
{% if recent_logs %}
|
||||
{% for log in recent_logs %}
|
||||
<div style="padding: 0.75rem; margin-bottom: 0.5rem; border-left: 4px solid
|
||||
{% if log.status == 'error' %}#dc3545
|
||||
{% elif log.status == 'warning' %}#ffc107
|
||||
{% elif log.status == 'playing' %}#28a745
|
||||
{% else %}#17a2b8{% endif %};
|
||||
background: #f8f9fa; border-radius: 4px;">
|
||||
<div style="display: flex; justify-content: space-between; align-items: start;">
|
||||
<div style="flex: 1;">
|
||||
<strong style="color:
|
||||
{% if log.status == 'error' %}#dc3545
|
||||
{% elif log.status == 'warning' %}#ffc107
|
||||
{% elif log.status == 'playing' %}#28a745
|
||||
{% else %}#17a2b8{% endif %};">
|
||||
{% if log.status == 'error' %}❌
|
||||
{% elif log.status == 'warning' %}⚠️
|
||||
{% elif log.status == 'playing' %}▶️
|
||||
{% elif log.status == 'restarting' %}🔄
|
||||
{% else %}ℹ️{% endif %}
|
||||
{{ log.status|upper }}
|
||||
</strong>
|
||||
<p style="margin: 0.25rem 0 0 0; font-size: 0.9rem;">{{ log.message }}</p>
|
||||
{% if log.playlist_version %}
|
||||
<p style="margin: 0.25rem 0 0 0; font-size: 0.85rem; color: #6c757d;">
|
||||
Playlist v{{ log.playlist_version }}
|
||||
</p>
|
||||
{% endif %}
|
||||
{% if log.error_details %}
|
||||
<details style="margin-top: 0.5rem;">
|
||||
<summary style="cursor: pointer; font-size: 0.85rem; color: #dc3545;">Error Details</summary>
|
||||
<pre style="margin: 0.5rem 0 0 0; padding: 0.5rem; background: #fff; border: 1px solid #ddd; border-radius: 4px; font-size: 0.8rem; overflow-x: auto;">{{ log.error_details }}</pre>
|
||||
</details>
|
||||
{% endif %}
|
||||
</div>
|
||||
<small style="color: #6c757d; white-space: nowrap; margin-left: 1rem;">
|
||||
{{ log.timestamp.strftime('%m/%d %H:%M') }}
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<div style="text-align: center; padding: 2rem; color: #6c757d;">
|
||||
<p>📭 No logs received yet</p>
|
||||
<p style="font-size: 0.9rem;">Logs will appear here once the player starts sending feedback</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Additional Info Section -->
|
||||
<div class="card" style="margin-top: 2rem;">
|
||||
<h2>ℹ️ Player Information</h2>
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 1rem; margin-top: 1rem;">
|
||||
<div>
|
||||
<p><strong>Player ID:</strong> {{ player.id }}</p>
|
||||
<p><strong>Created:</strong> {{ player.created_at.strftime('%Y-%m-%d %H:%M') if player.created_at else 'N/A' }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p><strong>Orientation:</strong> {{ player.orientation }}</p>
|
||||
<p><strong>Location:</strong> {{ player.location or 'Not set' }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p><strong>Last Heartbeat:</strong>
|
||||
{% if player.last_heartbeat %}
|
||||
{{ player.last_heartbeat.strftime('%Y-%m-%d %H:%M:%S') }}
|
||||
{% else %}
|
||||
Never
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
@@ -27,8 +27,8 @@
|
||||
<a href="{{ url_for('players.edit_player', player_id=player.id) }}" class="btn btn-primary">
|
||||
✏️ Edit Player
|
||||
</a>
|
||||
<a href="{{ url_for('content.upload_content', target_type='player', target_id=player.id, return_url=url_for('players.player_page', player_id=player.id)) }}" class="btn btn-success">
|
||||
📤 Upload Content
|
||||
<a href="{{ url_for('playlist.manage_playlist', player_id=player.id) }}" class="btn btn-success">
|
||||
🎬 Manage Playlist
|
||||
</a>
|
||||
<a href="{{ url_for('players.list') }}" class="btn">
|
||||
← Back to Players
|
||||
@@ -62,18 +62,6 @@
|
||||
<td style="padding: 10px; font-weight: bold;">Orientation:</td>
|
||||
<td style="padding: 10px;">{{ player.orientation or 'Landscape' }}</td>
|
||||
</tr>
|
||||
<tr style="border-bottom: 1px solid #dee2e6;">
|
||||
<td style="padding: 10px; font-weight: bold;">Group:</td>
|
||||
<td style="padding: 10px;">
|
||||
{% if player.group %}
|
||||
<span style="background: #007bff; color: white; padding: 3px 8px; border-radius: 3px; font-size: 12px;">
|
||||
{{ player.group.name }}
|
||||
</span>
|
||||
{% else %}
|
||||
<span style="color: #6c757d;">No group</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 10px; font-weight: bold;">Created:</td>
|
||||
<td style="padding: 10px;">{{ player.created_at.strftime('%Y-%m-%d %H:%M') }}</td>
|
||||
@@ -138,77 +126,43 @@
|
||||
<!-- Playlist Management Card -->
|
||||
<div class="card" style="margin-bottom: 20px;">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px;">
|
||||
<h3 style="margin: 0;">🎬 Current Playlist</h3>
|
||||
<div>
|
||||
<a href="{{ url_for('content.upload_content', target_type='player', target_id=player.id, return_url=url_for('players.player_page', player_id=player.id)) }}"
|
||||
class="btn btn-success btn-sm">
|
||||
+ Add Content
|
||||
</a>
|
||||
</div>
|
||||
<h3 style="margin: 0;">🎬 Playlist Management</h3>
|
||||
</div>
|
||||
|
||||
{% if playlist %}
|
||||
<div style="background: #f8f9fa; padding: 10px; border-radius: 5px; margin-bottom: 15px;">
|
||||
<strong>Total Items:</strong> {{ playlist|length }} |
|
||||
<strong>Total Duration:</strong> {% set total_duration = namespace(value=0) %}{% for item in playlist %}{% set total_duration.value = total_duration.value + (item.duration or 10) %}{% endfor %}{{ total_duration.value }}s
|
||||
<div style="background: #f8f9fa; padding: 15px; border-radius: 5px; margin-bottom: 15px;">
|
||||
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px;">
|
||||
<div>
|
||||
<div style="font-size: 12px; color: #6c757d; margin-bottom: 5px;">Total Items</div>
|
||||
<div style="font-size: 24px; font-weight: bold; color: #333;">{{ playlist|length }}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style="font-size: 12px; color: #6c757d; margin-bottom: 5px;">Total Duration</div>
|
||||
<div style="font-size: 24px; font-weight: bold; color: #333;">
|
||||
{% set total_duration = namespace(value=0) %}
|
||||
{% for item in playlist %}
|
||||
{% set total_duration.value = total_duration.value + (item.duration or 10) %}
|
||||
{% endfor %}
|
||||
{{ total_duration.value }}s
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style="font-size: 12px; color: #6c757d; margin-bottom: 5px;">Playlist Version</div>
|
||||
<div style="font-size: 24px; font-weight: bold; color: #333;">{{ player.playlist_version }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<table style="width: 100%; border-collapse: collapse;">
|
||||
<thead>
|
||||
<tr style="background: #f8f9fa; text-align: left;">
|
||||
<th style="padding: 10px; border-bottom: 2px solid #dee2e6; width: 50px;">Order</th>
|
||||
<th style="padding: 10px; border-bottom: 2px solid #dee2e6;">File Name</th>
|
||||
<th style="padding: 10px; border-bottom: 2px solid #dee2e6;">Type</th>
|
||||
<th style="padding: 10px; border-bottom: 2px solid #dee2e6;">Duration</th>
|
||||
<th style="padding: 10px; border-bottom: 2px solid #dee2e6;">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="playlist-items">
|
||||
{% for item in playlist %}
|
||||
<tr style="border-bottom: 1px solid #dee2e6;" data-content-id="{{ item.id }}">
|
||||
<td style="padding: 10px; text-align: center;">
|
||||
<strong>{{ loop.index }}</strong>
|
||||
</td>
|
||||
<td style="padding: 10px;">
|
||||
{{ item.filename }}
|
||||
</td>
|
||||
<td style="padding: 10px;">
|
||||
{% if item.type == 'image' %}
|
||||
<span style="background: #28a745; color: white; padding: 3px 8px; border-radius: 3px; font-size: 12px;">📷 Image</span>
|
||||
{% elif item.type == 'video' %}
|
||||
<span style="background: #007bff; color: white; padding: 3px 8px; border-radius: 3px; font-size: 12px;">🎬 Video</span>
|
||||
{% elif item.type == 'pdf' %}
|
||||
<span style="background: #dc3545; color: white; padding: 3px 8px; border-radius: 3px; font-size: 12px;">📄 PDF</span>
|
||||
{% else %}
|
||||
<span style="background: #6c757d; color: white; padding: 3px 8px; border-radius: 3px; font-size: 12px;">📁 Other</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td style="padding: 10px;">
|
||||
{{ item.duration or 10 }}s
|
||||
</td>
|
||||
<td style="padding: 10px;">
|
||||
<button onclick="moveUp({{ item.id }})" class="btn btn-sm"
|
||||
style="background: #007bff; color: white; padding: 3px 8px; margin-right: 5px;"
|
||||
{% if loop.first %}disabled{% endif %}>
|
||||
↑
|
||||
</button>
|
||||
<button onclick="moveDown({{ item.id }})" class="btn btn-sm"
|
||||
style="background: #007bff; color: white; padding: 3px 8px; margin-right: 5px;"
|
||||
{% if loop.last %}disabled{% endif %}>
|
||||
↓
|
||||
</button>
|
||||
<button onclick="removeFromPlaylist({{ item.id }}, '{{ item.filename }}')"
|
||||
class="btn btn-danger btn-sm" style="padding: 3px 8px;">
|
||||
🗑️ Remove
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<div style="background: #fff3cd; border: 1px solid #ffc107; color: #856404; padding: 15px; border-radius: 5px; text-align: center;">
|
||||
⚠️ No content in playlist. <a href="{{ url_for('content.upload_content', target_type='player', target_id=player.id, return_url=url_for('players.player_page', player_id=player.id)) }}" style="color: #856404; text-decoration: underline;">Upload content</a> to get started.
|
||||
<a href="{{ url_for('playlist.manage_playlist', player_id=player.id) }}"
|
||||
class="btn btn-primary"
|
||||
style="display: inline-block; width: 100%; text-align: center; padding: 15px; font-size: 16px;">
|
||||
🎬 Open Playlist Manager
|
||||
</a>
|
||||
|
||||
{% if not playlist %}
|
||||
<div style="background: #fff3cd; border: 1px solid #ffc107; color: #856404; padding: 15px; border-radius: 5px; text-align: center; margin-top: 15px;">
|
||||
⚠️ No content in playlist. Open the playlist manager to add content.
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
@@ -270,62 +224,4 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function moveUp(contentId) {
|
||||
updatePlaylistOrder(contentId, 'up');
|
||||
}
|
||||
|
||||
function moveDown(contentId) {
|
||||
updatePlaylistOrder(contentId, 'down');
|
||||
}
|
||||
|
||||
function updatePlaylistOrder(contentId, direction) {
|
||||
fetch('/players/{{ player.id }}/playlist/reorder', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
content_id: contentId,
|
||||
direction: direction
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
location.reload();
|
||||
} else {
|
||||
alert('Error reordering playlist: ' + data.message);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
alert('Error reordering playlist: ' + error);
|
||||
});
|
||||
}
|
||||
|
||||
function removeFromPlaylist(contentId, filename) {
|
||||
if (confirm(`Remove "${filename}" from this player's playlist?`)) {
|
||||
fetch('/players/{{ player.id }}/playlist/remove', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
content_id: contentId
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
location.reload();
|
||||
} else {
|
||||
alert('Error removing content: ' + data.message);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
alert('Error removing content: ' + error);
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
<th style="padding: 12px; border-bottom: 2px solid #dee2e6;">Name</th>
|
||||
<th style="padding: 12px; border-bottom: 2px solid #dee2e6;">Hostname</th>
|
||||
<th style="padding: 12px; border-bottom: 2px solid #dee2e6;">Location</th>
|
||||
<th style="padding: 12px; border-bottom: 2px solid #dee2e6;">Group</th>
|
||||
<th style="padding: 12px; border-bottom: 2px solid #dee2e6;">Orientation</th>
|
||||
<th style="padding: 12px; border-bottom: 2px solid #dee2e6;">Status</th>
|
||||
<th style="padding: 12px; border-bottom: 2px solid #dee2e6;">Last Seen</th>
|
||||
@@ -36,13 +35,6 @@
|
||||
<td style="padding: 12px;">
|
||||
{{ player.location or '-' }}
|
||||
</td>
|
||||
<td style="padding: 12px;">
|
||||
{% if player.group %}
|
||||
<span style="background: #007bff; color: white; padding: 3px 8px; border-radius: 3px; font-size: 12px;">{{ player.group.name }}</span>
|
||||
{% else %}
|
||||
<span style="color: #6c757d;">No group</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td style="padding: 12px;">
|
||||
{{ player.orientation or 'Landscape' }}
|
||||
</td>
|
||||
@@ -62,25 +54,10 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
<td style="padding: 12px;">
|
||||
<a href="{{ url_for('players.player_page', player_id=player.id) }}"
|
||||
class="btn btn-info btn-sm" title="View" style="margin-right: 5px;">
|
||||
👁️ View
|
||||
<a href="{{ url_for('players.manage_player', player_id=player.id) }}"
|
||||
class="btn btn-info btn-sm" title="Manage Player">
|
||||
⚙️ Manage
|
||||
</a>
|
||||
<a href="{{ url_for('players.edit_player', player_id=player.id) }}"
|
||||
class="btn btn-primary btn-sm" title="Edit" style="margin-right: 5px;">
|
||||
✏️ Edit
|
||||
</a>
|
||||
<a href="{{ url_for('players.player_fullscreen', player_id=player.id) }}"
|
||||
class="btn btn-success btn-sm" title="Fullscreen" target="_blank" style="margin-right: 5px;">
|
||||
⛶ Full
|
||||
</a>
|
||||
<form method="POST" action="{{ url_for('players.delete_player', player_id=player.id) }}"
|
||||
style="display: inline;"
|
||||
onsubmit="return confirm('Are you sure you want to delete player \'{{ player.name }}\'?');">
|
||||
<button type="submit" class="btn btn-danger btn-sm" title="Delete">
|
||||
🗑️ Delete
|
||||
</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
Reference in New Issue
Block a user