updated upload functions
This commit is contained in:
@@ -58,7 +58,6 @@ COPY --from=build /root/.cargo /root/.cargo
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
RUN pip install gunicorn
|
||||
RUN apt-get update && apt-get install -y libreoffice poppler-utils
|
||||
|
||||
# Make port 5000 available to the world outside this container
|
||||
EXPOSE 5000
|
||||
|
||||
Binary file not shown.
90
app.py
90
app.py
@@ -8,6 +8,10 @@ from functools import wraps
|
||||
from extensions import db, bcrypt, login_manager
|
||||
from models import User, Player, Content, Group # Add Group to the imports
|
||||
from flask_login import login_user, logout_user, login_required, current_user
|
||||
from pptx import Presentation
|
||||
from pptx.util import Inches
|
||||
from PIL import Image
|
||||
import io
|
||||
|
||||
app = Flask(__name__, instance_relative_config=True)
|
||||
|
||||
@@ -55,6 +59,10 @@ def convert_ppt_to_pdf(input_file, output_file):
|
||||
command = ['libreoffice', '--headless', '--convert-to', 'pdf', '--outdir', os.path.dirname(output_file), input_file]
|
||||
subprocess.run(command, check=True)
|
||||
|
||||
# Convert EMU to pixels
|
||||
def emu_to_pixels(emu):
|
||||
return int(emu / 914400 * 96)
|
||||
|
||||
@app.route('/')
|
||||
@login_required
|
||||
def dashboard():
|
||||
@@ -107,50 +115,61 @@ def upload_content():
|
||||
duration = int(request.form['duration'])
|
||||
return_url = request.form['return_url']
|
||||
media_type = request.form['media_type']
|
||||
|
||||
|
||||
print(f"Redirecting to: {return_url}") # Debugging: Log the return_url
|
||||
|
||||
for file in files:
|
||||
filename = secure_filename(file.filename)
|
||||
file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
|
||||
file.save(file_path)
|
||||
|
||||
# Handle PDF to JPG conversion
|
||||
if media_type == 'pdf':
|
||||
images = convert_from_path(file_path, dpi=300)
|
||||
for i, image in enumerate(images):
|
||||
image_filename = f"{os.path.splitext(filename)[0]}_{i + 1}.jpg"
|
||||
image_path = os.path.join(app.config['UPLOAD_FOLDER'], image_filename)
|
||||
image.save(image_path, 'JPEG')
|
||||
|
||||
# Add each converted image to the playlist
|
||||
if target_type == 'group':
|
||||
group = Group.query.get_or_404(target_id)
|
||||
for player in group.players:
|
||||
new_content = Content(file_name=image_filename, duration=duration, player_id=player.id)
|
||||
# Handle PPT/PPTX to JPG conversion
|
||||
if media_type == 'ppt':
|
||||
try:
|
||||
presentation = Presentation(file_path)
|
||||
for i, slide in enumerate(presentation.slides):
|
||||
slide_width = emu_to_pixels(presentation.slide_width)
|
||||
slide_height = emu_to_pixels(presentation.slide_height)
|
||||
img = Image.new('RGB', (slide_width, slide_height), 'white')
|
||||
|
||||
# Save the slide as an image
|
||||
image_filename = f"{os.path.splitext(filename)[0]}_slide_{i + 1}.jpg"
|
||||
image_path = os.path.join(app.config['UPLOAD_FOLDER'], image_filename)
|
||||
img.save(image_path, 'JPEG')
|
||||
|
||||
# Add each converted image to the playlist
|
||||
if target_type == 'group':
|
||||
group = Group.query.get_or_404(target_id)
|
||||
for player in group.players:
|
||||
new_content = Content(file_name=image_filename, duration=duration, player_id=player.id)
|
||||
db.session.add(new_content)
|
||||
elif target_type == 'player':
|
||||
new_content = Content(file_name=image_filename, duration=duration, player_id=target_id)
|
||||
db.session.add(new_content)
|
||||
elif target_type == 'player':
|
||||
new_content = Content(file_name=image_filename, duration=duration, player_id=target_id)
|
||||
db.session.add(new_content)
|
||||
|
||||
# Optionally, delete the original PDF file after conversion
|
||||
os.remove(file_path)
|
||||
finally:
|
||||
# Ensure the original PPT file is deleted after processing
|
||||
if os.path.exists(file_path):
|
||||
os.remove(file_path)
|
||||
|
||||
# Handle other media types
|
||||
elif media_type in ['image', 'video', 'ppt']:
|
||||
if media_type == 'ppt':
|
||||
ppt_output_file = os.path.splitext(file_path)[0] + '.pdf'
|
||||
convert_ppt_to_pdf(file_path, ppt_output_file)
|
||||
os.remove(file_path) # Remove the original PPT file
|
||||
file_path = ppt_output_file
|
||||
elif media_type in ['image', 'video', 'pdf']:
|
||||
if media_type == 'pdf':
|
||||
images = convert_from_path(file_path, dpi=300)
|
||||
for i, image in enumerate(images):
|
||||
image_filename = f"{os.path.splitext(filename)[0]}_{i + 1}.jpg"
|
||||
image_path = os.path.join(app.config['UPLOAD_FOLDER'], image_filename)
|
||||
image.save(image_path, 'JPEG')
|
||||
if target_type == 'group':
|
||||
group = Group.query.get_or_404(target_id)
|
||||
for player in group.players:
|
||||
new_content = Content(file_name=image_filename, duration=duration, player_id=player.id)
|
||||
db.session.add(new_content)
|
||||
elif target_type == 'player':
|
||||
new_content = Content(file_name=image_filename, duration=duration, player_id=target_id)
|
||||
db.session.add(new_content)
|
||||
if os.path.exists(file_path):
|
||||
os.remove(file_path)
|
||||
|
||||
if target_type == 'group':
|
||||
group = Group.query.get_or_404(target_id)
|
||||
for player in group.players:
|
||||
new_content = Content(file_name=filename, duration=duration, player_id=player.id)
|
||||
db.session.add(new_content)
|
||||
elif target_type == 'player':
|
||||
new_content = Content(file_name=filename, duration=duration, player_id=target_id)
|
||||
db.session.add(new_content)
|
||||
|
||||
db.session.commit()
|
||||
return redirect(return_url)
|
||||
|
||||
@@ -158,7 +177,6 @@ def upload_content():
|
||||
target_id = request.args.get('target_id')
|
||||
return_url = request.args.get('return_url', url_for('dashboard'))
|
||||
|
||||
# Serialize players and groups into JSON-serializable dictionaries
|
||||
players = [{'id': player.id, 'username': player.username} for player in Player.query.filter(~Player.groups.any()).all()]
|
||||
groups = [{'id': group.id, 'name': group.name} for group in Group.query.all()]
|
||||
|
||||
|
||||
@@ -19,3 +19,4 @@ services:
|
||||
# when setting allready exist and data are setted and is performed an update use second line of command
|
||||
command: sh -c "python clear_db.py && python init_db.py && gunicorn -w 4 -b 0.0.0.0:5000 app:app"
|
||||
#command: sh -c "python init_db.py && gunicorn -w 4 -b 0.0.0.0:5000 app:app"
|
||||
restart: unless-stopped
|
||||
Binary file not shown.
@@ -18,4 +18,5 @@ Werkzeug==3.1.3
|
||||
gunicorn==20.1.0
|
||||
pdf2image==1.17.0
|
||||
pillow==11.1.0
|
||||
python-pptx==0.6.21
|
||||
setuptools==75.8.0
|
||||
BIN
static/uploads/merged_1.jpg
Normal file
BIN
static/uploads/merged_1.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 713 KiB |
BIN
static/uploads/merged_2.jpg
Normal file
BIN
static/uploads/merged_2.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 612 KiB |
|
Before Width: | Height: | Size: 414 KiB After Width: | Height: | Size: 414 KiB |
BIN
static/uploads/welcome_Prodrive_slide_1.jpg
Normal file
BIN
static/uploads/welcome_Prodrive_slide_1.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.6 KiB |
@@ -15,22 +15,24 @@
|
||||
.dark-mode label, .dark-mode th, .dark-mode td {
|
||||
color: #ffffff;
|
||||
}
|
||||
.popup-message {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background-color: rgba(0, 0, 0, 0.8);
|
||||
color: white;
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
display: none;
|
||||
z-index: 1000;
|
||||
}
|
||||
.logo {
|
||||
max-height: 100px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
/* Modal styling for dark mode */
|
||||
.modal-content.dark-mode {
|
||||
background-color: #1e1e1e;
|
||||
color: #ffffff;
|
||||
}
|
||||
.modal-header.dark-mode {
|
||||
border-bottom: 1px solid #444;
|
||||
}
|
||||
.modal-footer.dark-mode {
|
||||
border-top: 1px solid #444;
|
||||
}
|
||||
.progress-bar {
|
||||
background-color: #007bff;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="{{ 'dark-mode' if theme == 'dark' else '' }}">
|
||||
@@ -41,7 +43,7 @@
|
||||
{% endif %}
|
||||
<h1 class="mb-0">Upload Content</h1>
|
||||
</div>
|
||||
<form id="upload-form" action="{{ url_for('upload_content') }}" method="post" enctype="multipart/form-data" onsubmit="showPopupMessage('Content uploaded successfully!')">
|
||||
<form id="upload-form" action="{{ url_for('upload_content') }}" method="post" enctype="multipart/form-data" onsubmit="showStatusModal()">
|
||||
<input type="hidden" name="return_url" value="{{ return_url }}">
|
||||
<div class="mb-3">
|
||||
<label for="target_type" class="form-label">Target Type:</label>
|
||||
@@ -91,13 +93,31 @@
|
||||
<label for="duration" class="form-label">Duration (seconds):</label>
|
||||
<input type="number" name="duration" id="duration" class="form-control" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Upload</button>
|
||||
<button type="submit" id="submit-button" class="btn btn-primary">Upload</button>
|
||||
</form>
|
||||
<a href="{{ return_url }}" class="btn btn-secondary mt-3">Back</a>
|
||||
<a href="{{ url_for('dashboard') }}" class="btn btn-secondary mt-3">Back to Dashboard</a>
|
||||
</div>
|
||||
|
||||
<div id="popup-message" class="popup-message"></div>
|
||||
<!-- Modal for Status Updates -->
|
||||
<div class="modal fade" id="statusModal" tabindex="-1" aria-labelledby="statusModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content {{ 'dark-mode' if theme == 'dark' else '' }}">
|
||||
<div class="modal-header {{ 'dark-mode' if theme == 'dark' else '' }}">
|
||||
<h5 class="modal-title" id="statusModalLabel">Processing Files</h5>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p id="status-message">Uploading and processing your files. Please wait...</p>
|
||||
<div class="progress">
|
||||
<div id="progress-bar" class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" style="width: 0%;" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer {{ 'dark-mode' if theme == 'dark' else '' }}">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" disabled>Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script>
|
||||
@@ -147,14 +167,22 @@
|
||||
}
|
||||
});
|
||||
|
||||
function showPopupMessage(message) {
|
||||
const popup = document.getElementById('popup-message');
|
||||
popup.textContent = message;
|
||||
popup.style.display = 'block';
|
||||
setTimeout(() => {
|
||||
popup.style.display = 'none';
|
||||
document.getElementById('upload-form').submit();
|
||||
}, 5000); // Display time set to 5 seconds
|
||||
function showStatusModal() {
|
||||
const statusModal = new bootstrap.Modal(document.getElementById('statusModal'));
|
||||
statusModal.show();
|
||||
|
||||
// Simulate progress updates
|
||||
const progressBar = document.getElementById('progress-bar');
|
||||
let progress = 0;
|
||||
const interval = setInterval(() => {
|
||||
progress += 10;
|
||||
progressBar.style.width = `${progress}%`;
|
||||
progressBar.setAttribute('aria-valuenow', progress);
|
||||
if (progress >= 100) {
|
||||
clearInterval(interval);
|
||||
document.getElementById('status-message').textContent = 'Files uploaded and processed successfully!';
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
Reference in New Issue
Block a user