feat: preview emoji media in message list
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
import requests
|
||||
import html
|
||||
import re
|
||||
from flask import Blueprint, render_template, jsonify, request, current_app, Response, stream_with_context
|
||||
from .auth import login_required
|
||||
from loguru import logger
|
||||
@@ -31,6 +33,17 @@ def _is_usable_local_media_path(value: str) -> bool:
|
||||
return False
|
||||
|
||||
|
||||
def _extract_emoji_preview_url(xml_text: str) -> str:
|
||||
if not xml_text:
|
||||
return ''
|
||||
patterns = (r'cdnurl="([^"]+)"', r'encrypturl="([^"]+)"', r'externurl="([^"]+)"')
|
||||
for pattern in patterns:
|
||||
match = re.search(pattern, xml_text)
|
||||
if match:
|
||||
return html.unescape(match.group(1))
|
||||
return ''
|
||||
|
||||
|
||||
def _proxy_remote_media(target_url: str) -> Response:
|
||||
if not target_url:
|
||||
return Response("missing url", status=400)
|
||||
@@ -109,6 +122,7 @@ def get_messages():
|
||||
|
||||
if _is_emoji_message(msg):
|
||||
msg['content'] = '[表情]'
|
||||
msg['emoji_preview_url'] = msg.get('image_path') or _extract_emoji_preview_url(msg.get('attachment_url', ''))
|
||||
continue
|
||||
|
||||
# 处理消息内容,格式化引用消息
|
||||
|
||||
@@ -87,6 +87,16 @@
|
||||
<img v-else-if="scope.row.message_thumb" :src="scope.row.message_thumb" class="message-thumb" @click="showImage(scope.row)">
|
||||
</div>
|
||||
|
||||
<div v-else-if="isEmojiMessage(scope.row)" class="message-media-preview">
|
||||
<div class="message-media-label">【表情消息】</div>
|
||||
<img
|
||||
v-if="getEmojiPreviewUrl(scope.row)"
|
||||
:src="getEmojiPreviewUrl(scope.row)"
|
||||
class="message-thumb"
|
||||
@click="showEmoji(scope.row)">
|
||||
<div v-else class="message-text-preview is-muted">【表情消息】等待下载完成</div>
|
||||
</div>
|
||||
|
||||
<div v-else-if="scope.row.message_type == 43" class="message-media-preview">
|
||||
<div class="message-media-label">【视频消息】</div>
|
||||
<img v-if="scope.row.message_thumb" :src="scope.row.message_thumb" class="message-thumb" @click="showVideo(scope.row)">
|
||||
@@ -138,8 +148,9 @@
|
||||
<el-descriptions-item label="消息类型">{% raw %}{{ getMessageTypeName(selectedMessage.message_type) }}{% endraw %}</el-descriptions-item>
|
||||
<el-descriptions-item label="内容">{% raw %}{{ selectedMessage.content }}{% endraw %}</el-descriptions-item>
|
||||
|
||||
<el-descriptions-item v-if="selectedMessage.message_type == 3 || selectedMessage.message_type == 43" label="媒体内容">
|
||||
<el-descriptions-item v-if="selectedMessage.message_type == 3 || selectedMessage.message_type == 43 || isEmojiMessage(selectedMessage)" label="媒体内容">
|
||||
<img v-if="selectedMessage.message_type == 3 && selectedMessage.image_path" :src="getImageUrl(selectedMessage.image_path)" style="max-width: 100%; border-radius: 16px;">
|
||||
<img v-else-if="isEmojiMessage(selectedMessage) && getEmojiPreviewUrl(selectedMessage)" :src="getEmojiPreviewUrl(selectedMessage)" style="max-width: 100%; border-radius: 16px;">
|
||||
<img v-else-if="selectedMessage.message_type == 3 && selectedMessage.message_thumb" :src="selectedMessage.message_thumb" style="max-width: 100%; border-radius: 16px;">
|
||||
<video v-if="selectedMessage.message_type == 43 && selectedMessage.attachment_url" :src="selectedMessage.attachment_url" controls style="max-width: 100%; border-radius: 16px;"></video>
|
||||
</el-descriptions-item>
|
||||
@@ -153,6 +164,7 @@
|
||||
|
||||
<el-dialog :visible.sync="imageDialogVisible" append-to-body width="80%" class="image-dialog">
|
||||
<img v-if="selectedMessage && selectedMessage.image_path" :src="getImageUrl(selectedMessage.image_path)" style="max-width: 100%; border-radius: 18px;">
|
||||
<img v-else-if="selectedMessage && getEmojiPreviewUrl(selectedMessage)" :src="getEmojiPreviewUrl(selectedMessage)" style="max-width: 100%; border-radius: 18px;">
|
||||
<img v-else-if="selectedMessage && selectedMessage.message_thumb" :src="selectedMessage.message_thumb" style="max-width: 100%; border-radius: 18px;">
|
||||
</el-dialog>
|
||||
</div>
|
||||
@@ -321,6 +333,10 @@
|
||||
this.selectedMessage = message;
|
||||
this.imageDialogVisible = true;
|
||||
},
|
||||
showEmoji(message) {
|
||||
this.selectedMessage = message;
|
||||
this.imageDialogVisible = true;
|
||||
},
|
||||
showQuotedImage(url) {
|
||||
const resolvedUrl = this.getQuotedPreviewUrl(url);
|
||||
if (!resolvedUrl) return;
|
||||
@@ -341,6 +357,10 @@
|
||||
};
|
||||
return typeMap[type] || `未知类型(${type})`;
|
||||
},
|
||||
isEmojiMessage(message) {
|
||||
if (!message) return false;
|
||||
return ['47', '1048625', '1090519089'].includes(String(message.message_type));
|
||||
},
|
||||
getImageUrl(imagePath) {
|
||||
if (!imagePath) return '';
|
||||
|
||||
@@ -367,6 +387,20 @@
|
||||
|
||||
return `/static/images/${fileName}`;
|
||||
},
|
||||
getEmojiPreviewUrl(message) {
|
||||
if (!message) return '';
|
||||
if (message.image_path) {
|
||||
return this.getImageUrl(message.image_path);
|
||||
}
|
||||
const previewUrl = message.emoji_preview_url || '';
|
||||
if (!previewUrl) {
|
||||
return '';
|
||||
}
|
||||
if (previewUrl.startsWith('http://') || previewUrl.startsWith('https://')) {
|
||||
return this.getMediaProxyUrl(previewUrl);
|
||||
}
|
||||
return this.getImageUrl(previewUrl);
|
||||
},
|
||||
getMediaProxyUrl(url) {
|
||||
if (!url) return '';
|
||||
if (url.startsWith('/api/messages/media_proxy')) {
|
||||
|
||||
Reference in New Issue
Block a user