Files
Ske_Signage/app/templates/player/view.html
2025-07-16 16:08:40 +03:00

355 lines
16 KiB
HTML

{% extends "base.html" %}
{% block title %}{{ player.username }} - Player View{% endblock %}
{% block content %}
<div class="container-fluid py-4">
<!-- Page Header -->
<div class="row mb-4">
<div class="col">
<h1><i class="bi bi-display"></i> {{ player.username }}</h1>
<p class="text-muted">Player details and content management</p>
</div>
<div class="col-auto">
<a href="{{ url_for('dashboard.index') }}" class="btn btn-secondary">
<i class="bi bi-arrow-left"></i> Back to Dashboard
</a>
<a href="{{ url_for('player.edit', player_id=player.id) }}" class="btn btn-primary">
<i class="bi bi-pencil"></i> Edit Player
</a>
</div>
</div>
<div class="row">
<!-- Player Information -->
<div class="col-md-4">
<div class="card">
<div class="card-header">
<h5><i class="bi bi-info-circle"></i> Player Information</h5>
</div>
<div class="card-body">
<div class="row mb-2">
<div class="col-sm-5"><strong>Username:</strong></div>
<div class="col-sm-7">{{ player.username }}</div>
</div>
<div class="row mb-2">
<div class="col-sm-5"><strong>Hostname:</strong></div>
<div class="col-sm-7"><code>{{ player.hostname }}</code></div>
</div>
<div class="row mb-2">
<div class="col-sm-5"><strong>Status:</strong></div>
<div class="col-sm-7">
{% if player.is_active %}
<span class="badge bg-success">Active</span>
{% else %}
<span class="badge bg-secondary">Inactive</span>
{% endif %}
</div>
</div>
<div class="row mb-2">
<div class="col-sm-5"><strong>Created:</strong></div>
<div class="col-sm-7">{{ player.created_at.strftime('%Y-%m-%d %H:%M') if player.created_at else 'N/A' }}</div>
</div>
<div class="row mb-2">
<div class="col-sm-5"><strong>Last Seen:</strong></div>
<div class="col-sm-7">
{% if player.last_seen %}
{{ player.last_seen.strftime('%Y-%m-%d %H:%M') }}
{% else %}
<span class="text-muted">Never</span>
{% endif %}
</div>
</div>
<div class="row mb-2">
<div class="col-sm-5"><strong>Groups:</strong></div>
<div class="col-sm-7">
{% if player.groups %}
{% for group in player.groups %}
<span class="badge bg-info me-1">{{ group.name }}</span>
{% endfor %}
{% else %}
<span class="text-muted">No groups</span>
{% endif %}
</div>
</div>
</div>
</div>
<!-- Quick Actions -->
<div class="card mt-3">
<div class="card-header">
<h6><i class="bi bi-lightning"></i> Quick Actions</h6>
</div>
<div class="card-body">
<div class="d-grid gap-2">
<a href="{{ url_for('player.fullscreen', player_id=player.id) }}"
class="btn btn-info" target="_blank">
<i class="bi bi-fullscreen"></i> Open Display
</a>
<button type="button" class="btn btn-success" onclick="refreshPlayer()">
<i class="bi bi-arrow-clockwise"></i> Refresh Content
</button>
</div>
</div>
</div>
</div>
<!-- Content Management -->
<div class="col-md-8">
<div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
<h5><i class="bi bi-collection-play"></i> Player Content</h5>
<a href="{{ url_for('content.upload') }}" class="btn btn-sm btn-primary">
<i class="bi bi-plus"></i> Add Content
</a>
</div>
<div class="card-body">
{% if content %}
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>Position</th>
<th>Filename</th>
<th>Type</th>
<th>Duration</th>
<th>Uploaded</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for item in content %}
<tr>
<td>
<span class="badge bg-primary">{{ item.position }}</span>
</td>
<td>
<strong>{{ item.file_name }}</strong>
{% if item.original_name %}
<br><small class="text-muted">{{ item.original_name }}</small>
{% endif %}
</td>
<td>
{% if item.content_type == 'image' %}
<span class="badge bg-success"><i class="bi bi-image"></i> Image</span>
{% elif item.content_type == 'video' %}
<span class="badge bg-info"><i class="bi bi-play-circle"></i> Video</span>
{% else %}
<span class="badge bg-secondary">{{ item.content_type }}</span>
{% endif %}
</td>
<td>{{ item.duration }}s</td>
<td>{{ item.uploaded_at.strftime('%m/%d %H:%M') if item.uploaded_at else 'N/A' }}</td>
<td>
<div class="btn-group btn-group-sm">
<button type="button" class="btn btn-outline-primary"
onclick="previewContent('{{ item.id }}', '{{ item.file_name }}', '{{ item.content_type }}')">
<i class="bi bi-eye"></i>
</button>
<button type="button" class="btn btn-outline-warning"
onclick="editContent('{{ item.id }}', '{{ item.file_name }}', {{ item.duration }})">
<i class="bi bi-pencil"></i>
</button>
<button type="button" class="btn btn-outline-danger"
onclick="removeContent('{{ item.id }}', '{{ item.file_name }}')">
<i class="bi bi-trash"></i>
</button>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="text-center py-4">
<i class="bi bi-collection-play text-muted" style="font-size: 3rem;"></i>
<h5 class="text-muted mt-2">No Content Available</h5>
<p class="text-muted">This player doesn't have any content assigned yet.</p>
<a href="{{ url_for('content.upload') }}" class="btn btn-primary">
<i class="bi bi-plus"></i> Upload First Content
</a>
</div>
{% endif %}
</div>
</div>
</div>
</div>
</div>
<!-- Content Preview Modal -->
<div class="modal fade" id="previewModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Content Preview</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body text-center" id="previewContent">
<!-- Content will be loaded here -->
</div>
</div>
</div>
</div>
<!-- Remove Content Modal -->
<div class="modal fade" id="removeModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Remove Content</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<p>Are you sure you want to remove <strong id="removeFilename"></strong> from this player?</p>
<p class="text-warning small">This will only remove the content from this player, not delete the file.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-danger" onclick="confirmRemoveContent()">Remove Content</button>
</div>
</div>
</div>
</div>
<!-- Edit Content Modal -->
<div class="modal fade" id="editModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Edit Content Duration</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<p>Edit display duration for <strong id="editFilename"></strong></p>
<div class="mb-3">
<label for="editDuration" class="form-label">Duration (seconds)</label>
<input type="number" class="form-control" id="editDuration" min="1" max="300" required>
<div class="form-text">How long should this content be displayed? (1-300 seconds)</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" onclick="confirmEditContent()">Update Duration</button>
</div>
</div>
</div>
</div>
<script>
let currentContentId = null;
function refreshPlayer() {
// Placeholder for content refresh functionality
alert('Content refresh signal sent to player!');
}
function previewContent(contentId, filename, contentType) {
console.log('Preview function called:', {contentId, filename, contentType});
const modal = new bootstrap.Modal(document.getElementById('previewModal'));
const previewDiv = document.getElementById('previewContent');
if (contentType === 'image') {
const imgSrc = `/static/uploads/${filename}`;
console.log('Loading image from:', imgSrc);
previewDiv.innerHTML = `<img src="${imgSrc}" class="img-fluid" alt="${filename}"
onload="console.log('Image loaded successfully')"
onerror="console.error('Failed to load image:', this.src)">`;
} else if (contentType === 'video') {
const videoSrc = `/static/uploads/${filename}`;
console.log('Loading video from:', videoSrc);
previewDiv.innerHTML = `<video controls class="w-100" style="max-height: 400px;">
<source src="${videoSrc}">
Your browser does not support the video tag.
</video>`;
} else {
console.log('Unsupported content type:', contentType);
previewDiv.innerHTML = `<p>Preview not available for this content type: ${contentType}</p>`;
}
modal.show();
}
function removeContent(contentId, filename) {
currentContentId = contentId;
document.getElementById('removeFilename').textContent = filename;
const modal = new bootstrap.Modal(document.getElementById('removeModal'));
modal.show();
}
function editContent(contentId, filename, currentDuration) {
currentContentId = contentId;
document.getElementById('editFilename').textContent = filename;
document.getElementById('editDuration').value = currentDuration;
const modal = new bootstrap.Modal(document.getElementById('editModal'));
modal.show();
}
function confirmEditContent() {
if (currentContentId) {
const newDuration = parseInt(document.getElementById('editDuration').value);
if (!newDuration || newDuration < 1 || newDuration > 300) {
alert('Please enter a valid duration between 1 and 300 seconds.');
return;
}
// Make API call to update content duration
fetch(`/api/content/${currentContentId}/edit`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
duration: newDuration
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
location.reload();
} else {
alert('Error updating content: ' + data.message);
}
})
.catch(error => {
console.error('Error:', error);
alert('Error updating content');
});
// Close modal
const modal = bootstrap.Modal.getInstance(document.getElementById('editModal'));
modal.hide();
}
}
function confirmRemoveContent() {
if (currentContentId) {
// Make API call to remove content from player
fetch(`/api/content/${currentContentId}/remove-from-player`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
player_id: {{ player.id|tojson }}
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
location.reload();
} else {
alert('Error removing content: ' + data.message);
}
})
.catch(error => {
console.error('Error:', error);
alert('Error removing content');
});
}
}
</script>
{% endblock %}