diff --git a/.gitignore b/.gitignore index 0365968..0c8d3ac 100644 --- a/.gitignore +++ b/.gitignore @@ -195,4 +195,5 @@ cython_debug/ # Exclude data files *.csv +*.zip config.ini \ No newline at end of file diff --git a/app.py b/app.py index 7ed12ef..c3c8785 100644 --- a/app.py +++ b/app.py @@ -15,6 +15,11 @@ from datetime import datetime from flask import send_from_directory import configparser +import zipfile +import os +from datetime import timedelta + + app = Flask(__name__) # Load configuration @@ -53,6 +58,26 @@ logger.addHandler(queue_handler) scraping_active = False scraping_thread = None + +def create_zip(file_paths, zip_name): + zip_path = os.path.join(app.root_path, 'temp', zip_name) + with zipfile.ZipFile(zip_path, 'w') as zipf: + for file_path in file_paths: + arcname = os.path.basename(file_path) + zipf.write(file_path, arcname) + return zip_path + +def delete_old_zips(): + temp_dir = os.path.join(app.root_path, 'temp') + now = datetime.now() + for filename in os.listdir(temp_dir): + if filename.endswith('.zip'): + file_path = os.path.join(temp_dir, filename) + file_time = datetime.fromtimestamp(os.path.getmtime(file_path)) + if now - file_time > timedelta(hours=1): + os.remove(file_path) + logger.info(f"Deleted old zip file: {filename}") + def fetch_faction_data(faction_id): url = f"https://api.torn.com/faction/{faction_id}?selections=&key={API_KEY}" response = requests.get(url) @@ -282,15 +307,48 @@ def download_results(): return render_template('download_results.html', files=files) +@app.route('/download_files', methods=['POST']) +def download_files(): + delete_old_zips() # Clean up old zip files + + file_paths = request.json.get('file_paths', []) + + if not file_paths: + return jsonify({"error": "No files specified"}), 400 + + # Validate and correct file paths + valid_file_paths = [] + for file_path in file_paths: + if file_path.startswith('/data/'): + corrected_path = file_path.lstrip('/') + full_path = os.path.join(app.root_path, corrected_path) + if os.path.isfile(full_path): + valid_file_paths.append(full_path) + elif file_path.startswith('/log/'): + corrected_path = file_path.lstrip('/') + full_path = os.path.join(app.root_path, corrected_path) + if os.path.isfile(full_path): + valid_file_paths.append(full_path) + + if not valid_file_paths: + return jsonify({"error": "No valid files specified"}), 400 + + # Create a unique zip file name + zip_name = f"files_{datetime.now().strftime('%Y%m%d%H%M%S')}.zip" + zip_path = create_zip(valid_file_paths, zip_name) + + return send_from_directory(directory='temp', path=zip_name, as_attachment=True) + @app.route('/delete_files', methods=['POST']) def delete_files(): - file_paths = request.form.getlist('file_paths') + file_paths = request.json.get('file_paths', []) if not file_paths: return jsonify({"error": "No files specified"}), 400 errors = [] for file_path in file_paths: + file_path = os.path.join(app.root_path, file_path.lstrip('/')) if not os.path.isfile(file_path): errors.append({"file": file_path, "error": "File not found"}) continue @@ -323,9 +381,9 @@ def get_size(path): def download_data_file(filename): return send_from_directory('data', filename) -@app.route('/logs/') +@app.route('/log/') def download_log_file(filename): - return send_from_directory('logs', filename) + return send_from_directory('log', filename) @app.route('/config/lines_per_page') def get_lines_per_page(): diff --git a/static/download_results.js b/static/download_results.js index ac0901a..0a98b25 100644 --- a/static/download_results.js +++ b/static/download_results.js @@ -2,9 +2,9 @@ function deleteFiles(filePaths) { fetch('/delete_files', { method: 'POST', headers: { - 'Content-Type': 'application/x-www-form-urlencoded', + 'Content-Type': 'application/json', }, - body: new URLSearchParams({ + body: JSON.stringify({ 'file_paths': filePaths }) }) @@ -29,18 +29,37 @@ function deleteSelectedFiles() { } } + function downloadSelectedFiles() { const selectedFiles = Array.from(document.querySelectorAll('input[name="fileCheckbox"]:checked')) .map(checkbox => checkbox.value); if (selectedFiles.length > 0) { - selectedFiles.forEach(file => { - const link = document.createElement('a'); - link.href = file; - link.download = file.split('/').pop(); - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); - }); + fetch('/download_files', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ 'file_paths': selectedFiles }) + }) + .then(response => { + if (!response.ok) { + return response.json().then(err => { throw new Error(err.error); }); + } + return response.blob(); + }) + .then(blob => { + if (blob.type !== 'application/zip') { + throw new Error("Received invalid ZIP file."); + } + const url = window.URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = 'files.zip'; + document.body.appendChild(a); + a.click(); + a.remove(); + }) + .catch(error => alert('Error: ' + error.message)); } else { alert('No files selected'); } diff --git a/temp/.gitkeep b/temp/.gitkeep new file mode 100644 index 0000000..e69de29