import os import glob from flask import render_template, Blueprint, current_app, request from app.tasks import get_redis from app.forms import ScrapingForm from app.util import get_size from app.config import load_config from app.api import scraper as scraper from app.analysis import load_data, load_analysis_modules from datetime import datetime views_bp = Blueprint("views", __name__) def sizeof_fmt(num, suffix="B"): """Convert bytes to human readable format""" for unit in ["", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"]: if abs(num) < 1024.0: return f"{num:3.1f} {unit}{suffix}" num /= 1024.0 return f"{num:.1f} Yi{suffix}" def register_views(app): @app.route('/') def index(): form = ScrapingForm() return render_template('index.html', form=form) @app.route('/results') def results(): return render_template('results.html') @app.route('/log_viewer') def log_viewer(): return render_template('log_viewer.html') @app.route('/download_results') def download_results(): # Get the current active log file and data file from Redis and app config redis_client = get_redis() current_faction_id = redis_client.get("current_faction_id") active_data_file = None if current_faction_id: active_data_file = redis_client.hget(f"scraper:{current_faction_id}", "data_file_name") active_log_file = app.config['LOG_FILE_NAME'] def get_file_info(file_path, file_type='data'): stats = os.stat(file_path) name = os.path.basename(file_path) # Determine if file is active is_active = False if file_type == 'data' and active_data_file: is_active = os.path.abspath(file_path) == os.path.abspath(active_data_file) elif file_type == 'log' and active_log_file: is_active = os.path.basename(file_path) == os.path.basename(active_log_file) return { 'name': file_path, # Full path for internal use 'name_display': name, # Just filename for display 'last_modified': stats.st_mtime, # Send timestamp instead of datetime 'created': stats.st_ctime, # Send timestamp instead of datetime 'size': sizeof_fmt(stats.st_size), 'active': is_active } data_files = [] log_files = [] # Get data files data_dir = os.path.abspath(app.config['DATA']['DATA_DIR']) if os.path.exists(data_dir): for file in glob.glob(os.path.join(data_dir, "*.csv")): data_files.append(get_file_info(file, 'data')) # Get log files log_dir = os.path.abspath(app.config['LOGGING']['LOG_DIR']) if os.path.exists(log_dir): for file in glob.glob(os.path.join(log_dir, "*.log")): log_files.append(get_file_info(file, 'log')) # Sort files by modification time, newest first data_files.sort(key=lambda x: x['last_modified'], reverse=True) log_files.sort(key=lambda x: x['last_modified'], reverse=True) files = { 'data': data_files, 'log': log_files } return render_template('download_results.html', files=files) views_bp = Blueprint("views", __name__) @views_bp.route("/analyze", methods=["GET", "POST"]) def analyze(): analysis_modules = load_analysis_modules() # Load available analyses data_dir = current_app.config.get("DATA", {}).get("DATA_DIR") selected_file = None selected_analyses = [] # Find all available CSV files data_files = sorted( glob.glob(os.path.join(data_dir, "*.csv")), key=os.path.getmtime, reverse=True ) if data_dir else [] context = { "data_files": data_files, "analyses": analysis_modules, "selected_file": selected_file, "selected_analyses": selected_analyses } if request.method == "POST": selected_analyses = request.form.getlist("analyses") selected_file = request.form.get("data_file") if not selected_file: context["error"] = "No file selected." return render_template("analyze.html", **context) df = load_data(selected_file) results = {} for analysis in analysis_modules: if analysis.name in selected_analyses: results[analysis.name] = analysis.execute(df) # Some may return HTML context["results"] = results return render_template("analyze.html", **context) @views_bp.route('/server_time') def server_time(): current_time = datetime.now(datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S') return {'server_time': current_time} app.register_blueprint(views_bp)