updated to 4k images from pptx
This commit is contained in:
19
app.py
19
app.py
@@ -327,7 +327,8 @@ def edit_player(player_id):
|
||||
hostname = request.form['hostname']
|
||||
password = request.form['password'] if request.form['password'] else None
|
||||
quickconnect_password = request.form['quickconnect_password'] if request.form['quickconnect_password'] else None
|
||||
edit_player_util(player_id, username, hostname, password, quickconnect_password)
|
||||
orientation = request.form.get('orientation', player.orientation) # <-- Get orientation
|
||||
edit_player_util(player_id, username, hostname, password, quickconnect_password, orientation) # <-- Pass orientation
|
||||
flash(f'Player "{username}" updated successfully.', 'success')
|
||||
return redirect(url_for('player_page', player_id=player.id))
|
||||
|
||||
@@ -648,14 +649,14 @@ def create_admin(username, password):
|
||||
|
||||
from models.create_default_user import create_default_user
|
||||
|
||||
with app.app_context():
|
||||
try:
|
||||
db.session.execute(db.select(User).limit(1))
|
||||
except Exception as e:
|
||||
print("Database not initialized or missing tables. Re-initializing...")
|
||||
db.create_all()
|
||||
# Always ensure default user exists
|
||||
create_default_user(db, User, bcrypt)
|
||||
if not app.debug or os.environ.get('WERKZEUG_RUN_MAIN') == 'true':
|
||||
with app.app_context():
|
||||
try:
|
||||
db.session.execute(db.select(User).limit(1))
|
||||
except Exception as e:
|
||||
print("Database not initialized or missing tables. Re-initializing...")
|
||||
db.create_all()
|
||||
create_default_user(db, User, bcrypt)
|
||||
|
||||
# Add this at the end of app.py
|
||||
if __name__ == '__main__':
|
||||
|
||||
Binary file not shown.
@@ -49,11 +49,23 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-12">
|
||||
<div class="mb-3">
|
||||
<label for="orientation" class="form-label">Group Orientation</label>
|
||||
<select class="form-control {{ 'dark-mode' if theme == 'dark' else '' }}" id="orientation" name="orientation" required>
|
||||
<option value="Landscape" selected>Landscape</option>
|
||||
<option value="Portret">Portret</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert alert-warning" role="alert">
|
||||
<strong>Warning:</strong> Adding players to a group will delete their individual playlists.
|
||||
All players in a group will share the same content.
|
||||
</div>
|
||||
<div id="orientation-warning" class="alert alert-danger d-none" role="alert">
|
||||
No players with the selected orientation are available.
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<button type="submit" class="btn btn-primary">Create Group</button>
|
||||
<a href="{{ url_for('dashboard') }}" class="btn btn-secondary mt-3">Back to Dashboard</a>
|
||||
@@ -61,5 +73,38 @@
|
||||
</form>
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script>
|
||||
// Get all players and their orientations from the backend
|
||||
const players = [
|
||||
{% for player in players %}
|
||||
{id: {{ player.id }}, username: "{{ player.username }}", orientation: "{{ player.orientation }}"},
|
||||
{% endfor %}
|
||||
];
|
||||
|
||||
const orientationSelect = document.getElementById('orientation');
|
||||
const playersSelect = document.getElementById('players');
|
||||
const orientationWarning = document.getElementById('orientation-warning');
|
||||
|
||||
function filterPlayers() {
|
||||
const selectedOrientation = orientationSelect.value;
|
||||
playersSelect.innerHTML = '';
|
||||
let compatibleCount = 0;
|
||||
players.forEach(player => {
|
||||
if (player.orientation === selectedOrientation) {
|
||||
const option = document.createElement('option');
|
||||
option.value = player.id;
|
||||
option.textContent = player.username;
|
||||
playersSelect.appendChild(option);
|
||||
compatibleCount++;
|
||||
}
|
||||
});
|
||||
document.getElementById('orientation-warning').classList.toggle('d-none', compatibleCount > 0);
|
||||
}
|
||||
|
||||
orientationSelect.addEventListener('change', filterPlayers);
|
||||
|
||||
// Initial filter on page load
|
||||
filterPlayers();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -60,6 +60,13 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="orientation" class="form-label">Orientation</label>
|
||||
<select class="form-control {{ 'dark-mode' if theme == 'dark' else '' }}" id="orientation" name="orientation" required>
|
||||
<option value="Landscape" {% if player.orientation == 'Landscape' %}selected{% endif %}>Landscape</option>
|
||||
<option value="Portret" {% if player.orientation == 'Portret' %}selected{% endif %}>Portret</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<button type="submit" class="btn btn-primary">Update Player</button>
|
||||
<a href="{{ return_url }}" class="btn btn-secondary mt-3">Back to Player Page</a>
|
||||
|
||||
@@ -106,8 +106,12 @@
|
||||
☰
|
||||
</div>
|
||||
|
||||
<!-- Media Name -->
|
||||
<div class="flex-grow-1 mb-2 mb-md-0">
|
||||
<!-- Media Thumbnail and Name -->
|
||||
<div class="flex-grow-1 mb-2 mb-md-0 d-flex align-items-center">
|
||||
<img src="{{ url_for('static', filename='uploads/' ~ media.file_name) }}"
|
||||
alt="thumbnail"
|
||||
style="width: 48px; height: 48px; object-fit: cover; margin-right: 10px; border-radius: 4px;"
|
||||
onerror="this.style.display='none';">
|
||||
<p class="mb-0"><strong>Media Name:</strong> {{ media.file_name }}</p>
|
||||
</div>
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -130,7 +130,7 @@ def add_player(username, hostname, password, quickconnect_password, orientation=
|
||||
log_player_created(username, hostname)
|
||||
return new_player
|
||||
|
||||
def edit_player(player_id, username, hostname, password=None, quickconnect_password=None):
|
||||
def edit_player(player_id, username, hostname, password=None, quickconnect_password=None, orientation=None):
|
||||
"""
|
||||
Edit an existing player's details.
|
||||
"""
|
||||
@@ -147,6 +147,9 @@ def edit_player(player_id, username, hostname, password=None, quickconnect_passw
|
||||
if quickconnect_password:
|
||||
player.quickconnect_password = bcrypt.generate_password_hash(quickconnect_password).decode('utf-8')
|
||||
|
||||
if orientation:
|
||||
player.orientation = orientation
|
||||
|
||||
db.session.commit()
|
||||
log_player_edited(username)
|
||||
return player
|
||||
|
||||
@@ -105,23 +105,14 @@ def convert_video_and_update_playlist(app, file_path, original_filename, target_
|
||||
print(f"Video conversion failed for: {file_path}")
|
||||
|
||||
# PDF conversion functions
|
||||
def convert_pdf_to_images(pdf_file, output_folder, delete_pdf=True):
|
||||
def convert_pdf_to_images(pdf_file, output_folder, delete_pdf=True, dpi=600):
|
||||
"""
|
||||
Convert a PDF file to images in sequential order.
|
||||
|
||||
Args:
|
||||
pdf_file (str): Path to the PDF file
|
||||
output_folder (str): Path to save the images
|
||||
delete_pdf (bool): Whether to delete the PDF file after processing
|
||||
|
||||
Returns:
|
||||
list: List of generated image filenames in page order, or empty list if conversion failed
|
||||
Convert a PDF file to images in sequential order at high resolution (4K).
|
||||
"""
|
||||
print(f"Converting PDF to images: {pdf_file}")
|
||||
print(f"Converting PDF to images: {pdf_file} at {dpi} DPI")
|
||||
try:
|
||||
# Convert PDF to images
|
||||
images = convert_from_path(pdf_file, dpi=300)
|
||||
print(f"Number of pages in PDF: {len(images)}")
|
||||
images = convert_from_path(pdf_file, dpi=dpi)
|
||||
base_name = os.path.splitext(os.path.basename(pdf_file))[0]
|
||||
image_filenames = []
|
||||
|
||||
@@ -240,6 +231,7 @@ def process_pptx(input_file, output_folder, duration, target_type, target_id):
|
||||
'--headless',
|
||||
'--convert-to', 'pdf',
|
||||
'--outdir', output_folder,
|
||||
'--printer-resolution', '600',
|
||||
input_file
|
||||
]
|
||||
|
||||
@@ -251,7 +243,7 @@ def process_pptx(input_file, output_folder, duration, target_type, target_id):
|
||||
print(f"LibreOffice errors (if any): {result.stderr.decode()}")
|
||||
|
||||
# Step 2: Convert PDF to images and update playlist
|
||||
image_filenames = convert_pdf_to_images(pdf_file, output_folder, True)
|
||||
image_filenames = convert_pdf_to_images(pdf_file, output_folder, True, dpi=600)
|
||||
|
||||
# Verify we got images
|
||||
if not image_filenames:
|
||||
@@ -306,7 +298,7 @@ def process_uploaded_files(app, files, media_type, duration, target_type, target
|
||||
if media_type == 'image':
|
||||
add_image_to_playlist(app, file, filename, duration, target_type, target_id)
|
||||
result['message'] = f"Image {filename} added to playlist"
|
||||
log_upload('image', filename, target_type, target_name)
|
||||
log_upload('image', filename, target_type, target_id)
|
||||
|
||||
elif media_type == 'video':
|
||||
# For videos, add to playlist then start conversion in background
|
||||
@@ -329,7 +321,7 @@ def process_uploaded_files(app, files, media_type, duration, target_type, target
|
||||
threading.Thread(target=convert_video_and_update_playlist,
|
||||
args=(app, file_path, filename, target_type, target_id, duration)).start()
|
||||
result['message'] = f"Video {filename} added to playlist and being processed"
|
||||
log_upload('video', filename, target_type, target_name)
|
||||
log_upload('video', filename, target_type, target_id)
|
||||
|
||||
elif media_type == 'pdf':
|
||||
# For PDFs, convert to images and update playlist
|
||||
@@ -337,7 +329,7 @@ def process_uploaded_files(app, files, media_type, duration, target_type, target
|
||||
duration, target_type, target_id)
|
||||
if success:
|
||||
result['message'] = f"PDF {filename} processed successfully"
|
||||
log_process('pdf', filename, target_type, target_name)
|
||||
log_process('pdf', filename, target_type, target_id)
|
||||
else:
|
||||
result['success'] = False
|
||||
result['message'] = f"Error processing PDF file: {filename}"
|
||||
@@ -348,7 +340,7 @@ def process_uploaded_files(app, files, media_type, duration, target_type, target
|
||||
duration, target_type, target_id)
|
||||
if success:
|
||||
result['message'] = f"PowerPoint {filename} processed successfully"
|
||||
log_process('ppt', filename, target_type, target_name)
|
||||
log_process('ppt', filename, target_type, target_id)
|
||||
else:
|
||||
result['success'] = False
|
||||
result['message'] = f"Error processing PowerPoint file: {filename}"
|
||||
|
||||
Reference in New Issue
Block a user