File size: 5,142 Bytes
3d2357d 7769832 3d2357d 7769832 3d2357d 7769832 3d2357d 7769832 3d2357d 7769832 3d2357d 7769832 4f5d5ba 7769832 4f5d5ba 3d2357d |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
import os
import requests
import urllib.parse
from flask import Flask, render_template, request, redirect, url_for, flash, jsonify, Response
from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user
from werkzeug.security import check_password_hash, generate_password_hash
from dotenv import load_dotenv
import time
# 加载环境变量
load_dotenv()
app = Flask(__name__)
app.secret_key = os.environ.get('SECRET_KEY', 'starsky_secret_key')
# 登录管理配置
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'
# 用户类
class User(UserMixin):
def __init__(self, id, username, password_hash):
self.id = id
self.username = username
self.password_hash = password_hash
# 默认用户
default_username = os.environ.get('ADMIN_USERNAME', 'admin')
default_password = os.environ.get('ADMIN_PASSWORD', 'admin123')
# 用户存储
users = {
default_username: User(
default_username,
default_username,
generate_password_hash(default_password)
)
}
# 检查 subconverter 是否启动
def check_subconverter():
max_retries = 10
for i in range(max_retries):
try:
response = requests.get('http://localhost:25500/version', timeout=2)
if response.status_code == 200:
print(f"Subconverter 服务已启动: {response.text}")
return True
except:
pass
print(f"等待 Subconverter 服务启动... ({i+1}/{max_retries})")
time.sleep(2)
print("警告: Subconverter 服务可能未正常启动")
return False
# 应用启动时检查 subconverter 服务
check_subconverter()
@login_manager.user_loader
def load_user(user_id):
return users.get(user_id)
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
user = users.get(username)
if user and check_password_hash(user.password_hash, password):
login_user(user)
return redirect(url_for('index'))
else:
flash('用户名或密码错误')
return render_template('login.html')
@app.route('/logout')
@login_required
def logout():
logout_user()
return redirect(url_for('login'))
@app.route('/')
@login_required
def index():
return render_template('index.html')
@app.route('/convert', methods=['POST'])
@login_required
def convert():
# 获取参数
backend_url = request.form.get('backend_url', 'https://raw.githubusercontent.com/yuanwangokk-1/subscribe/refs/heads/main/ACL4SSR/ACL4SSR.ini')
target = request.form.get('target', 'clash')
original_url = request.form.get('original_url', '')
if not original_url:
return jsonify({"status": "error", "message": "订阅链接不能为空"})
try:
# 检查subconverter服务是否可用
try:
version_check = requests.get('http://localhost:25500/version', timeout=2)
if version_check.status_code != 200:
return jsonify({"status": "error", "message": "订阅转换服务暂时不可用,请稍后再试"})
except:
return jsonify({"status": "error", "message": "订阅转换服务暂时不可用,请稍后再试"})
# 构建转换请求参数
params = {
'target': target,
'url': original_url,
'insert': 'false',
'config': backend_url,
'emoji': 'true',
'list': 'false',
'xudp': 'false',
'udp': 'false',
'tfo': 'false',
'expand': 'true',
'scv': 'false',
'fdn': 'false',
'new_name': 'true'
}
# 通过URL参数构建转换链接
base_url = request.host_url.rstrip('/')
convert_url = f"{base_url}/api/sub?{urllib.parse.urlencode(params)}"
return jsonify({"status": "success", "result": convert_url})
except Exception as e:
return jsonify({"status": "error", "message": f"处理失败: {str(e)}"})
@app.route('/api/sub')
def subscribe_api():
"""代理 subconverter 的转换请求"""
try:
# 获取所有URL参数
params = request.args.to_dict()
# 调用本地 subconverter 服务
sub_url = f"http://localhost:25500/sub?{urllib.parse.urlencode(params)}"
response = requests.get(sub_url, timeout=30)
# 返回原始响应
return Response(
response.content,
status=response.status_code,
content_type=response.headers.get('Content-Type', 'text/plain')
)
except Exception as e:
return f"转换失败: {str(e)}", 500
# 不要在这里调用 app.run()
# 让 Hugging Face 的 WSGI 服务器来运行应用
# 仅在本地开发时使用以下代码
if __name__ == '__main__' and os.environ.get('DEVELOPMENT') == 'true':
app.run(host='0.0.0.0', port=7860, debug=True)
|