mirror of
https://github.com/truewhile/MeBox.git
synced 2026-09-28 11:16:37 +08:00
优化
This commit is contained in:
@@ -9,6 +9,7 @@ import (
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
@@ -180,6 +181,7 @@ func (p *AdultProvider) SearchCandidates(ctx context.Context, query string) ([]*
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
matches = p.enrichMetaTubeCandidates(ctx, mtCfg, code, matches)
|
||||
for _, m := range matches {
|
||||
m.OriginalName = code
|
||||
m.Title = FormatAdultTitle(code, m.Title)
|
||||
@@ -194,6 +196,7 @@ func (p *AdultProvider) SearchCandidates(ctx context.Context, query string) ([]*
|
||||
if mtCfg.ServerURL != "" {
|
||||
matches, err := p.metatube.Search(ctx, mtCfg, code)
|
||||
if err == nil && len(matches) > 0 {
|
||||
matches = p.enrichMetaTubeCandidates(ctx, mtCfg, code, matches)
|
||||
for _, m := range matches {
|
||||
m.OriginalName = code
|
||||
m.Title = FormatAdultTitle(code, m.Title)
|
||||
@@ -217,6 +220,50 @@ func (p *AdultProvider) SearchCandidates(ctx context.Context, query string) ([]*
|
||||
}
|
||||
}
|
||||
|
||||
// GetMetaTubeCandidate fetches the selected provider result instead of
|
||||
// re-running a search that may choose a different provider.
|
||||
func (p *AdultProvider) GetMetaTubeCandidate(ctx context.Context, provider, id string) (*Match, error) {
|
||||
if p == nil || p.metatube == nil {
|
||||
return nil, nil
|
||||
}
|
||||
provider = strings.TrimSpace(provider)
|
||||
id = strings.TrimSpace(id)
|
||||
if provider == "" || id == "" {
|
||||
return nil, nil
|
||||
}
|
||||
engine := strings.ToLower(p.getSetting(ctx, "adult.scraper.engine", "builtin"))
|
||||
if engine != "metatube" && engine != "auto" {
|
||||
return nil, nil
|
||||
}
|
||||
cfg := p.ResolveMetaTubeConfig(ctx)
|
||||
if cfg.ServerURL == "" {
|
||||
return nil, nil
|
||||
}
|
||||
return p.metatube.GetMovie(ctx, cfg, provider, id)
|
||||
}
|
||||
|
||||
func (p *AdultProvider) enrichMetaTubeCandidates(ctx context.Context, cfg MetaTubeConfig, code string, matches []*Match) []*Match {
|
||||
var wg sync.WaitGroup
|
||||
for i, candidate := range matches {
|
||||
if candidate == nil ||
|
||||
normalizeAdultCode(candidate.OriginalName) != code ||
|
||||
strings.TrimSpace(candidate.DoubanID) == "" ||
|
||||
strings.TrimSpace(candidate.TheTVDBID) == "" {
|
||||
continue
|
||||
}
|
||||
wg.Add(1)
|
||||
go func(index int, current *Match) {
|
||||
defer wg.Done()
|
||||
detailed, err := p.metatube.GetMovie(ctx, cfg, current.TheTVDBID, current.DoubanID)
|
||||
if err == nil && detailed != nil {
|
||||
matches[index] = detailed
|
||||
}
|
||||
}(i, candidate)
|
||||
}
|
||||
wg.Wait()
|
||||
return matches
|
||||
}
|
||||
|
||||
func (p *AdultProvider) searchBuiltin(ctx context.Context, code string) (*Match, error) {
|
||||
bases := p.resolveBases(ctx)
|
||||
if len(bases) == 0 {
|
||||
|
||||
@@ -25,7 +25,8 @@ func TestAdultProviderRouting(t *testing.T) {
|
||||
repos := repository.New(db)
|
||||
|
||||
mtServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path == "/v1/movies/search" {
|
||||
switch r.URL.Path {
|
||||
case "/v1/movies/search":
|
||||
q := r.URL.Query().Get("q")
|
||||
if q == "SSIS-001" {
|
||||
results := struct {
|
||||
@@ -46,6 +47,21 @@ func TestAdultProviderRouting(t *testing.T) {
|
||||
_ = json.NewEncoder(w).Encode(results)
|
||||
return
|
||||
}
|
||||
case "/v1/movies/javdb/999":
|
||||
_ = json.NewEncoder(w).Encode(struct {
|
||||
Data MetaTubeMovieInfo `json:"data"`
|
||||
}{
|
||||
Data: MetaTubeMovieInfo{
|
||||
ID: "999",
|
||||
Number: "SSIS-001",
|
||||
Title: "河北彩花 専属デビュー",
|
||||
Provider: "javdb",
|
||||
CoverURL: "https://example.com/poster.jpg",
|
||||
PreviewImages: []string{"https://example.com/backdrop.jpg"},
|
||||
ReleaseDate: "2021-06-19",
|
||||
},
|
||||
})
|
||||
return
|
||||
}
|
||||
http.NotFound(w, r)
|
||||
}))
|
||||
@@ -80,6 +96,10 @@ func TestAdultProviderRouting(t *testing.T) {
|
||||
if len(candidates) != 1 {
|
||||
t.Fatalf("expected 1 candidate, got %d", len(candidates))
|
||||
}
|
||||
if candidates[0].PosterURL != "https://example.com/poster.jpg" ||
|
||||
candidates[0].BackdropURL != "https://example.com/backdrop.jpg" {
|
||||
t.Fatalf("candidate artwork was not enriched: %#v", candidates[0])
|
||||
}
|
||||
|
||||
// 2. Test auto mode with failing metatube query
|
||||
_ = repos.Setting.Set(context.Background(), "adult.scraper.engine", "auto")
|
||||
|
||||
@@ -127,7 +127,21 @@ func (s *ScraperService) manualRequestMatch(ctx context.Context, req ManualScrap
|
||||
}
|
||||
}
|
||||
case source == "adult":
|
||||
if match := s.manualAdultMatch(ctx, firstText(req.OriginalName, req.Title)); match != nil {
|
||||
var match *Match
|
||||
if s.adult != nil {
|
||||
match, _ = s.adult.GetMetaTubeCandidate(ctx, req.TheTVDBID, req.DoubanID)
|
||||
}
|
||||
if match == nil {
|
||||
match = s.manualAdultMatch(ctx, firstText(req.OriginalName, req.Title))
|
||||
}
|
||||
if match != nil {
|
||||
// Older search responses used the portrait poster as a backdrop
|
||||
// fallback. Do not let that placeholder replace a real preview
|
||||
// image fetched from the selected MetaTube provider.
|
||||
if strings.TrimSpace(match.BackdropURL) != "" &&
|
||||
strings.TrimSpace(req.BackdropURL) == strings.TrimSpace(req.PosterURL) {
|
||||
req.BackdropURL = ""
|
||||
}
|
||||
return mergeManualRequestIntoMatch(match, req), nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,72 @@ func TestManualRequestMatchFallsBackToCandidatePayload(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestManualAdultMatchUsesSelectedMetaTubeDetailsAndRealBackdrop(t *testing.T) {
|
||||
var detailCalls atomic.Int32
|
||||
upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path != "/v1/movies/AVE/94600" {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
detailCalls.Add(1)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_ = json.NewEncoder(w).Encode(struct {
|
||||
Data MetaTubeMovieInfo `json:"data"`
|
||||
}{
|
||||
Data: MetaTubeMovieInfo{
|
||||
ID: "94600",
|
||||
Number: "CWPBD-138",
|
||||
Title: "Selected title",
|
||||
Provider: "AVE",
|
||||
CoverURL: "https://example.com/poster.jpg",
|
||||
PreviewImages: []string{"https://example.com/backdrop.jpg"},
|
||||
},
|
||||
})
|
||||
}))
|
||||
defer upstream.Close()
|
||||
|
||||
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := db.AutoMigrate(&model.Setting{}, &model.APIConfig{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
repos := repository.New(db)
|
||||
if err := repos.Setting.Set(t.Context(), "adult.scraper.engine", "metatube"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := repos.Setting.Set(t.Context(), "adult.scraper.metatube_server", upstream.URL); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
adult := NewAdultProvider(zap.NewNop(), nil, repos)
|
||||
scraper := &ScraperService{adult: adult}
|
||||
|
||||
match, err := scraper.manualRequestMatch(t.Context(), ManualScrapeRequest{
|
||||
Source: "adult",
|
||||
MediaType: "adult",
|
||||
Title: "CWPBD-138 Selected title",
|
||||
OriginalName: "CWPBD-138",
|
||||
PosterURL: "https://example.com/search-cover.jpg",
|
||||
BackdropURL: "https://example.com/search-cover.jpg",
|
||||
DoubanID: "94600",
|
||||
TheTVDBID: "AVE",
|
||||
NSFW: true,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if detailCalls.Load() != 1 {
|
||||
t.Fatalf("selected MetaTube detail calls = %d, want 1", detailCalls.Load())
|
||||
}
|
||||
if match.PosterURL != "https://example.com/search-cover.jpg" {
|
||||
t.Fatalf("selected poster = %q", match.PosterURL)
|
||||
}
|
||||
if match.BackdropURL != "https://example.com/backdrop.jpg" {
|
||||
t.Fatalf("backdrop = %q, want detail preview", match.BackdropURL)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParsePositiveIDStringAcceptsProviderPrefixes(t *testing.T) {
|
||||
cases := map[string]string{
|
||||
"12345": "12345",
|
||||
|
||||
Reference in New Issue
Block a user