feat: preview emoji media in message list
This commit is contained in:
@@ -1,4 +1,6 @@
|
|||||||
import requests
|
import requests
|
||||||
|
import html
|
||||||
|
import re
|
||||||
from flask import Blueprint, render_template, jsonify, request, current_app, Response, stream_with_context
|
from flask import Blueprint, render_template, jsonify, request, current_app, Response, stream_with_context
|
||||||
from .auth import login_required
|
from .auth import login_required
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
@@ -31,6 +33,17 @@ def _is_usable_local_media_path(value: str) -> bool:
|
|||||||
return False
|
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:
|
def _proxy_remote_media(target_url: str) -> Response:
|
||||||
if not target_url:
|
if not target_url:
|
||||||
return Response("missing url", status=400)
|
return Response("missing url", status=400)
|
||||||
@@ -109,6 +122,7 @@ def get_messages():
|
|||||||
|
|
||||||
if _is_emoji_message(msg):
|
if _is_emoji_message(msg):
|
||||||
msg['content'] = '[表情]'
|
msg['content'] = '[表情]'
|
||||||
|
msg['emoji_preview_url'] = msg.get('image_path') or _extract_emoji_preview_url(msg.get('attachment_url', ''))
|
||||||
continue
|
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)">
|
<img v-else-if="scope.row.message_thumb" :src="scope.row.message_thumb" class="message-thumb" @click="showImage(scope.row)">
|
||||||
</div>
|
</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 v-else-if="scope.row.message_type == 43" class="message-media-preview">
|
||||||
<div class="message-media-label">【视频消息】</div>
|
<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)">
|
<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 %}{{ getMessageTypeName(selectedMessage.message_type) }}{% endraw %}</el-descriptions-item>
|
||||||
<el-descriptions-item label="内容">{% raw %}{{ selectedMessage.content }}{% 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-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;">
|
<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>
|
<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>
|
</el-descriptions-item>
|
||||||
@@ -153,6 +164,7 @@
|
|||||||
|
|
||||||
<el-dialog :visible.sync="imageDialogVisible" append-to-body width="80%" class="image-dialog">
|
<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-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;">
|
<img v-else-if="selectedMessage && selectedMessage.message_thumb" :src="selectedMessage.message_thumb" style="max-width: 100%; border-radius: 18px;">
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
@@ -321,6 +333,10 @@
|
|||||||
this.selectedMessage = message;
|
this.selectedMessage = message;
|
||||||
this.imageDialogVisible = true;
|
this.imageDialogVisible = true;
|
||||||
},
|
},
|
||||||
|
showEmoji(message) {
|
||||||
|
this.selectedMessage = message;
|
||||||
|
this.imageDialogVisible = true;
|
||||||
|
},
|
||||||
showQuotedImage(url) {
|
showQuotedImage(url) {
|
||||||
const resolvedUrl = this.getQuotedPreviewUrl(url);
|
const resolvedUrl = this.getQuotedPreviewUrl(url);
|
||||||
if (!resolvedUrl) return;
|
if (!resolvedUrl) return;
|
||||||
@@ -341,6 +357,10 @@
|
|||||||
};
|
};
|
||||||
return typeMap[type] || `未知类型(${type})`;
|
return typeMap[type] || `未知类型(${type})`;
|
||||||
},
|
},
|
||||||
|
isEmojiMessage(message) {
|
||||||
|
if (!message) return false;
|
||||||
|
return ['47', '1048625', '1090519089'].includes(String(message.message_type));
|
||||||
|
},
|
||||||
getImageUrl(imagePath) {
|
getImageUrl(imagePath) {
|
||||||
if (!imagePath) return '';
|
if (!imagePath) return '';
|
||||||
|
|
||||||
@@ -367,6 +387,20 @@
|
|||||||
|
|
||||||
return `/static/images/${fileName}`;
|
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) {
|
getMediaProxyUrl(url) {
|
||||||
if (!url) return '';
|
if (!url) return '';
|
||||||
if (url.startsWith('/api/messages/media_proxy')) {
|
if (url.startsWith('/api/messages/media_proxy')) {
|
||||||
|
|||||||
Reference in New Issue
Block a user