updated features to upload pptx files
This commit is contained in:
@@ -5,14 +5,15 @@
|
||||
{% block content %}
|
||||
<style>
|
||||
.upload-container {
|
||||
max-width: 900px;
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.upload-zone {
|
||||
border: 3px dashed #ced4da;
|
||||
border-radius: 12px;
|
||||
padding: 60px 40px;
|
||||
border: 2px dashed #ced4da;
|
||||
border-radius: 8px;
|
||||
padding: 25px 20px;
|
||||
text-align: center;
|
||||
background: #f8f9fa;
|
||||
transition: all 0.3s;
|
||||
@@ -54,18 +55,21 @@
|
||||
}
|
||||
|
||||
.file-list {
|
||||
margin-top: 20px;
|
||||
margin-top: 15px;
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.file-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 12px;
|
||||
padding: 8px 10px;
|
||||
background: #fff;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 6px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
body.dark-mode .file-item {
|
||||
@@ -80,7 +84,7 @@
|
||||
}
|
||||
|
||||
.file-icon {
|
||||
font-size: 24px;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.remove-file {
|
||||
@@ -97,7 +101,7 @@
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 20px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.form-group label {
|
||||
@@ -205,106 +209,100 @@
|
||||
</style>
|
||||
|
||||
<div class="upload-container">
|
||||
<div style="margin-bottom: 30px; display: flex; justify-content: space-between; align-items: center;">
|
||||
<h1 style="display: flex; align-items: center; gap: 0.5rem;">
|
||||
<img src="{{ url_for('static', filename='icons/upload.svg') }}" alt="" style="width: 32px; height: 32px;">
|
||||
Upload Media Files
|
||||
<div style="margin-bottom: 20px; display: flex; justify-content: space-between; align-items: center;">
|
||||
<h1 style="display: flex; align-items: center; gap: 0.5rem; font-size: 24px; margin: 0;">
|
||||
<img src="{{ url_for('static', filename='icons/upload.svg') }}" alt="" style="width: 28px; height: 28px;">
|
||||
Upload Media
|
||||
</h1>
|
||||
<a href="{{ url_for('content.content_list') }}" class="btn" style="display: flex; align-items: center; gap: 0.5rem;">
|
||||
<img src="{{ url_for('static', filename='icons/playlist.svg') }}" alt="" style="width: 18px; height: 18px; filter: brightness(0) invert(1);">
|
||||
<a href="{{ url_for('content.content_list') }}" class="btn" style="display: flex; align-items: center; gap: 0.5rem; padding: 8px 16px;">
|
||||
<img src="{{ url_for('static', filename='icons/playlist.svg') }}" alt="" style="width: 16px; height: 16px; filter: brightness(0) invert(1);">
|
||||
Back to Playlists
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<form id="upload-form" method="POST" action="{{ url_for('content.upload_media') }}" enctype="multipart/form-data">
|
||||
|
||||
<!-- Playlist Selector -->
|
||||
<div class="card" style="margin-bottom: 30px;">
|
||||
<h2 style="margin-bottom: 15px;">📋 Select Target Playlist (Optional)</h2>
|
||||
<p style="color: #6c757d; margin-bottom: 20px;">
|
||||
Choose a playlist to directly add uploaded files, or leave blank to add to media library only.
|
||||
</p>
|
||||
<!-- Compact Two-Column Layout -->
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">
|
||||
|
||||
<div class="form-group">
|
||||
<label for="playlist_id">Target Playlist</label>
|
||||
<select name="playlist_id" id="playlist_id" class="form-control">
|
||||
<option value="">-- Media Library Only (Don't add to playlist) --</option>
|
||||
{% for playlist in playlists %}
|
||||
<option value="{{ playlist.id }}">
|
||||
{{ playlist.name }} ({{ playlist.orientation }}) - v{{ playlist.version }} - {{ playlist.content_count }} items
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<small style="color: #6c757d; display: block; margin-top: 5px;">
|
||||
💡 Tip: You can add files to playlists later from the media library
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Upload Zone -->
|
||||
<div class="card" style="margin-bottom: 30px;">
|
||||
<h2 style="margin-bottom: 20px; display: flex; align-items: center; gap: 0.5rem;">
|
||||
<img src="{{ url_for('static', filename='icons/upload.svg') }}" alt="" style="width: 24px; height: 24px;">
|
||||
Select Files
|
||||
</h2>
|
||||
|
||||
<div class="upload-zone" id="upload-zone">
|
||||
<img src="{{ url_for('static', filename='icons/upload.svg') }}" alt="" style="width: 96px; height: 96px; opacity: 0.3; margin-bottom: 20px;">
|
||||
<h3 style="margin-bottom: 10px;">Drag and Drop Files Here</h3>
|
||||
<p style="color: #6c757d; margin: 15px 0;">or</p>
|
||||
<div class="file-input-wrapper">
|
||||
<label for="file-input" class="btn btn-primary" style="display: inline-flex; align-items: center; gap: 0.5rem;">
|
||||
<img src="{{ url_for('static', filename='icons/upload.svg') }}" alt="" style="width: 18px; height: 18px; filter: brightness(0) invert(1);">
|
||||
Browse Files
|
||||
</label>
|
||||
<input type="file" id="file-input" name="files" multiple
|
||||
accept="image/*,video/*,.pdf,.ppt,.pptx">
|
||||
<!-- Left Column: Upload Zone -->
|
||||
<div class="card">
|
||||
<h2 style="margin-bottom: 15px; font-size: 18px; display: flex; align-items: center; gap: 0.5rem;">
|
||||
<img src="{{ url_for('static', filename='icons/upload.svg') }}" alt="" style="width: 20px; height: 20px;">
|
||||
Select Files
|
||||
</h2>
|
||||
|
||||
<div class="upload-zone" id="upload-zone">
|
||||
<img src="{{ url_for('static', filename='icons/upload.svg') }}" alt="" style="width: 48px; height: 48px; opacity: 0.3; margin-bottom: 10px;">
|
||||
<h3 style="margin-bottom: 8px; font-size: 16px;">Drag & Drop</h3>
|
||||
<p style="color: #6c757d; margin: 8px 0; font-size: 13px;">or</p>
|
||||
<div class="file-input-wrapper">
|
||||
<label for="file-input" class="btn btn-primary" style="display: inline-flex; align-items: center; gap: 0.5rem; padding: 8px 16px; font-size: 14px;">
|
||||
<img src="{{ url_for('static', filename='icons/upload.svg') }}" alt="" style="width: 16px; height: 16px; filter: brightness(0) invert(1);">
|
||||
Browse
|
||||
</label>
|
||||
<input type="file" id="file-input" name="files" multiple
|
||||
accept="image/*,video/*,.pdf,.ppt,.pptx">
|
||||
</div>
|
||||
<p style="font-size: 11px; color: #999; margin-top: 12px; line-height: 1.4;">
|
||||
<strong>Supported:</strong> JPG, PNG, GIF, MP4, AVI, MOV, PDF, PPT
|
||||
</p>
|
||||
</div>
|
||||
<p style="font-size: 14px; color: #999; margin-top: 20px;">
|
||||
<strong>Supported formats:</strong><br>
|
||||
Images: JPG, PNG, GIF, BMP<br>
|
||||
Videos: MP4, AVI, MOV, MKV, WEBM<br>
|
||||
Documents: PDF, PPT, PPTX
|
||||
</p>
|
||||
|
||||
<div id="file-list" class="file-list"></div>
|
||||
</div>
|
||||
|
||||
<div id="file-list" class="file-list"></div>
|
||||
</div>
|
||||
|
||||
<!-- Upload Settings -->
|
||||
<div class="card" style="margin-bottom: 30px;">
|
||||
<h2 style="margin-bottom: 20px; display: flex; align-items: center; gap: 0.5rem;">
|
||||
<img src="{{ url_for('static', filename='icons/info.svg') }}" alt="" style="width: 24px; height: 24px;">
|
||||
Upload Settings
|
||||
</h2>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="content_type">Media Type</label>
|
||||
<select name="content_type" id="content_type" class="form-control">
|
||||
<option value="image">Image</option>
|
||||
<option value="video">Video</option>
|
||||
<option value="pdf">PDF Document</option>
|
||||
</select>
|
||||
<small style="color: #6c757d; display: block; margin-top: 5px;">
|
||||
This will be auto-detected from file extension
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="duration">Default Duration (seconds)</label>
|
||||
<input type="number" name="duration" id="duration" class="form-control"
|
||||
value="10" min="1" max="300">
|
||||
<small style="color: #6c757d; display: block; margin-top: 5px;">
|
||||
How long each item should display (for images and PDFs)
|
||||
</small>
|
||||
<!-- Right Column: Settings -->
|
||||
<div class="card">
|
||||
<h2 style="margin-bottom: 15px; font-size: 18px; display: flex; align-items: center; gap: 0.5rem;">
|
||||
<img src="{{ url_for('static', filename='icons/info.svg') }}" alt="" style="width: 20px; height: 20px;">
|
||||
Upload Settings
|
||||
</h2>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="playlist_id">Target Playlist (Optional)</label>
|
||||
<select name="playlist_id" id="playlist_id" class="form-control">
|
||||
<option value="">-- Media Library Only --</option>
|
||||
{% for playlist in playlists %}
|
||||
<option value="{{ playlist.id }}">
|
||||
{{ playlist.name }} ({{ playlist.orientation }}) - {{ playlist.content_count }} items
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<small style="color: #6c757d; display: block; margin-top: 4px; font-size: 11px;">
|
||||
💡 Add to playlists later if needed
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="content_type">Media Type</label>
|
||||
<select name="content_type" id="content_type" class="form-control">
|
||||
<option value="image">Image</option>
|
||||
<option value="video">Video</option>
|
||||
<option value="pdf">PDF</option>
|
||||
<option value="pptx">PPTX</option>
|
||||
</select>
|
||||
<small style="color: #6c757d; display: block; margin-top: 4px; font-size: 11px;">
|
||||
Auto-detected from file extension
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="duration">Default Duration (seconds)</label>
|
||||
<input type="number" name="duration" id="duration" class="form-control"
|
||||
value="10" min="1" max="300">
|
||||
<small style="color: #6c757d; display: block; margin-top: 4px; font-size: 11px;">
|
||||
Display time for images and PDFs
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<!-- Upload Button -->
|
||||
<button type="submit" class="btn-upload" id="upload-btn" disabled style="display: flex; align-items: center; justify-content: center; gap: 0.5rem; margin-top: 20px; padding: 12px 30px;">
|
||||
<img src="{{ url_for('static', filename='icons/upload.svg') }}" alt="" style="width: 18px; height: 18px; filter: brightness(0) invert(1);">
|
||||
Upload Files
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Upload Button -->
|
||||
<button type="submit" class="btn-upload" id="upload-btn" disabled style="display: flex; align-items: center; justify-content: center; gap: 0.5rem;">
|
||||
<img src="{{ url_for('static', filename='icons/upload.svg') }}" alt="" style="width: 20px; height: 20px; filter: brightness(0) invert(1);">
|
||||
Upload Files
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -350,18 +348,97 @@
|
||||
|
||||
// Handle file input
|
||||
fileInput.addEventListener('change', (e) => {
|
||||
handleFiles(e.target.files);
|
||||
console.log('File input changed, files:', e.target.files.length);
|
||||
if (e.target.files.length > 0) {
|
||||
handleFiles(e.target.files);
|
||||
}
|
||||
});
|
||||
|
||||
// Click upload zone to trigger file input
|
||||
uploadZone.addEventListener('click', () => {
|
||||
// Click upload zone to trigger file input (but not if clicking on the label)
|
||||
uploadZone.addEventListener('click', (e) => {
|
||||
// Don't trigger if clicking on the label or button
|
||||
if (e.target.tagName === 'LABEL' || e.target.closest('label') || e.target.tagName === 'INPUT') {
|
||||
return;
|
||||
}
|
||||
fileInput.click();
|
||||
});
|
||||
|
||||
function handleFiles(files) {
|
||||
console.log('handleFiles called with', files.length, 'file(s)');
|
||||
selectedFiles = Array.from(files);
|
||||
displayFiles();
|
||||
uploadBtn.disabled = selectedFiles.length === 0;
|
||||
|
||||
// Auto-detect media type and duration from first file
|
||||
if (selectedFiles.length > 0) {
|
||||
console.log('Auto-detecting for first file:', selectedFiles[0].name);
|
||||
autoDetectMediaType(selectedFiles[0]);
|
||||
autoDetectDuration(selectedFiles[0]);
|
||||
}
|
||||
}
|
||||
|
||||
function autoDetectMediaType(file) {
|
||||
const ext = file.name.split('.').pop().toLowerCase();
|
||||
const contentTypeSelect = document.getElementById('content_type');
|
||||
|
||||
console.log('Auto-detecting media type for:', file.name, 'Extension:', ext);
|
||||
|
||||
if (['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].includes(ext)) {
|
||||
contentTypeSelect.value = 'image';
|
||||
console.log('Set type to: image');
|
||||
} else if (['mp4', 'avi', 'mov', 'mkv', 'webm', 'flv', 'wmv'].includes(ext)) {
|
||||
contentTypeSelect.value = 'video';
|
||||
console.log('Set type to: video');
|
||||
} else if (ext === 'pdf') {
|
||||
contentTypeSelect.value = 'pdf';
|
||||
console.log('Set type to: pdf');
|
||||
} else if (['ppt', 'pptx'].includes(ext)) {
|
||||
contentTypeSelect.value = 'pptx';
|
||||
console.log('Set type to: pptx');
|
||||
}
|
||||
}
|
||||
|
||||
function autoDetectDuration(file) {
|
||||
const ext = file.name.split('.').pop().toLowerCase();
|
||||
const durationInput = document.getElementById('duration');
|
||||
|
||||
console.log('Auto-detecting duration for:', file.name, 'Extension:', ext);
|
||||
|
||||
// For videos, try to get actual duration
|
||||
if (['mp4', 'avi', 'mov', 'mkv', 'webm', 'flv', 'wmv'].includes(ext)) {
|
||||
console.log('Processing as video...');
|
||||
const video = document.createElement('video');
|
||||
video.preload = 'metadata';
|
||||
|
||||
video.onloadedmetadata = function() {
|
||||
window.URL.revokeObjectURL(video.src);
|
||||
const duration = Math.ceil(video.duration);
|
||||
console.log('Video duration detected:', duration, 'seconds');
|
||||
if (duration && duration > 0) {
|
||||
durationInput.value = duration;
|
||||
}
|
||||
};
|
||||
|
||||
video.onerror = function() {
|
||||
console.log('Video loading error, using default 30s');
|
||||
window.URL.revokeObjectURL(video.src);
|
||||
durationInput.value = 30; // Default for videos if can't read duration
|
||||
};
|
||||
|
||||
video.src = URL.createObjectURL(file);
|
||||
} else if (['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].includes(ext)) {
|
||||
// Images: default 10 seconds
|
||||
console.log('Setting image duration: 10s');
|
||||
durationInput.value = 10;
|
||||
} else if (ext === 'pdf') {
|
||||
// PDFs: default 15 seconds per page (estimate)
|
||||
console.log('Setting PDF duration: 15s');
|
||||
durationInput.value = 15;
|
||||
} else if (['ppt', 'pptx'].includes(ext)) {
|
||||
// Presentations: default 20 seconds per slide (estimate)
|
||||
console.log('Setting presentation duration: 20s');
|
||||
durationInput.value = 20;
|
||||
}
|
||||
}
|
||||
|
||||
function displayFiles() {
|
||||
|
||||
Reference in New Issue
Block a user