fix: proxy quoted media in dashboard messages
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
from flask import Blueprint, render_template, jsonify, request, current_app
|
||||
import requests
|
||||
from flask import Blueprint, render_template, jsonify, request, current_app, Response, stream_with_context
|
||||
from .auth import login_required
|
||||
from loguru import logger
|
||||
import xml.etree.ElementTree as ET
|
||||
@@ -17,6 +18,41 @@ def _is_emoji_message(msg: dict) -> bool:
|
||||
return message_type in {'47', '1048625', '1090519089'} or any(marker in content for marker in xml_markers)
|
||||
|
||||
|
||||
def _proxy_remote_media(target_url: str) -> Response:
|
||||
if not target_url:
|
||||
return Response("missing url", status=400)
|
||||
|
||||
headers = {
|
||||
"User-Agent": (
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
|
||||
"AppleWebKit/537.36 (KHTML, like Gecko) "
|
||||
"Chrome/123.0.0.0 Safari/537.36"
|
||||
),
|
||||
"Referer": "http://weixin.qq.com/"
|
||||
}
|
||||
range_header = request.headers.get("Range")
|
||||
if range_header:
|
||||
headers["Range"] = range_header
|
||||
|
||||
upstream = requests.get(target_url, headers=headers, stream=True, timeout=30)
|
||||
|
||||
response_headers = {}
|
||||
for key in ("Content-Type", "Content-Length", "Content-Range", "Accept-Ranges", "Cache-Control", "ETag", "Last-Modified"):
|
||||
value = upstream.headers.get(key)
|
||||
if value:
|
||||
response_headers[key] = value
|
||||
|
||||
if "Accept-Ranges" not in response_headers:
|
||||
response_headers["Accept-Ranges"] = "bytes"
|
||||
|
||||
return Response(
|
||||
stream_with_context(upstream.iter_content(chunk_size=64 * 1024)),
|
||||
status=upstream.status_code,
|
||||
headers=response_headers,
|
||||
direct_passthrough=True
|
||||
)
|
||||
|
||||
|
||||
# 消息列表页面
|
||||
@messages_bp.route('/messages')
|
||||
@login_required
|
||||
@@ -63,16 +99,16 @@ def get_messages():
|
||||
continue
|
||||
|
||||
# 处理消息内容,格式化引用消息
|
||||
if msg['message_type'] == "49" and msg['content']: # 应用消息类型
|
||||
if str(msg.get('message_type')) == "49" and msg.get('content'): # 应用消息类型
|
||||
try:
|
||||
# 检查是否为引用消息
|
||||
if '<refermsg>' in msg['content']:
|
||||
# 使用格式化工具处理引用消息
|
||||
quote_data = parse_quote_message(msg['content'])
|
||||
msg['content'] = quote_data['formatted_message']
|
||||
msg['quoted_type'] = quote_data['reference_type']
|
||||
msg['quoted_preview_image'] = quote_data['preview_image']
|
||||
msg['quoted_preview_video_thumb'] = quote_data['preview_video_thumb']
|
||||
msg['content'] = quote_data.get('formatted_message') or format_quote_message(msg['content'])
|
||||
msg['quoted_type'] = quote_data.get('reference_type', '')
|
||||
msg['quoted_preview_image'] = quote_data.get('preview_image', '')
|
||||
msg['quoted_preview_video_thumb'] = quote_data.get('preview_video_thumb', '')
|
||||
else:
|
||||
# 其他类型的应用消息,解析 XML 提取标题
|
||||
root = ET.fromstring(msg['content'])
|
||||
@@ -81,6 +117,10 @@ def get_messages():
|
||||
msg['content'] = title_elem.text
|
||||
except Exception as e:
|
||||
logger.error(f"解析消息类型49出错: {e}")
|
||||
try:
|
||||
msg['content'] = format_quote_message(msg['content'])
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return jsonify(result)
|
||||
except Exception as e:
|
||||
@@ -143,3 +183,14 @@ def get_hourly_message_trend():
|
||||
except Exception as e:
|
||||
logger.error(f"获取按小时聊天趋势数据失败: {e}")
|
||||
return jsonify({'success': False, 'error': str(e)}), 500
|
||||
|
||||
|
||||
@messages_bp.route('/api/messages/media_proxy', methods=['GET'])
|
||||
@login_required
|
||||
def message_media_proxy():
|
||||
target_url = request.args.get('url', '').strip()
|
||||
try:
|
||||
return _proxy_remote_media(target_url)
|
||||
except Exception as e:
|
||||
logger.error(f"消息媒体代理失败: {e}")
|
||||
return Response(f"proxy failed: {e}", status=502)
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
{% raw %}{{ scope.row.content || `【消息类型: ${scope.row.message_type}】` }}{% endraw %}
|
||||
<div v-if="scope.row.quoted_type === 'image' && scope.row.quoted_preview_image" class="quoted-media-preview">
|
||||
<div class="message-media-label">【引用图片】</div>
|
||||
<img :src="scope.row.quoted_preview_image" class="message-thumb" @click="showQuotedImage(scope.row.quoted_preview_image)">
|
||||
<img :src="getMediaProxyUrl(scope.row.quoted_preview_image)" class="message-thumb" @click="showQuotedImage(scope.row.quoted_preview_image)">
|
||||
</div>
|
||||
<div v-else-if="scope.row.quoted_type === 'video' && scope.row.quoted_preview_video_thumb" class="quoted-media-preview">
|
||||
<div class="message-media-label">【引用视频】</div>
|
||||
@@ -361,6 +361,13 @@
|
||||
}
|
||||
|
||||
return `/static/images/${fileName}`;
|
||||
},
|
||||
getMediaProxyUrl(url) {
|
||||
if (!url) return '';
|
||||
if (url.startsWith('/api/messages/media_proxy')) {
|
||||
return url;
|
||||
}
|
||||
return `/api/messages/media_proxy?url=${encodeURIComponent(url)}`;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
||||
Reference in New Issue
Block a user