This commit is contained in:
2025-11-28 21:20:40 +08:00
commit f940b95b67
73 changed files with 15721 additions and 0 deletions

202
routes/parser.py Normal file
View File

@@ -0,0 +1,202 @@
from flask import Blueprint, request, jsonify
from flask_login import current_user
from models import ParseLog
from models import db
from utils.security import get_client_ip
from utils.limiter import RateLimiter
from utils.queue import ParseQueue, ConcurrencyController
from parsers.factory import ParserFactory
import uuid
import time
from datetime import datetime
parser_bp = Blueprint('parser', __name__)
@parser_bp.route('/parse', methods=['POST'])
def parse_video():
"""解析视频"""
data = request.get_json()
video_url = data.get('url')
if not video_url:
return jsonify({'success': False, 'message': '请提供视频链接'}), 400
# 获取用户信息
user_id = current_user.id if current_user.is_authenticated else None
ip_address = get_client_ip(request)
# 检查限流
limit_check = RateLimiter.check_limit(user_id=user_id, ip_address=ip_address)
if not limit_check['allowed']:
return jsonify({
'success': False,
'message': f"今日解析次数已达上限({limit_check['limit']}次)",
'limit_info': limit_check
}), 429
# 检测平台
try:
platform = ParserFactory.detect_platform(video_url)
except ValueError as e:
return jsonify({'success': False, 'message': str(e)}), 400
# 生成任务ID
task_id = str(uuid.uuid4())
# 添加到队列
ParseQueue.add_task(task_id, video_url, user_id, ip_address)
# 尝试立即处理
if ConcurrencyController.can_process():
result = _process_task(task_id, video_url, platform, user_id, ip_address)
return jsonify(result)
else:
# 返回任务ID让前端轮询
return jsonify({
'success': True,
'status': 'queued',
'task_id': task_id,
'message': '任务已加入队列,请稍候...',
'queue_status': ParseQueue.get_queue_status()
})
@parser_bp.route('/task/<task_id>', methods=['GET'])
def get_task_result(task_id):
"""获取任务结果"""
result = ParseQueue.get_result(task_id)
if result:
return jsonify(result)
else:
# 检查是否还在队列中
queue_status = ParseQueue.get_queue_status()
return jsonify({
'success': False,
'status': 'processing',
'message': '任务处理中...',
'queue_status': queue_status
})
@parser_bp.route('/queue-status', methods=['GET'])
def queue_status():
"""获取队列状态"""
status = ParseQueue.get_queue_status()
return jsonify({
'success': True,
'queue_status': status
})
def _process_task(task_id, video_url, platform, user_id, ip_address):
"""处理解析任务"""
start_time = time.time()
# 获取该平台所有可用的API
from models import ParserAPI
available_apis = ParserAPI.query.filter_by(
platform=platform.lower(),
is_enabled=True
).all()
if not available_apis:
return {
'success': False,
'status': 'failed',
'message': f'没有可用的{platform}解析接口',
'response_time': int((time.time() - start_time) * 1000)
}
last_error = None
# 尝试所有可用的API
for api_config in available_apis:
try:
# 创建解析器
parser = ParserFactory.create_parser(api_config)
# 执行解析
result = parser.parse(video_url)
# 计算响应时间
response_time = int((time.time() - start_time) * 1000)
# 记录日志
log = ParseLog(
user_id=user_id,
ip_address=ip_address,
platform=platform,
video_url=video_url,
parser_api_id=api_config.id,
status='success',
response_time=response_time
)
db.session.add(log)
# 更新API统计
api_config.total_calls += 1
api_config.success_calls += 1
api_config.avg_response_time = int(
(api_config.avg_response_time * (api_config.total_calls - 1) + response_time) / api_config.total_calls
)
api_config.fail_count = 0 # 重置失败计数
# 更新用户统计
if user_id:
from models import User
user = User.query.get(user_id)
user.total_parse_count += 1
# 更新限流计数
RateLimiter.increment_count(user_id=user_id, ip_address=ip_address, success=True)
db.session.commit()
# 保存结果
response = {
'success': True,
'status': 'completed',
'data': result,
'response_time': response_time
}
ParseQueue.complete_task(task_id, response)
return response
except Exception as e:
# 记录失败继续尝试下一个API
last_error = str(e)
api_config.total_calls += 1
api_config.fail_count += 1
db.session.commit()
continue
# 所有API都失败了
# 计算响应时间
response_time = int((time.time() - start_time) * 1000)
# 记录失败日志
log = ParseLog(
user_id=user_id,
ip_address=ip_address,
platform=platform,
video_url=video_url,
status='failed',
error_message=last_error or '所有接口都失败',
response_time=response_time
)
db.session.add(log)
# 更新限流计数(失败也计数)
RateLimiter.increment_count(user_id=user_id, ip_address=ip_address, success=False)
db.session.commit()
# 保存错误结果
response = {
'success': False,
'status': 'failed',
'message': last_error or '所有解析接口都失败',
'response_time': response_time
}
ParseQueue.complete_task(task_id, response)
return response