添加繁体转简体,简体转繁体功能

This commit is contained in:
truewhile
2026-09-11 15:14:24 +08:00
parent 9ca1b28cb4
commit 2bb3610da7
11 changed files with 268 additions and 10 deletions
+3
View File
@@ -28,6 +28,9 @@ type User struct {
// PinnedLibraryIDs 存储用户置顶的媒体库 ID 列表(JSON 字符串),顺序即置顶优先级。
PinnedLibraryIDs string `gorm:"type:text" json:"-"`
PinnedLibraryList []string `gorm:"-" json:"pinned_library_ids,omitempty"`
// SubtitleChineseMode 是网页播放器外挂字幕的简繁转换偏好:
// original / simplified / traditional。
SubtitleChineseMode string `gorm:"size:16;not null;default:original" json:"subtitle_chinese_mode"`
// ExpiredAt is the account expiry time. Nil means the account never
// expires. When set and in the past, the account is treated as expired
// (login blocked) until an admin or a redemption code renews it.
+16 -6
View File
@@ -27,12 +27,13 @@ func NewProfileService(log *zap.Logger, repo *repository.Container) *ProfileServ
// ProfileUpdate is the patch object accepted by UpdateProfile. Empty
// fields are ignored so the same payload can be reused across screens.
type ProfileUpdate struct {
Username *string `json:"username,omitempty"`
Nickname *string `json:"nickname,omitempty"`
Email *string `json:"email,omitempty"`
AvatarURL *string `json:"avatar_url,omitempty"`
HideAdult *bool `json:"hide_adult,omitempty"`
Password string `json:"password,omitempty"`
Username *string `json:"username,omitempty"`
Nickname *string `json:"nickname,omitempty"`
Email *string `json:"email,omitempty"`
AvatarURL *string `json:"avatar_url,omitempty"`
HideAdult *bool `json:"hide_adult,omitempty"`
SubtitleChineseMode *string `json:"subtitle_chinese_mode,omitempty"`
Password string `json:"password,omitempty"`
}
// UpdateProfile applies a non-credential patch to the user.
@@ -73,6 +74,15 @@ func (p *ProfileService) UpdateProfile(ctx context.Context, userID string, patch
if patch.HideAdult != nil {
updates["hide_adult"] = *patch.HideAdult
}
if patch.SubtitleChineseMode != nil {
mode := strings.ToLower(strings.TrimSpace(*patch.SubtitleChineseMode))
switch mode {
case "original", "simplified", "traditional":
updates["subtitle_chinese_mode"] = mode
default:
return nil, errors.New("subtitle_chinese_mode must be original, simplified, or traditional")
}
}
if len(updates) > 0 {
if err := p.repo.DB.Model(&model.User{}).Where("id = ?", userID).
Updates(updates).Error; err != nil {
+60
View File
@@ -0,0 +1,60 @@
package service
import (
"testing"
"github.com/glebarez/sqlite"
"go.uber.org/zap"
"gorm.io/gorm"
"github.com/truewhile/MeBox/internal/model"
"github.com/truewhile/MeBox/internal/repository"
)
func TestProfileSubtitleChineseModePersistsAndValidates(t *testing.T) {
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
if err != nil {
t.Fatal(err)
}
if err := db.AutoMigrate(&model.User{}); err != nil {
t.Fatal(err)
}
repos := repository.New(db)
svc := NewProfileService(zap.NewNop(), repos)
user := &model.User{
Username: "subtitle-viewer",
PasswordHash: "hash",
Role: "user",
IsActive: true,
}
if err := repos.User.Create(t.Context(), user); err != nil {
t.Fatal(err)
}
traditional := "traditional"
updated, err := svc.UpdateProfile(t.Context(), user.ID, ProfileUpdate{
SubtitleChineseMode: &traditional,
})
if err != nil {
t.Fatal(err)
}
if updated.SubtitleChineseMode != traditional {
t.Fatalf("subtitle mode = %q, want %q", updated.SubtitleChineseMode, traditional)
}
invalid := "automatic"
if _, err := svc.UpdateProfile(t.Context(), user.ID, ProfileUpdate{
SubtitleChineseMode: &invalid,
}); err == nil {
t.Fatal("invalid subtitle mode should be rejected")
}
reloaded, err := repos.User.FindByID(t.Context(), user.ID)
if err != nil {
t.Fatal(err)
}
if reloaded.SubtitleChineseMode != traditional {
t.Fatalf("invalid update changed subtitle mode to %q", reloaded.SubtitleChineseMode)
}
}