| import io |
| import os |
| import subprocess |
| import tempfile |
| import zipfile |
| from flask import Flask, render_template, request, send_file, jsonify |
|
|
| app = Flask(__name__) |
|
|
| |
| app.config['MAX_CONTENT_LENGTH'] = 100 * 1024 * 1024 |
|
|
| ALLOWED_EXTENSIONS = {'.doc', '.docx', '.ppt', '.pptx', '.xls', '.xlsx'} |
|
|
| def is_allowed_file(filename): |
| _, ext = os.path.splitext(filename.lower()) |
| return ext in ALLOWED_EXTENSIONS |
|
|
| @app.route('/') |
| def index(): |
| return render_template('index.html') |
|
|
| @app.route('/convert', methods=['POST']) |
| def convert(): |
| if 'files' not in request.files: |
| return jsonify({'error': 'No files found in the request.'}), 400 |
|
|
| files = request.files.getlist('files') |
| if not files or all(file.filename == '' for file in files): |
| return jsonify({'error': 'No files selected for upload.'}), 400 |
|
|
| |
| zip_buffer = io.BytesIO() |
| converted_files_count = 0 |
| failed_conversions = [] |
|
|
| |
| with tempfile.TemporaryDirectory() as temp_dir: |
| for file in files: |
| if not file.filename: |
| continue |
|
|
| _, ext = os.path.splitext(file.filename.lower()) |
| if ext not in ALLOWED_EXTENSIONS: |
| failed_conversions.append((file.filename, f"Unsupported extension '{ext}'")) |
| continue |
|
|
| |
| input_path = os.path.join(temp_dir, file.filename) |
| try: |
| file.save(input_path) |
| except Exception as e: |
| failed_conversions.append((file.filename, f"Failed to save file: {e}")) |
| continue |
|
|
| |
| cmd = [ |
| "soffice", |
| "--headless", |
| "--convert-to", |
| "pdf", |
| "--outdir", |
| temp_dir, |
| input_path |
| ] |
|
|
| print(f"Web conversion: executing {' '.join(cmd)}") |
|
|
| try: |
| |
| result = subprocess.run( |
| cmd, |
| stdout=subprocess.PIPE, |
| stderr=subprocess.PIPE, |
| text=True, |
| timeout=180 |
| ) |
| if result.returncode != 0: |
| failed_conversions.append((file.filename, f"LibreOffice failed (code {result.returncode})")) |
| continue |
| except subprocess.TimeoutExpired: |
| failed_conversions.append((file.filename, "Conversion timed out (180s)")) |
| continue |
| except Exception as e: |
| failed_conversions.append((file.filename, f"Conversion error: {e}")) |
| continue |
|
|
| |
| base_name, _ = os.path.splitext(file.filename) |
| pdf_filename = f"{base_name}.pdf" |
| pdf_path = os.path.join(temp_dir, pdf_filename) |
|
|
| if os.path.exists(pdf_path): |
| converted_files_count += 1 |
| else: |
| failed_conversions.append((file.filename, "Expected PDF output was not created")) |
|
|
| |
| if converted_files_count == 0: |
| error_details = ", ".join([f"'{name}': {reason}" for name, reason in failed_conversions]) |
| return jsonify({'error': f'Failed to convert any files. Details: {error_details}'}), 400 |
|
|
| |
| if converted_files_count == 1: |
| pdf_filename = None |
| pdf_path = None |
| for file in files: |
| base_name, _ = os.path.splitext(file.filename) |
| pdf_filename = f"{base_name}.pdf" |
| pdf_path = os.path.join(temp_dir, pdf_filename) |
| if os.path.exists(pdf_path): |
| break |
| |
| if pdf_path and pdf_filename: |
| |
| pdf_buffer = io.BytesIO() |
| with open(pdf_path, 'rb') as f: |
| pdf_buffer.write(f.read()) |
| pdf_buffer.seek(0) |
| |
| return send_file( |
| pdf_buffer, |
| mimetype='application/pdf', |
| as_attachment=True, |
| download_name=pdf_filename |
| ) |
|
|
| |
| with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zip_file: |
| for file in files: |
| base_name, _ = os.path.splitext(file.filename) |
| pdf_filename = f"{base_name}.pdf" |
| pdf_path = os.path.join(temp_dir, pdf_filename) |
| if os.path.exists(pdf_path): |
| |
| zip_file.write(pdf_path, pdf_filename) |
|
|
| |
| if failed_conversions: |
| log_lines = ["Conversion Report (Some files failed to convert):\n", "="*50, "\n"] |
| for name, reason in failed_conversions: |
| log_lines.append(f"FAILED: {name} | Reason: {reason}\n") |
| zip_file.writestr("conversion_errors.log", "".join(log_lines)) |
|
|
| |
| zip_buffer.seek(0) |
|
|
| |
| return send_file( |
| zip_buffer, |
| mimetype='application/zip', |
| as_attachment=True, |
| download_name='converted_pdfs.zip' |
| ) |
|
|
|
|
| if __name__ == '__main__': |
| |
| port = int(os.environ.get('PORT', 7860)) |
| app.run(host='0.0.0.0', port=port) |
|
|
|
|
|
|