updated features to upload pptx files

This commit is contained in:
DigiServer Developer
2025-11-15 01:26:12 +02:00
parent 9d4f932a95
commit 930a5bf636
24 changed files with 1963 additions and 2218 deletions

View File

@@ -219,6 +219,92 @@
.duration-input {
width: 80px;
text-align: center;
transition: all 0.3s ease;
}
.duration-input:hover {
border-color: #667eea;
box-shadow: 0 0 0 2px rgba(102, 126, 234, 0.1);
}
.duration-input:focus {
border-color: #667eea;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.2);
}
.save-duration-btn {
transition: all 0.2s ease;
animation: fadeIn 0.2s ease;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: scale(0.8);
}
to {
opacity: 1;
transform: scale(1);
}
}
/* Dark mode support */
body.dark-mode .playlist-section {
background: #2d3748;
color: #e2e8f0;
}
body.dark-mode .section-header h2 {
color: #e2e8f0;
}
body.dark-mode .section-header {
border-bottom-color: #4a5568;
}
body.dark-mode .playlist-table thead {
background: #1a202c;
}
body.dark-mode .playlist-table th {
color: #cbd5e0;
border-bottom-color: #4a5568;
}
body.dark-mode .playlist-table td {
border-bottom-color: #4a5568;
color: #e2e8f0;
}
body.dark-mode .playlist-table tr:hover {
background: #1a202c;
}
body.dark-mode .form-control {
background: #1a202c;
border-color: #4a5568;
color: #e2e8f0;
}
body.dark-mode .form-control:focus {
border-color: #667eea;
background: #2d3748;
}
body.dark-mode .add-content-form {
background: #1a202c;
}
body.dark-mode .form-group label {
color: #e2e8f0;
}
body.dark-mode .empty-state {
color: #718096;
}
body.dark-mode .drag-handle {
color: #718096;
}
</style>
@@ -290,9 +376,9 @@
</thead>
<tbody id="playlist-tbody">
{% for content in playlist_content %}
<tr class="draggable-row" draggable="true" data-content-id="{{ content.id }}">
<tr class="draggable-row" data-content-id="{{ content.id }}">
<td>
<span class="drag-handle">⋮⋮</span>
<span class="drag-handle" draggable="true">⋮⋮</span>
</td>
<td>{{ loop.index }}</td>
<td>{{ content.filename }}</td>
@@ -304,11 +390,28 @@
{% endif %}
</td>
<td>
<input type="number"
class="form-control duration-input"
value="{{ content.duration }}"
min="1"
onchange="updateDuration({{ content.id }}, this.value)">
<div style="display: flex; align-items: center; gap: 5px;">
<input type="number"
class="form-control duration-input"
id="duration-{{ content.id }}"
value="{{ content._playlist_duration }}"
min="1"
draggable="false"
onclick="event.stopPropagation()"
onmousedown="event.stopPropagation()"
oninput="markDurationChanged({{ content.id }})"
onkeypress="if(event.key==='Enter') saveDuration({{ content.id }})"
style="width: 60px; padding: 5px 8px;">
<button type="button"
class="btn btn-success btn-sm save-duration-btn"
id="save-btn-{{ content.id }}"
onclick="event.stopPropagation(); saveDuration({{ content.id }})"
onmousedown="event.stopPropagation()"
style="display: none; padding: 5px 10px; font-size: 12px; cursor: pointer;"
title="Save duration (or press Enter)">
💾
</button>
</div>
</td>
<td>{{ "%.2f"|format(content.file_size_mb) }} MB</td>
<td>
@@ -335,7 +438,7 @@
</div>
<!-- Add Content Section -->
{% if available_files %}
{% if available_content %}
<div class="playlist-section">
<div class="section-header">
<h2> Add Existing Content</h2>
@@ -344,11 +447,11 @@
<form method="POST" action="{{ url_for('playlist.add_to_playlist', player_id=player.id) }}"
class="add-content-form">
<div class="form-group">
<label for="filename">Select File:</label>
<select name="filename" id="filename" class="form-control" required>
<option value="" disabled selected>Choose a file...</option>
{% for filename in available_files %}
<option value="{{ filename }}">{{ filename }}</option>
<label for="content_id">Select Content:</label>
<select name="content_id" id="content_id" class="form-control" required>
<option value="" disabled selected>Choose content...</option>
{% for content in available_content %}
<option value="{{ content.id }}">{{ content.filename }} ({{ content.content_type }})</option>
{% endfor %}
</select>
</div>
@@ -380,20 +483,41 @@ document.addEventListener('DOMContentLoaded', function() {
const tbody = document.getElementById('playlist-tbody');
if (!tbody) return;
const rows = tbody.querySelectorAll('.draggable-row');
// Set up drag handles
const dragHandles = tbody.querySelectorAll('.drag-handle');
dragHandles.forEach(handle => {
handle.addEventListener('dragstart', handleDragStart);
});
// Set up drop zones on rows
const rows = tbody.querySelectorAll('.draggable-row');
rows.forEach(row => {
row.addEventListener('dragstart', handleDragStart);
row.addEventListener('dragover', handleDragOver);
row.addEventListener('drop', handleDrop);
row.addEventListener('dragend', handleDragEnd);
});
// Prevent dragging from inputs and buttons
const inputs = document.querySelectorAll('.duration-input, button');
inputs.forEach(input => {
input.addEventListener('mousedown', (e) => {
e.stopPropagation();
});
input.addEventListener('click', (e) => {
e.stopPropagation();
});
});
});
function handleDragStart(e) {
draggedElement = this;
this.classList.add('dragging');
// Get the parent row
const row = e.target.closest('.draggable-row');
if (!row) return;
draggedElement = row;
row.classList.add('dragging');
e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData('text/html', row.innerHTML);
}
function handleDragOver(e) {
@@ -464,7 +588,41 @@ function saveOrder() {
});
}
function updateDuration(contentId, duration) {
function markDurationChanged(contentId) {
const saveBtn = document.getElementById(`save-btn-${contentId}`);
const input = document.getElementById(`duration-${contentId}`);
// Show save button if value changed
if (input.value !== input.defaultValue) {
saveBtn.style.display = 'inline-block';
input.style.borderColor = '#ffc107';
} else {
saveBtn.style.display = 'none';
input.style.borderColor = '';
}
}
function saveDuration(contentId) {
const inputElement = document.getElementById(`duration-${contentId}`);
const saveBtn = document.getElementById(`save-btn-${contentId}`);
const duration = parseInt(inputElement.value);
// Validate duration
if (duration < 1) {
alert('Duration must be at least 1 second');
inputElement.value = inputElement.defaultValue;
inputElement.style.borderColor = '';
saveBtn.style.display = 'none';
return;
}
const originalValue = inputElement.defaultValue;
// Visual feedback
inputElement.disabled = true;
saveBtn.disabled = true;
saveBtn.textContent = '⏳';
const formData = new FormData();
formData.append('duration', duration);
@@ -476,15 +634,65 @@ function updateDuration(contentId, duration) {
.then(data => {
if (data.success) {
console.log('Duration updated successfully');
// Update total duration
location.reload();
inputElement.style.borderColor = '#28a745';
inputElement.defaultValue = duration;
saveBtn.textContent = '✓';
// Update total duration display
updateTotalDuration();
setTimeout(() => {
inputElement.style.borderColor = '';
inputElement.disabled = false;
saveBtn.style.display = 'none';
saveBtn.textContent = '💾';
saveBtn.disabled = false;
}, 1500);
} else {
inputElement.style.borderColor = '#dc3545';
inputElement.value = originalValue;
saveBtn.textContent = '✖';
alert('Error updating duration: ' + data.message);
setTimeout(() => {
inputElement.disabled = false;
inputElement.style.borderColor = '';
saveBtn.style.display = 'none';
saveBtn.textContent = '💾';
saveBtn.disabled = false;
}, 1500);
}
})
.catch(error => {
console.error('Error:', error);
inputElement.style.borderColor = '#dc3545';
inputElement.value = originalValue;
saveBtn.textContent = '✖';
alert('Error updating duration');
setTimeout(() => {
inputElement.disabled = false;
inputElement.style.borderColor = '';
saveBtn.style.display = 'none';
saveBtn.textContent = '💾';
saveBtn.disabled = false;
}, 1500);
});
}
function updateTotalDuration() {
const durationInputs = document.querySelectorAll('.duration-input');
let total = 0;
durationInputs.forEach(input => {
total += parseInt(input.value) || 0;
});
const statValues = document.querySelectorAll('.stat-value');
statValues.forEach((element, index) => {
const label = element.parentElement.querySelector('.stat-label');
if (label && label.textContent.includes('Total Duration')) {
element.textContent = total + 's';
}
});
}
</script>