Files
fedora-metalink-proxy/app.py
2025-06-20 19:20:36 +01:00

101 lines
3.6 KiB
Python

import os
import requests
from flask import Flask, render_template, request, redirect, url_for, Response
from dotenv import load_dotenv
from bs4 import BeautifulSoup
# Load environment variables from .env file
load_dotenv()
app = Flask(__name__, template_folder='templates')
def get_config():
"""Retrieve configuration from environment variables."""
return {
"excluded_countries": os.getenv('EXCLUDED_COUNTRIES', '[]'),
"preferred_protocols": os.getenv('PREFERRED_PROTOCOLS', '["https", "http"]'),
"preferred_types": os.getenv('PREFERRED_TYPES', '["https", "http"]'),
"min_preference": os.getenv('MIN_PREFERENCE', '0')
}
@app.route('/metalink')
def get_metalink():
# Get query parameters from the request
repo = request.args.get('repo')
arch = request.args.get('arch')
# Check if required parameters are provided
if not repo or not arch:
return "Error: Missing 'repo' or 'arch' parameter", 400
# Construct the metalink URL using the provided parameters
metalink_url = f'https://mirrors.fedoraproject.org/metalink?repo={repo}&arch={arch}'
# Fetch the metalink file from the constructed URL
response = requests.get(metalink_url)
metalink_content = response.content
# Get the filtering criteria from environment variables
config = get_config()
excluded_countries = eval(config['excluded_countries'])
preferred_protocols = eval(config['preferred_protocols'])
preferred_types = eval(config['preferred_types'])
min_preference = int(config['min_preference'])
# Filter out the URLs based on the criteria
filtered_content = filter_urls(metalink_content, excluded_countries, preferred_protocols, preferred_types, min_preference)
# Return the filtered content as a response
return Response(filtered_content, mimetype='application/xml')
def filter_urls(content, excluded_countries, preferred_protocols, preferred_types, min_preference):
# Parse the XML content
soup = BeautifulSoup(content, 'xml')
# Find all URL elements
urls = soup.find_all('url')
# Iterate over URLs and remove those that do not meet the criteria
for url in urls:
location = url.get('location')
protocol = url.get('protocol')
type_ = url.get('type')
preference = int(url.get('preference', 0))
if (location in excluded_countries or
protocol not in preferred_protocols or
type_ not in preferred_types or
preference < min_preference):
url.decompose()
# Convert the BeautifulSoup object back to a string and clean up
filtered_content = str(soup)
filtered_content = '\n'.join(line for line in filtered_content.splitlines() if line.strip())
return filtered_content
@app.route('/dash/config', methods=['GET', 'POST'])
def config_route():
if request.method == 'POST':
# Update environment variables with form data
os.environ['EXCLUDED_COUNTRIES'] = request.form.get('excluded_countries', '')
os.environ['PREFERRED_PROTOCOLS'] = request.form.get('preferred_protocols', '')
os.environ['PREFERRED_TYPES'] = request.form.get('preferred_types', '')
os.environ['MIN_PREFERENCE'] = request.form.get('min_preference', '')
return redirect(url_for('config_route'))
config = get_config()
return render_template('config.html', **config)
@app.route('/dash/stats')
def stats():
return render_template('stats.html')
@app.route('/dash/logs')
def logs():
return render_template('logs.html')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8182)