fix: align scraped media naming and release sorting

This commit is contained in:
ShukeBta
2026-07-03 02:55:33 +08:00
parent 78de029ef3
commit b610dda098
48 changed files with 544 additions and 42 deletions
+6 -5
View File
@@ -103,12 +103,13 @@ func (r *MediaRepository) ListByLibrariesFiltered(ctx context.Context, libraryID
return nil, 0, err
}
// 多级排序消除"随机"观感:
// 1. year desc — 上映年份新→旧(用户期望的上映时间维度)
// 2. updated_at desc — 同年按最近更新(刮削/补集会刷新)
// 3. created_at desc — 再按入库时间
// 4. id desc — 稳定 tie-breaker:云盘批量扫描同批 created_at 相同时,
// 1. release_date desc — 精确上映/首播日期新→旧
// 2. year desc — 老数据没有完整日期时仍按年份新→旧
// 3. updated_at desc — 同日期/同年按最近更新兜底
// 4. created_at desc — 再按入库时间
// 5. id desc — 稳定 tie-breaker:云盘批量扫描同批 created_at 相同时,
// 没有它 DB 返回顺序不确定,正是"随机排序"的根因。
err := q.Order("year DESC, updated_at DESC, created_at DESC, id DESC").
err := q.Order("release_date DESC, year DESC, updated_at DESC, created_at DESC, id DESC").
Offset(offset).Limit(limit).Find(&items).Error
return items, total, err
}
@@ -103,6 +103,9 @@ func addMediaTitleUpdates(updates map[string]any, existing, incoming model.Media
if incoming.Year > 0 {
setIfChanged(updates, "year", existing.Year, incoming.Year)
}
if incoming.ReleaseDate != "" {
setIfChanged(updates, "release_date", existing.ReleaseDate, incoming.ReleaseDate)
}
if strings.TrimSpace(existing.ScrapeStatus) == "no_match" && incoming.ScrapeStatus != "matched" && (titleChanged || yearChanged) {
updates["scrape_status"] = "pending"
}
@@ -119,6 +122,9 @@ func addMediaExternalIDUpdates(updates map[string]any, existing, incoming model.
if incoming.Year > 0 && existing.Year <= 0 {
updates["year"] = incoming.Year
}
if incoming.ReleaseDate != "" && existing.ReleaseDate == "" {
updates["release_date"] = incoming.ReleaseDate
}
if changedExternalID && (status == "no_match" || status == "matched") && incoming.ScrapeStatus != "matched" {
updates["scrape_status"] = "pending"
}
@@ -152,6 +158,9 @@ func addMatchedMediaDetailUpdates(updates map[string]any, existing, incoming mod
if incoming.Year > 0 {
setIfChanged(updates, "year", existing.Year, incoming.Year)
}
if incoming.ReleaseDate != "" {
setIfChanged(updates, "release_date", existing.ReleaseDate, incoming.ReleaseDate)
}
if incoming.NSFW && !existing.NSFW {
updates["nsfw"] = true
}
+36
View File
@@ -186,6 +186,42 @@ func TestMediaUpsertMatchedIncomingRefreshesScrapedMetadata(t *testing.T) {
}
}
func TestListByLibraryOrdersByReleaseDate(t *testing.T) {
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
if err != nil {
t.Fatal(err)
}
if err := database.AutoMigrate(db); err != nil {
t.Fatalf("migrate: %v", err)
}
repos := New(db)
lib := model.Library{Name: "国产剧", Path: "/media/tv", Type: "tv", Enabled: true}
if err := repos.Library.Create(t.Context(), &lib); err != nil {
t.Fatal(err)
}
rows := []model.Media{
{LibraryID: lib.ID, Title: "旧片但最近更新", Path: "/media/tv/old.mkv", Year: 2026, ReleaseDate: "2026-01-10", ScrapeStatus: "matched"},
{LibraryID: lib.ID, Title: "最新首播", Path: "/media/tv/newest.mkv", Year: 2026, ReleaseDate: "2026-06-23", ScrapeStatus: "matched"},
{LibraryID: lib.ID, Title: "无完整日期", Path: "/media/tv/year-only.mkv", Year: 2025, ScrapeStatus: "matched"},
}
for i := range rows {
if err := repos.Media.Upsert(t.Context(), &rows[i]); err != nil {
t.Fatal(err)
}
}
items, total, err := repos.Media.ListByLibrary(t.Context(), lib.ID, 0, 10)
if err != nil {
t.Fatal(err)
}
if total != 3 || len(items) != 3 {
t.Fatalf("list total=%d len=%d", total, len(items))
}
if got := []string{items[0].Title, items[1].Title, items[2].Title}; got[0] != "最新首播" || got[1] != "旧片但最近更新" || got[2] != "无完整日期" {
t.Fatalf("release-date order = %#v", got)
}
}
func TestMediaUpsertScanDoesNotClearMatchedMetadata(t *testing.T) {
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
if err != nil {