mirror of
https://github.com/truewhile/MeBox.git
synced 2026-10-14 00:56:37 +08:00
优化
This commit is contained in:
@@ -9,6 +9,7 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
@@ -180,6 +181,7 @@ func (p *AdultProvider) SearchCandidates(ctx context.Context, query string) ([]*
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
matches = p.enrichMetaTubeCandidates(ctx, mtCfg, code, matches)
|
||||||
for _, m := range matches {
|
for _, m := range matches {
|
||||||
m.OriginalName = code
|
m.OriginalName = code
|
||||||
m.Title = FormatAdultTitle(code, m.Title)
|
m.Title = FormatAdultTitle(code, m.Title)
|
||||||
@@ -194,6 +196,7 @@ func (p *AdultProvider) SearchCandidates(ctx context.Context, query string) ([]*
|
|||||||
if mtCfg.ServerURL != "" {
|
if mtCfg.ServerURL != "" {
|
||||||
matches, err := p.metatube.Search(ctx, mtCfg, code)
|
matches, err := p.metatube.Search(ctx, mtCfg, code)
|
||||||
if err == nil && len(matches) > 0 {
|
if err == nil && len(matches) > 0 {
|
||||||
|
matches = p.enrichMetaTubeCandidates(ctx, mtCfg, code, matches)
|
||||||
for _, m := range matches {
|
for _, m := range matches {
|
||||||
m.OriginalName = code
|
m.OriginalName = code
|
||||||
m.Title = FormatAdultTitle(code, m.Title)
|
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) {
|
func (p *AdultProvider) searchBuiltin(ctx context.Context, code string) (*Match, error) {
|
||||||
bases := p.resolveBases(ctx)
|
bases := p.resolveBases(ctx)
|
||||||
if len(bases) == 0 {
|
if len(bases) == 0 {
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ func TestAdultProviderRouting(t *testing.T) {
|
|||||||
repos := repository.New(db)
|
repos := repository.New(db)
|
||||||
|
|
||||||
mtServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
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")
|
q := r.URL.Query().Get("q")
|
||||||
if q == "SSIS-001" {
|
if q == "SSIS-001" {
|
||||||
results := struct {
|
results := struct {
|
||||||
@@ -46,6 +47,21 @@ func TestAdultProviderRouting(t *testing.T) {
|
|||||||
_ = json.NewEncoder(w).Encode(results)
|
_ = json.NewEncoder(w).Encode(results)
|
||||||
return
|
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)
|
http.NotFound(w, r)
|
||||||
}))
|
}))
|
||||||
@@ -80,6 +96,10 @@ func TestAdultProviderRouting(t *testing.T) {
|
|||||||
if len(candidates) != 1 {
|
if len(candidates) != 1 {
|
||||||
t.Fatalf("expected 1 candidate, got %d", len(candidates))
|
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
|
// 2. Test auto mode with failing metatube query
|
||||||
_ = repos.Setting.Set(context.Background(), "adult.scraper.engine", "auto")
|
_ = 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":
|
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
|
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) {
|
func TestParsePositiveIDStringAcceptsProviderPrefixes(t *testing.T) {
|
||||||
cases := map[string]string{
|
cases := map[string]string{
|
||||||
"12345": "12345",
|
"12345": "12345",
|
||||||
|
|||||||
Reference in New Issue
Block a user