Repository: AlistGo/alist (language: go)

Issue:
解压缩创建文件夹中文乱码
### Please make sure of the following things

- [x] I have read the [documentation](https://alist.nn.ci).
我已经阅读了[文档](https://alist.nn.ci)。

- [x] I'm sure there are no duplicate issues or discussions.
我确定没有重复的issue或讨论。

- [x] I'm sure it's due to `AList` and not something else(such as [Network](https://alist.nn.ci/faq/howto.html#tls-handshake-timeout-read-connection-reset-by-peer-dns-lookup-failed-connect-connection-refused-client-timeout-exceeded-while-awaiting-headers-no-such-host) ,`Dependencies` or `Operational`).
我确定是`AList`的问题，而不是其他原因（例如[网络](https://alist.nn.ci/zh/faq/howto.html#tls-handshake-timeout-read-connection-reset-by-peer-dns-lookup-failed-connect-connection-refused-client-timeout-exceeded-while-awaiting-headers-no-such-host)，`依赖`或`操作`）。

- [x] I'm sure this issue is not fixed in the latest version.
我确定这个问题在最新版本中没有被修复。


### AList Version / AList 版本

v3.42.0

### Driver used / 使用的存储驱动

local

### Describe the bug / 问题描述

文件解压到本地，新建文件夹，中文乱码。这里新建文件夹中文名称的时候，编码可能有问题。alist能显示，但是linux系统 文件管理器上显示的文件夹名称是乱码。

![Image](https://github.com/user-attachments/assets/d6c6b7f4-934c-40c4-b07b-f2ab35eb185e)


![Image](https://github.com/user-attachments/assets/8f719e29-22de-430e-93c8-0200219ae4ac)



比较有意思的是，文件解压后文件名称（中文）正常，但是 alist 网页加载显示的不正常。说明 网页设置编码可能不支持中文。

![Image](https://github.com/user-attachments/assets/96470385-473d-444f-a97f-285be08fdeb7)

![Image](https://github.com/user-attachments/assets/821aa517-e4f2-4969-a2a5-0906fb8141e4)



### Reproduction / 复现链接

压缩文件----------右键解压到指定目录--------选择新建子目录

### Config / 配置

无

### Logs / 日志

_No response_


Discussion / hints:

Fix patch:
diff --git a/internal/archive/zip/utils.go b/internal/archive/zip/utils.go
index 81b47782840..aa51b88eb93 100644
--- a/internal/archive/zip/utils.go
+++ b/internal/archive/zip/utils.go
@@ -59,7 +59,7 @@ func _decompress(file *zip.File, targetPath, password string, up model.UpdatePro
 		return err
 	}
 	defer rc.Close()
-	f, err := os.OpenFile(stdpath.Join(targetPath, file.FileInfo().Name()), os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600)
+	f, err := os.OpenFile(stdpath.Join(targetPath, decodeName(file.FileInfo().Name())), os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600)
 	if err != nil {
 		return err
 	}
@@ -87,12 +87,27 @@ func filterPassword(err error) error {
 func decodeName(name string) string {
 	b := []byte(name)
 	detector := chardet.NewTextDetector()
-	result, err := detector.DetectBest(b)
+	results, err := detector.DetectAll(b)
 	if err != nil {
 		return name
 	}
-	enc := getEncoding(result.Charset)
-	if enc == nil {
+	var ce, re, enc encoding.Encoding
+	for _, r := range results {
+		if r.Confidence > 30 {
+			ce = getCommonEncoding(r.Charset)
+			if ce != nil {
+				break
+			}
+		}
+		if re == nil {
+			re = getEncoding(r.Charset)
+		}
+	}
+	if ce != nil {
+		enc = ce
+	} else if re != nil {
+		enc = re
+	} else {
 		return name
 	}
 	i := bytes.NewReader(b)
@@ -101,8 +116,30 @@ func decodeName(name string) string {
 	return string(content)
 }
 
+func getCommonEncoding(name string) (enc encoding.Encoding) {
+	switch name {
+	case "UTF-8":
+		enc = unicode.UTF8
+	case "UTF-16LE":
+		enc = unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM)
+	case "Shift_JIS":
+		enc = japanese.ShiftJIS
+	case "GB-18030":
+		enc = simplifiedchinese.GB18030
+	case "EUC-KR":
+		enc = korean.EUCKR
+	case "Big5":
+		enc = traditionalchinese.Big5
+	default:
+		enc = nil
+	}
+	return
+}
+
 func getEncoding(name string) (enc encoding.Encoding) {
 	switch name {
+	case "UTF-8":
+		enc = unicode.UTF8
 	case "UTF-16BE":
 		enc = unicode.UTF16(unicode.BigEndian, unicode.IgnoreBOM)
 	case "UTF-16LE":
diff --git a/internal/archive/zip/zip.go b/internal/archive/zip/zip.go
index e5285518b05..9dc8cc7638f 100644
--- a/internal/archive/zip/zip.go
+++ b/internal/archive/zip/zip.go
@@ -35,7 +35,6 @@ func (*Zip) GetMeta(ss *stream.SeekableStream, args model.ArchiveArgs) (model.Ar
 	for _, file := range zipReader.File {
 		if file.IsEncrypted() {
 			encrypted = true
-			break
 		}
 
 		name := strings.TrimPrefix(decodeName(file.Name), "/")
@@ -70,6 +69,7 @@ func (*Zip) GetMeta(ss *stream.SeekableStream, args model.ArchiveArgs) (model.Ar
 			dirObj.IsFolder = true
 			dirObj.Name = stdpath.Base(dir)
 			dirObj.Modified = file.ModTime()
+			dirObj.Children = make([]model.ObjTree, 0)
 		}
 		if isNewFolder {
 			// 将 文件夹 添加到 父文件夹
diff --git a/server/handles/archive.go b/server/handles/archive.go
index 6ff13641b44..fab3916e3ca 100644
--- a/server/handles/archive.go
+++ b/server/handles/archive.go
@@ -39,7 +39,7 @@ type ArchiveMetaResp struct {
 
 type ArchiveContentResp struct {
 	ObjResp
-	Children []ArchiveContentResp `json:"children,omitempty"`
+	Children []ArchiveContentResp `json:"children"`
 }
 
 func toObjsRespWithoutSignAndThumb(obj model.Obj) ObjResp {


Test patch: