Files
digiserver-v2/app/templates/content/upload_media.html
ske087 498c03ef00 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
2025-11-13 21:00:07 +02:00

362 lines
12 KiB
HTML

{% extends "base.html" %}
{% block title %}Upload Media - DigiServer v2{% endblock %}
{% block content %}
<style>
.upload-container {
max-width: 900px;
margin: 0 auto;
}
.upload-zone {
border: 3px dashed #ced4da;
border-radius: 12px;
padding: 60px 40px;
text-align: center;
background: #f8f9fa;
transition: all 0.3s;
cursor: pointer;
}
.upload-zone:hover {
border-color: #667eea;
background: #f0f2ff;
}
.upload-zone.dragover {
border-color: #667eea;
background: #e8ebff;
transform: scale(1.02);
}
.file-input-wrapper {
margin: 20px 0;
}
.file-input-wrapper input[type="file"] {
display: none;
}
.file-list {
margin-top: 20px;
}
.file-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px;
background: #fff;
border: 1px solid #dee2e6;
border-radius: 6px;
margin-bottom: 10px;
}
.file-info {
display: flex;
align-items: center;
gap: 10px;
}
.file-icon {
font-size: 24px;
}
.remove-file {
cursor: pointer;
color: #dc3545;
font-weight: bold;
padding: 5px 10px;
}
.remove-file:hover {
background: #dc3545;
color: white;
border-radius: 4px;
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-weight: 600;
color: #333;
}
.form-control {
width: 100%;
padding: 12px;
border: 1px solid #ced4da;
border-radius: 6px;
font-size: 14px;
}
.form-control:focus {
outline: none;
border-color: #667eea;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}
.btn-upload {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
padding: 15px 40px;
font-size: 16px;
font-weight: 600;
border-radius: 8px;
cursor: pointer;
transition: all 0.3s;
width: 100%;
}
.btn-upload:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(102, 126, 234, 0.4);
}
.btn-upload:disabled {
background: #6c757d;
cursor: not-allowed;
transform: none;
}
.playlist-selector {
background: #f8f9fa;
padding: 20px;
border-radius: 8px;
margin-bottom: 30px;
border: 2px solid #dee2e6;
}
.playlist-selector.selected {
border-color: #667eea;
background: #f0f2ff;
}
</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
</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);">
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>
<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">
</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>
<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>
</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>
<script>
const uploadZone = document.getElementById('upload-zone');
const fileInput = document.getElementById('file-input');
const fileList = document.getElementById('file-list');
const uploadBtn = document.getElementById('upload-btn');
const uploadForm = document.getElementById('upload-form');
let selectedFiles = [];
// Prevent default drag behaviors
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
uploadZone.addEventListener(eventName, preventDefaults, false);
document.body.addEventListener(eventName, preventDefaults, false);
});
function preventDefaults(e) {
e.preventDefault();
e.stopPropagation();
}
// Highlight drop zone when item is dragged over it
['dragenter', 'dragover'].forEach(eventName => {
uploadZone.addEventListener(eventName, () => {
uploadZone.classList.add('dragover');
});
});
['dragleave', 'drop'].forEach(eventName => {
uploadZone.addEventListener(eventName, () => {
uploadZone.classList.remove('dragover');
});
});
// Handle dropped files
uploadZone.addEventListener('drop', (e) => {
const dt = e.dataTransfer;
const files = dt.files;
handleFiles(files);
});
// Handle file input
fileInput.addEventListener('change', (e) => {
handleFiles(e.target.files);
});
// Click upload zone to trigger file input
uploadZone.addEventListener('click', () => {
fileInput.click();
});
function handleFiles(files) {
selectedFiles = Array.from(files);
displayFiles();
uploadBtn.disabled = selectedFiles.length === 0;
}
function displayFiles() {
fileList.innerHTML = '';
if (selectedFiles.length === 0) {
return;
}
selectedFiles.forEach((file, index) => {
const fileItem = document.createElement('div');
fileItem.className = 'file-item';
const ext = file.name.split('.').pop().toLowerCase();
let icon = '📁';
if (['jpg', 'jpeg', 'png', 'gif', 'bmp'].includes(ext)) icon = '📷';
else if (['mp4', 'avi', 'mov', 'mkv', 'webm'].includes(ext)) icon = '🎥';
else if (ext === 'pdf') icon = '📄';
else if (['ppt', 'pptx'].includes(ext)) icon = '📊';
const sizeInMB = (file.size / (1024 * 1024)).toFixed(2);
fileItem.innerHTML = `
<div class="file-info">
<span class="file-icon">${icon}</span>
<div>
<div style="font-weight: 600;">${file.name}</div>
<div style="font-size: 12px; color: #6c757d;">${sizeInMB} MB</div>
</div>
</div>
<span class="remove-file" onclick="removeFile(${index})">✕</span>
`;
fileList.appendChild(fileItem);
});
}
function removeFile(index) {
selectedFiles.splice(index, 1);
displayFiles();
uploadBtn.disabled = selectedFiles.length === 0;
// Update file input
const dt = new DataTransfer();
selectedFiles.forEach(file => dt.items.add(file));
fileInput.files = dt.files;
}
// Form submission
uploadForm.addEventListener('submit', (e) => {
if (selectedFiles.length === 0) {
e.preventDefault();
alert('Please select files to upload');
return;
}
uploadBtn.disabled = true;
uploadBtn.innerHTML = '⏳ Uploading...';
});
</script>
{% endblock %}