From a9b85c0f3f96441944110ec098438bfc20c49c72 Mon Sep 17 00:00:00 2001 From: ShukeBta <272197458+ShukeBta@users.noreply.github.com> Date: Tue, 16 Jun 2026 02:20:27 +0800 Subject: [PATCH] Allow virtual media reference ids --- internal/database/database.go | 6 ++++++ internal/model/model.go | 10 ++++----- internal/model/model_test.go | 40 +++++++++++++++++++++++++++++++++++ internal/model/strm.go | 4 ++-- 4 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 internal/model/model_test.go diff --git a/internal/database/database.go b/internal/database/database.go index 00de091..4cb7fdd 100644 --- a/internal/database/database.go +++ b/internal/database/database.go @@ -662,6 +662,12 @@ func ensurePostgresColumnCompatibility(db *gorm.DB) error { statements := []string{ `ALTER TABLE media ALTER COLUMN container TYPE varchar(128)`, `ALTER TABLE media ALTER COLUMN genres TYPE text`, + `ALTER TABLE media ALTER COLUMN series_id TYPE varchar(128)`, + `ALTER TABLE media ALTER COLUMN duplicate_of TYPE varchar(128)`, + `ALTER TABLE playback_histories ALTER COLUMN media_id TYPE varchar(128)`, + `ALTER TABLE favorites ALTER COLUMN media_id TYPE varchar(128)`, + `ALTER TABLE playlist_items ALTER COLUMN media_id TYPE varchar(128)`, + `ALTER TABLE strm_records ALTER COLUMN media_id TYPE varchar(128)`, } for _, stmt := range statements { if err := db.Exec(stmt).Error; err != nil { diff --git a/internal/model/model.go b/internal/model/model.go index c7f0b9f..1b332b3 100644 --- a/internal/model/model.go +++ b/internal/model/model.go @@ -70,7 +70,7 @@ type Library struct { type Media struct { Base LibraryID string `gorm:"index;size:36" json:"library_id"` - SeriesID string `gorm:"index;size:36" json:"series_id,omitempty"` + SeriesID string `gorm:"index;size:128" json:"series_id,omitempty"` Title string `gorm:"size:255;not null" json:"title"` OriginalName string `gorm:"size:255" json:"original_name,omitempty"` Path string `gorm:"uniqueIndex;size:1024;not null" json:"path"` @@ -115,7 +115,7 @@ type Media struct { // IsDuplicate flags this media as a duplicate of another media row. IsDuplicate bool `gorm:"default:false" json:"is_duplicate"` - DuplicateOf string `gorm:"size:36" json:"duplicate_of,omitempty"` + DuplicateOf string `gorm:"size:128" json:"duplicate_of,omitempty"` } // APIConfig stores third-party data-source configuration. The api_key @@ -160,7 +160,7 @@ type Series struct { type PlaybackHistory struct { Base UserID string `gorm:"index;size:36;not null" json:"user_id"` - MediaID string `gorm:"index;size:36;not null" json:"media_id"` + MediaID string `gorm:"index;size:128;not null" json:"media_id"` PositionMs int64 `json:"position_ms"` DurationMs int64 `json:"duration_ms"` WatchedAt time.Time `json:"watched_at"` @@ -171,7 +171,7 @@ type PlaybackHistory struct { type Favorite struct { Base UserID string `gorm:"index;size:36;not null;uniqueIndex:uniq_user_media" json:"user_id"` - MediaID string `gorm:"index;size:36;not null;uniqueIndex:uniq_user_media" json:"media_id"` + MediaID string `gorm:"index;size:128;not null;uniqueIndex:uniq_user_media" json:"media_id"` } // Playlist 是用户策划的、有序的媒体列表。 @@ -186,7 +186,7 @@ type Playlist struct { type PlaylistItem struct { Base PlaylistID string `gorm:"index;size:36;not null" json:"playlist_id"` - MediaID string `gorm:"index;size:36;not null" json:"media_id"` + MediaID string `gorm:"index;size:128;not null" json:"media_id"` Position int `json:"position"` } diff --git a/internal/model/model_test.go b/internal/model/model_test.go new file mode 100644 index 0000000..922cda3 --- /dev/null +++ b/internal/model/model_test.go @@ -0,0 +1,40 @@ +package model + +import ( + "sync" + "testing" + + "gorm.io/gorm/schema" +) + +func TestMediaReferenceFieldsAllowVirtualEmbyIDs(t *testing.T) { + virtualIDLen := len("msgo-series-c003a8f345ea99aca9bb857591afd915") + cases := []struct { + name string + model any + fieldName string + }{ + {name: "media_series_id", model: &Media{}, fieldName: "SeriesID"}, + {name: "media_duplicate_of", model: &Media{}, fieldName: "DuplicateOf"}, + {name: "playback_history_media_id", model: &PlaybackHistory{}, fieldName: "MediaID"}, + {name: "favorite_media_id", model: &Favorite{}, fieldName: "MediaID"}, + {name: "playlist_item_media_id", model: &PlaylistItem{}, fieldName: "MediaID"}, + {name: "strm_record_media_id", model: &STRMRecord{}, fieldName: "MediaID"}, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + parsed, err := schema.Parse(tc.model, &sync.Map{}, schema.NamingStrategy{}) + if err != nil { + t.Fatal(err) + } + field := parsed.LookUpField(tc.fieldName) + if field == nil { + t.Fatalf("field %s not found", tc.fieldName) + } + if field.Size < virtualIDLen { + t.Fatalf("%s size = %d, want at least %d", tc.fieldName, field.Size, virtualIDLen) + } + }) + } +} diff --git a/internal/model/strm.go b/internal/model/strm.go index ffedeed..9629cc2 100644 --- a/internal/model/strm.go +++ b/internal/model/strm.go @@ -10,8 +10,8 @@ type STRMRecord struct { FilePath string `gorm:"size:1024;not null" json:"file_path"` // 本地 STRM 文件路径 Protocol string `gorm:"size:32;not null" json:"protocol"` // webdav / alist / s3 / http / https FileSize int64 `json:"file_size"` - MediaID string `gorm:"size:36;index" json:"media_id"` // 关联媒体 ID - MediaType string `gorm:"size:16" json:"media_type"` // movie / series + MediaID string `gorm:"size:128;index" json:"media_id"` // 关联媒体 ID + MediaType string `gorm:"size:16" json:"media_type"` // movie / series SeasonNum int `json:"season_num"` EpisodeNum int `json:"episode_num"` }