diff --git a/Dockerfile b/Dockerfile index dbbc95e..618366c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -59,7 +59,7 @@ 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 - +RUN apt-get install ffmpeg -y # Make port 5000 available to the world outside this container EXPOSE 5000 diff --git a/__pycache__/app.cpython-311.pyc b/__pycache__/app.cpython-311.pyc index 8d26885..a1cd99a 100644 Binary files a/__pycache__/app.cpython-311.pyc and b/__pycache__/app.cpython-311.pyc differ diff --git a/app.py b/app.py index da639b8..827ff00 100644 --- a/app.py +++ b/app.py @@ -12,6 +12,7 @@ from pptx import Presentation from pptx.util import Inches from PIL import Image import io +import threading app = Flask(__name__, instance_relative_config=True) @@ -45,7 +46,7 @@ migrate = Migrate(app, db) @login_manager.user_loader def load_user(user_id): - return User.query.get(int(user_id)) + return db.session.get(User, int(user_id)) def admin_required(f): @wraps(f) @@ -75,7 +76,12 @@ def convert_ppt_to_images(input_file, output_folder): '--outdir', output_folder, input_file ] - subprocess.run(command, check=True) + try: + subprocess.run(command, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + print(f"PPT file converted to images: {input_file}") + except subprocess.CalledProcessError as e: + print(f"Error converting PPT to images: {e.stderr.decode()}") + return False # Rename the generated images to follow the naming convention base_name = os.path.splitext(os.path.basename(input_file))[0] @@ -83,6 +89,7 @@ def convert_ppt_to_images(input_file, output_folder): if file_name.endswith('.png'): new_name = f"{base_name}_{i + 1}.png" os.rename(os.path.join(output_folder, file_name), os.path.join(output_folder, new_name)) + return True def convert_pdf_to_images(input_file, output_folder): """ @@ -155,68 +162,87 @@ def upload_content(): files = request.files.getlist('files') duration = int(request.form['duration']) return_url = request.form.get('return_url') - media_type = request.form.get('media_type') + media_type = request.form['media_type'] if not target_type or not target_id: flash('Please select a target type and target ID.', 'danger') return redirect(url_for('upload_content')) for file in files: - filename = secure_filename(file.filename) - file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename) - file.save(file_path) + try: + # Generate a secure filename and save the file + filename = secure_filename(file.filename) + file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename) + file.save(file_path) - # Handle PPT/PPTX to images - if media_type == 'ppt': - convert_ppt_to_images(file_path, app.config['UPLOAD_FOLDER']) + # Handle PDF files + if media_type == 'pdf': + print(f"Processing PDF file: {file_path}") + convert_pdf_to_images(file_path, app.config['UPLOAD_FOLDER']) - # Add each slide image to the playlist - base_name = os.path.splitext(filename)[0] - for slide_image in os.listdir(app.config['UPLOAD_FOLDER']): - if slide_image.startswith(base_name) and slide_image.endswith('.png'): - if target_type == 'group': - group = Group.query.get_or_404(target_id) - for player in group.players: - new_content = Content(file_name=slide_image, duration=duration, player_id=player.id) + # Add the converted images to the playlist + if target_type == 'group': + group = Group.query.get_or_404(target_id) + for player in group.players: + for image_file in os.listdir(app.config['UPLOAD_FOLDER']): + if image_file.startswith(os.path.splitext(filename)[0]) and image_file.endswith('.jpg'): + new_content = Content(file_name=image_file, duration=duration, player_id=player.id) + db.session.add(new_content) + elif target_type == 'player': + for image_file in os.listdir(app.config['UPLOAD_FOLDER']): + if image_file.startswith(os.path.splitext(filename)[0]) and image_file.endswith('.jpg'): + new_content = Content(file_name=image_file, duration=duration, player_id=target_id) db.session.add(new_content) - elif target_type == 'player': - new_content = Content(file_name=slide_image, duration=duration, player_id=target_id) + + # Handle video files + elif media_type == 'video': + # Add the video file 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=filename, duration=duration, player_id=player.id) db.session.add(new_content) - - # Remove the original PPT/PPTX file after processing - os.remove(file_path) - - # Handle PDF to images - elif media_type == 'pdf': - convert_pdf_to_images(file_path, app.config['UPLOAD_FOLDER']) - - # Add each page image to the playlist - base_name = os.path.splitext(filename)[0] - for page_image in os.listdir(app.config['UPLOAD_FOLDER']): - if page_image.startswith(base_name) and page_image.endswith('.jpg'): - if target_type == 'group': - group = Group.query.get_or_404(target_id) - for player in group.players: - new_content = Content(file_name=page_image, duration=duration, player_id=player.id) - db.session.add(new_content) - elif target_type == 'player': - new_content = Content(file_name=page_image, duration=duration, player_id=target_id) - db.session.add(new_content) - - # Remove the original PDF file after processing - os.remove(file_path) - - # Handle video files - elif media_type == 'video': - # Add the video file 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=filename, duration=duration, player_id=player.id) + elif target_type == 'player': + new_content = Content(file_name=filename, duration=duration, player_id=target_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) + + # Launch the video conversion function in a thread + thread = threading.Thread(target=convert_video_and_update_playlist, args=(file_path, filename, target_type, target_id, duration)) + thread.start() + + # Handle PPT files + elif media_type == 'ppt': + print(f"Processing PPT file: {file_path}") + success = convert_ppt_to_images(file_path, app.config['UPLOAD_FOLDER']) + + if success: + # Add each slide image to the playlist + base_name = os.path.splitext(filename)[0] + for slide_image in sorted(os.listdir(app.config['UPLOAD_FOLDER'])): + if slide_image.startswith(base_name) and slide_image.endswith('.png'): + if target_type == 'group': + group = Group.query.get_or_404(target_id) + for player in group.players: + new_content = Content(file_name=slide_image, duration=duration, player_id=player.id) + db.session.add(new_content) + elif target_type == 'player': + new_content = Content(file_name=slide_image, duration=duration, player_id=target_id) + db.session.add(new_content) + + # Commit the changes to the database + db.session.commit() + + # Remove the original PPT file after processing + if os.path.exists(file_path): + os.remove(file_path) + print(f"Original PPT file deleted: {file_path}") + else: + print(f"Failed to process PPT file: {file_path}") + flash(f"Failed to process PPT file: {file_path}", 'danger') + + except Exception as e: + print(f"Error processing file {filename}: {e}") + flash(f"Error processing file {filename}: {e}", 'danger') db.session.commit() return redirect(return_url) @@ -231,6 +257,7 @@ def upload_content(): return render_template('upload_content.html', target_type=target_type, target_id=target_id, players=players, groups=groups, return_url=return_url) + @app.route('/admin') @login_required @admin_required @@ -596,9 +623,80 @@ def delete_group_media(group_id, content_id): db.session.commit() return redirect(url_for('manage_group', group_id=group_id)) +def convert_video(input_file, output_folder): + """ + Converts a video file to MP4 format with H.264 codec, 720p resolution, and 30 FPS. + + Args: + input_file (str): Path to the input video file. + output_folder (str): Path to the folder where the converted video will be saved. + + Returns: + str: Path to the converted video file, or None if conversion fails. + """ + if not os.path.exists(output_folder): + os.makedirs(output_folder) + + # Generate the output file path + base_name = os.path.splitext(os.path.basename(input_file))[0] + output_file = os.path.join(output_folder, f"{base_name}.mp4") + + # FFmpeg command to convert the video + command = [ + "ffmpeg", + "-i", input_file, # Input file + "-c:v", "libx264", # Video codec: H.264 + "-preset", "fast", # Encoding speed/quality tradeoff + "-crf", "23", # Constant Rate Factor (quality, lower is better) + "-vf", "scale=-1:720", # Scale video to 720p (preserve aspect ratio) + "-r", "30", # Frame rate: 30 FPS + "-c:a", "aac", # Audio codec: AAC + "-b:a", "128k", # Audio bitrate + output_file # Output file + ] + + try: + # Run the FFmpeg command + subprocess.run(command, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + print(f"Video converted successfully: {output_file}") + return output_file + except subprocess.CalledProcessError as e: + print(f"Error converting video: {e.stderr.decode()}") + return None + +def convert_video_and_update_playlist(file_path, original_filename, target_type, target_id, duration): + print(f"Starting video conversion for: {file_path}") + converted_file = convert_video(file_path, app.config['UPLOAD_FOLDER']) + if converted_file: + converted_filename = os.path.basename(converted_file) + print(f"Video converted successfully: {converted_filename}") + + # Use the application context to interact with the database + with app.app_context(): + # Update the database with the converted filename + if target_type == 'group': + group = Group.query.get_or_404(target_id) + for player in group.players: + content = Content.query.filter_by(player_id=player.id, file_name=original_filename).first() + if content: + content.file_name = converted_filename + elif target_type == 'player': + content = Content.query.filter_by(player_id=target_id, file_name=original_filename).first() + if content: + content.file_name = converted_filename + + db.session.commit() + print(f"Database updated with converted video: {converted_filename}") + + # Delete the original file only if it exists + if os.path.exists(file_path): + os.remove(file_path) + print(f"Original file deleted: {file_path}") + + + else: + print(f"Video conversion failed for: {file_path}") + + if __name__ == '__main__': - with app.app_context(): - db.create_all() # Creează toate tabelele - app.run(debug=True, host='0.0.0.0') - - + app.run(host='0.0.0.0', port=5000, debug=True) \ No newline at end of file diff --git a/instance/dashboard.db b/instance/dashboard.db index 22779c1..1b0f415 100644 Binary files a/instance/dashboard.db and b/instance/dashboard.db differ diff --git a/static/uploads/IMG_0297.mov b/static/uploads/IMG_0297.mov deleted file mode 100644 index 5572bd4..0000000 Binary files a/static/uploads/IMG_0297.mov and /dev/null differ