修复安卓手机显示名称不符显示为linux的问题;修复文件名乱码的问题

This commit is contained in:
2026-03-28 19:13:22 +08:00
parent 3d391415c6
commit 8b5f7d517e
5 changed files with 92 additions and 28 deletions

View File

@@ -456,6 +456,7 @@ func (h *HTTPHandler) downloadFallback(c *gin.Context) {
defer cancel()
filename := filepath.Base(transfer.Name)
filename = decodeDownloadFilename(filename)
if filename == "." || filename == "" {
filename = "download.bin"
}
@@ -597,6 +598,19 @@ func contentDisposition(filename string) string {
return `attachment; filename="` + escaped + `"`
}
func decodeDownloadFilename(filename string) string {
filename = strings.TrimSpace(filename)
if filename == "" || !strings.Contains(filename, "%") {
return filename
}
decoded, err := url.PathUnescape(filename)
if err != nil {
return filename
}
return strings.TrimSpace(decoded)
}
func (h *HTTPHandler) ensureFallbackBucket(ctx context.Context, transferID string) error {
if h.deps.MinIOClient == nil {
return nil

17
frontend/dist/assets/index-BoiTbES-.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -4,7 +4,7 @@
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>AirShare Pro</title>
<script type="module" crossorigin src="/assets/index-DPzeYqvr.js"></script>
<script type="module" crossorigin src="/assets/index-BoiTbES-.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-C-7tVt-S.css">
</head>
<body>

View File

@@ -302,6 +302,7 @@ async function loadPendingDownloads() {
const downloads = await devicesApi.listPendingDownloads(localDevice.value.id)
pendingDownloads.value = downloads.map((item) => ({
...item,
name: normalizeDisplayName(item.name),
download_path: item.download_path || `/api/transfers/${encodeURIComponent(item.transfer_id)}/fallback/download`,
size_label: formatFileSize(Number(item.size_bytes || 0)),
created_label: formatRelativeTime(item.created_at),
@@ -551,7 +552,7 @@ function addFiles(files) {
id: createId(`file-${index}`),
kind: 'file',
file,
name: file.name,
name: normalizeDisplayName(file.name),
size: formatFileSize(file.size),
sizeBytes: file.size,
status: '待发送',
@@ -1166,15 +1167,47 @@ function ensureDeviceId() {
function ensureDeviceName(deviceId) {
let deviceName = localStorage.getItem(DEVICE_NAME_KEY)
if (!deviceName) {
const platform = navigator.userAgentData?.platform || navigator.platform || 'Web'
deviceName = `${platform} ${deviceId.slice(0, 4)}`
if (!deviceName || isLegacyAutoDeviceName(deviceName, deviceId)) {
deviceName = `${detectDeviceLabel()} ${deviceId.slice(0, 4)}`
localStorage.setItem(DEVICE_NAME_KEY, deviceName)
}
return deviceName
}
function isLegacyAutoDeviceName(deviceName, deviceId) {
const value = String(deviceName || '').trim()
const suffix = deviceId.slice(0, 4)
if (!value || !suffix || !value.endsWith(` ${suffix}`)) {
return false
}
return /^(android|iphone|ipad|linux|macintel|macos|windows|win32|web)\s/i.test(value)
}
function detectDeviceLabel() {
const source = `${navigator.userAgent} ${navigator.platform}`.toLowerCase()
if (source.includes('iphone')) {
return 'iPhone'
}
if (source.includes('ipad')) {
return 'iPad'
}
if (source.includes('android')) {
return 'Android'
}
if (source.includes('windows') || source.includes('win32')) {
return 'Windows'
}
if (source.includes('mac os') || source.includes('macintosh') || source.includes('macintel')) {
return 'macOS'
}
if (source.includes('linux')) {
return 'Linux'
}
return 'Web'
}
function detectDeviceType() {
const source = `${navigator.userAgent} ${navigator.platform}`.toLowerCase()
if (source.includes('iphone') || source.includes('android') || source.includes('mobile')) {
@@ -1186,6 +1219,23 @@ function detectDeviceType() {
return 'desktop'
}
function normalizeDisplayName(value, fallback = 'file') {
const raw = String(value || '').trim()
if (!raw) {
return fallback
}
if (!/%[0-9A-Fa-f]{2}/.test(raw)) {
return raw
}
try {
return decodeURIComponent(raw)
} catch {
return raw
}
}
function mapDeviceIcon(type) {
if (type === 'phone') {
return 'smartphone'
@@ -1600,7 +1650,7 @@ function handleIncomingRealtimeFileMeta(payload) {
ensurePeerSession(sender, true)
incomingFileBuffers.set(payload.transfer_id, {
name: payload.name || 'file',
name: normalizeDisplayName(payload.name, 'file'),
mimeType: payload.mime_type || 'application/octet-stream',
sizeBytes: Number(payload.size_bytes || 0),
receivedBytes: 0,
@@ -1613,7 +1663,7 @@ function handleIncomingRealtimeFileMeta(payload) {
id: createId('incoming-file'),
transferId: payload.transfer_id,
kind: 'file',
name: payload.name || 'file',
name: normalizeDisplayName(payload.name, 'file'),
size: formatFileSize(Number(payload.size_bytes || 0)),
sizeBytes: Number(payload.size_bytes || 0),
status: '正在接收...',
@@ -1965,7 +2015,7 @@ function handleIncomingTransferCreated(envelope) {
id: createId('incoming-file'),
transferId: payload.transfer_id,
kind: 'file',
name: payload.name || 'file',
name: normalizeDisplayName(payload.name, 'file'),
size: formatFileSize(Number(payload.size_bytes || 0)),
sizeBytes: Number(payload.size_bytes || 0),
status: '接收中...',
@@ -2010,7 +2060,7 @@ function handleIncomingTransferFile(envelope) {
id: createId('incoming-file'),
transferId: payload.transfer_id,
kind: 'file',
name: payload.name || 'file',
name: normalizeDisplayName(payload.name, 'file'),
size: '',
sizeBytes: 0,
status: '可保存',
@@ -2742,7 +2792,7 @@ handleIncomingTransferCreated = function handleIncomingTransferCreatedOverride(e
id: createId('incoming-file'),
transferId: payload.transfer_id,
kind: 'file',
name: payload.name || 'file',
name: normalizeDisplayName(payload.name, 'file'),
size: formatFileSize(Number(payload.size_bytes || 0)),
sizeBytes: Number(payload.size_bytes || 0),
status: '等待接收...',
@@ -2791,7 +2841,7 @@ handleIncomingTransferFile = function handleIncomingTransferFileOverride(envelop
id: createId('incoming-file'),
transferId: payload.transfer_id,
kind: 'file',
name: payload.name || 'file',
name: normalizeDisplayName(payload.name, 'file'),
size: '',
sizeBytes: 0,
status: '可保存',