Files
MeBox/internal/service/scraper_episode_details_test.go
T

211 lines
6.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package service
import (
"encoding/json"
"net/http"
"net/http/httptest"
"path/filepath"
"strings"
"sync"
"testing"
"github.com/glebarez/sqlite"
"go.uber.org/zap"
"gorm.io/gorm"
"github.com/ShukeBta/MediaStationGo/internal/config"
"github.com/ShukeBta/MediaStationGo/internal/model"
"github.com/ShukeBta/MediaStationGo/internal/repository"
)
func TestEnrichLibraryDefersEpisodeDetailsUntilMainMetadataFinishes(t *testing.T) {
var mu sync.Mutex
paths := []string{}
upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
mu.Lock()
paths = append(paths, r.URL.Path)
mu.Unlock()
w.Header().Set("Content-Type", "application/json")
switch {
case strings.HasPrefix(r.URL.Path, "/search/tv"):
_ = json.NewEncoder(w).Encode(map[string]any{
"results": []map[string]any{{
"id": 12345,
"name": "间谍过家家",
"original_name": "SPY×FAMILY",
"overview": "测试简介",
"poster_path": "/poster.jpg",
"backdrop_path": "/backdrop.jpg",
"first_air_date": "2022-04-09",
"vote_average": 8.6,
}},
})
case r.URL.Path == "/tv/12345/season/2/episode/1":
_ = json.NewEncoder(w).Encode(map[string]any{
"name": "任务代号: 猫",
"overview": "第一集剧情",
"still_path": "/still-1.jpg",
"vote_average": 8.9,
"runtime": 24,
})
case r.URL.Path == "/tv/12345/season/2/episode/2":
_ = json.NewEncoder(w).Encode(map[string]any{
"name": "接近目标",
"overview": "第二集剧情",
"still_path": "/still-2.jpg",
"vote_average": 9.0,
"runtime": 25,
})
case r.URL.Path == "/tv/12345":
_ = json.NewEncoder(w).Encode(map[string]any{
"id": 12345,
"name": "间谍过家家",
"overview": "测试简介",
"poster_path": "/poster.jpg",
"backdrop_path": "/backdrop.jpg",
"first_air_date": "2022-04-09",
"vote_average": 8.6,
"origin_country": []string{"JP"},
"spoken_languages": []map[string]any{{
"iso_639_1": "ja",
}},
"genres": []map[string]any{{
"name": "Animation",
}},
})
default:
http.NotFound(w, r)
}
}))
defer upstream.Close()
db, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"), &gorm.Config{})
if err != nil {
t.Fatal(err)
}
if err := db.AutoMigrate(&model.Library{}, &model.Series{}, &model.Media{}); err != nil {
t.Fatal(err)
}
repos := repository.New(db)
cfg := &config.Config{}
cfg.Secrets.TMDbAPIKey = "test-key"
cfg.Secrets.TMDbAPIProxy = upstream.URL
cfg.Secrets.TMDbImageProxy = upstream.URL + "/images"
log := zap.NewNop()
scraper := NewScraperService(cfg, log, repos, NewTMDbProvider(cfg, log, nil), nil, nil, nil, NewHub(log))
lib := model.Library{Name: "番剧", Path: t.TempDir(), Type: "tv", Enabled: true}
if err := repos.DB.Create(&lib).Error; err != nil {
t.Fatal(err)
}
rows := []model.Media{
{
Base: model.Base{ID: "episode-1"},
LibraryID: lib.ID,
Title: "间谍过家家",
Path: filepath.Join(lib.Path, "间谍过家家 - S02E01.mkv"),
SeasonNum: 2,
EpisodeNum: 1,
ScrapeStatus: "pending",
},
{
Base: model.Base{ID: "episode-2"},
LibraryID: lib.ID,
Title: "间谍过家家",
Path: filepath.Join(lib.Path, "间谍过家家 - S02E02.mkv"),
SeasonNum: 2,
EpisodeNum: 2,
ScrapeStatus: "pending",
},
}
if err := repos.DB.Create(&rows).Error; err != nil {
t.Fatal(err)
}
result, err := scraper.EnrichLibraryDetailed(t.Context(), lib.ID, true)
if err != nil {
t.Fatal(err)
}
if result.Processed != 2 || result.Matched != 2 {
t.Fatalf("result=%+v, want two matched episodes", result)
}
mu.Lock()
gotPaths := append([]string(nil), paths...)
mu.Unlock()
firstEpisodeDetail := firstIndexFunc(gotPaths, func(path string) bool {
return strings.Contains(path, "/season/")
})
lastMainMetadata := lastIndexFunc(gotPaths, func(path string) bool {
return strings.HasPrefix(path, "/search/tv") || path == "/tv/12345"
})
if firstEpisodeDetail < 0 {
t.Fatalf("no deferred episode detail requests recorded: %v", gotPaths)
}
if firstEpisodeDetail <= lastMainMetadata {
t.Fatalf("episode detail ran before main metadata finished: paths=%v", gotPaths)
}
var stored []model.Media
if err := repos.DB.Where("library_id = ?", lib.ID).Order("episode_num ASC").Find(&stored).Error; err != nil {
t.Fatal(err)
}
if len(stored) != 2 || stored[0].Overview != "第一集剧情" || stored[1].Overview != "第二集剧情" {
t.Fatalf("deferred episode metadata not saved: %+v", stored)
}
if stored[0].EpisodeTitle != "任务代号: 猫" || stored[1].EpisodeTitle != "接近目标" {
t.Fatalf("deferred episode titles not saved: %+v", stored)
}
if stored[0].OriginalName != "SPY×FAMILY" || stored[1].OriginalName != "SPY×FAMILY" {
t.Fatalf("series original_name should stay shared: %+v", stored)
}
}
func TestEnrichLibrarySkipsDeferredEpisodeStillWhenDisabled(t *testing.T) {
scraper, repos, closeServer := newTestScraper(t)
defer closeServer()
lib := model.Library{Name: "番剧", Path: t.TempDir(), Type: "tv", Enabled: true}
if err := repos.DB.Create(&lib).Error; err != nil {
t.Fatal(err)
}
media := model.Media{
LibraryID: lib.ID,
Title: "间谍过家家",
Path: filepath.Join(lib.Path, "间谍过家家 - S02E01.mkv"),
SeasonNum: 2,
EpisodeNum: 1,
ScrapeStatus: "pending",
}
if err := repos.DB.Create(&media).Error; err != nil {
t.Fatal(err)
}
episodeArtwork := false
result, err := scraper.EnrichLibraryDetailedWithOptions(t.Context(), lib.ID, ScrapeOptions{
RetryNoMatch: true,
EpisodeArtwork: &episodeArtwork,
})
if err != nil {
t.Fatal(err)
}
if result.Processed != 1 || result.Matched != 1 {
t.Fatalf("result=%+v, want one matched episode", result)
}
var got model.Media
if err := repos.DB.First(&got, "id = ?", media.ID).Error; err != nil {
t.Fatal(err)
}
if got.Overview != "单集剧情" || got.DurationSec != 24*60 {
t.Fatalf("deferred episode text metadata should still be saved: overview=%q duration=%d", got.Overview, got.DurationSec)
}
if strings.HasSuffix(got.BackdropURL, "/images/w500/still.jpg") {
t.Fatalf("deferred episode still should not be saved when disabled: backdrop=%q", got.BackdropURL)
}
if !strings.HasSuffix(got.BackdropURL, "/images/w1280/backdrop.jpg") {
t.Fatalf("series backdrop should remain available when episode still is disabled: got %q", got.BackdropURL)
}
}