Ссылки на внешние базы в ревью (recognition)
Каждый кандидат внешней базы метаданных (TMDB/TVDB/TVMaze) теперь несёт URL на страницу элемента — при ревью можно кликнуть и проверить матч. URL формируется клиентом провайдера при поиске, сохраняется в БД (metadata_candidate.url) и отображается ссылкой в веб-интерфейсе. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -36,6 +36,7 @@ type Candidate struct {
|
||||
Title string
|
||||
OriginalTitle string
|
||||
Year int
|
||||
URL string // ссылка на страницу элемента на сайте провайдера
|
||||
TagProvider string // напр. "tvdb"/"imdb" (опц.)
|
||||
TagID string
|
||||
}
|
||||
|
||||
@@ -98,6 +98,10 @@ func (t *TMDB) Search(ctx context.Context, q Query) ([]Candidate, error) {
|
||||
return nil, fmt.Errorf("tmdb search: %w", err)
|
||||
}
|
||||
|
||||
webPath := "movie"
|
||||
if q.Type == Series {
|
||||
webPath = "tv"
|
||||
}
|
||||
out := make([]Candidate, 0, len(resp.Results))
|
||||
for _, r := range resp.Results {
|
||||
title, orig, date := r.Title, r.OriginalTitle, r.ReleaseDate
|
||||
@@ -110,6 +114,7 @@ func (t *TMDB) Search(ctx context.Context, q Query) ([]Candidate, error) {
|
||||
Title: title,
|
||||
OriginalTitle: orig,
|
||||
Year: yearOf(date),
|
||||
URL: "https://www.themoviedb.org/" + webPath + "/" + strconv.Itoa(r.ID),
|
||||
})
|
||||
}
|
||||
return out, nil
|
||||
|
||||
@@ -42,6 +42,9 @@ func TestTMDB_SearchMovie(t *testing.T) {
|
||||
if c.Provider != "tmdb" || c.ID != "603" || c.Title != "The Matrix" || c.Year != 1999 {
|
||||
t.Errorf("candidate = %+v", c)
|
||||
}
|
||||
if c.URL != "https://www.themoviedb.org/movie/603" {
|
||||
t.Errorf("URL = %q", c.URL)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTMDB_SearchSeries(t *testing.T) {
|
||||
@@ -65,6 +68,9 @@ func TestTMDB_SearchSeries(t *testing.T) {
|
||||
if len(got) != 1 || got[0].ID != "60622" || got[0].Title != "Fargo" || got[0].Year != 2014 {
|
||||
t.Errorf("candidate = %+v", got[0])
|
||||
}
|
||||
if got[0].URL != "https://www.themoviedb.org/tv/60622" {
|
||||
t.Errorf("URL = %q", got[0].URL)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTMDB_SeasonEpisodeCounts(t *testing.T) {
|
||||
|
||||
@@ -176,6 +176,7 @@ func (t *TVDB) Search(ctx context.Context, q Query) ([]Candidate, error) {
|
||||
ID: r.TVDBID,
|
||||
Title: r.Name,
|
||||
Year: year,
|
||||
URL: "https://www.thetvdb.com/dereferrer/series/" + r.TVDBID,
|
||||
})
|
||||
}
|
||||
return out, nil
|
||||
|
||||
@@ -71,6 +71,9 @@ func TestTVDB_SearchAndLoginCached(t *testing.T) {
|
||||
if len(got) != 1 || got[0].ID != "269613" || got[0].Provider != "tvdb" || got[0].Year != 2014 {
|
||||
t.Fatalf("candidate = %+v", got)
|
||||
}
|
||||
if got[0].URL != "https://www.thetvdb.com/dereferrer/series/269613" {
|
||||
t.Fatalf("URL = %q", got[0].URL)
|
||||
}
|
||||
// Второй запрос переиспользует токен — повторного логина нет.
|
||||
if _, err := c.Search(context.Background(), Query{Type: Series, Title: "Fargo"}); err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@@ -82,6 +82,7 @@ func (t *TVMaze) Search(ctx context.Context, q Query) ([]Candidate, error) {
|
||||
ID: strconv.Itoa(s.ID),
|
||||
Title: s.Name,
|
||||
Year: yearOf(s.Premiered),
|
||||
URL: "https://www.tvmaze.com/shows/" + strconv.Itoa(s.ID),
|
||||
}
|
||||
// Тег папки — привычный TVDB-id, если есть; иначе IMDb.
|
||||
switch {
|
||||
|
||||
@@ -41,6 +41,9 @@ func TestTVMaze_SearchSeries(t *testing.T) {
|
||||
if c.Provider != "tvmaze" || c.ID != "1" || c.Title != "Fargo" || c.Year != 2014 {
|
||||
t.Errorf("candidate = %+v", c)
|
||||
}
|
||||
if c.URL != "https://www.tvmaze.com/shows/1" {
|
||||
t.Errorf("URL = %q", c.URL)
|
||||
}
|
||||
// TVDB-id из externals → тег папки.
|
||||
if c.TagProvider != "tvdb" || c.TagID != "269613" {
|
||||
t.Errorf("tag = %s/%s, want tvdb/269613", c.TagProvider, c.TagID)
|
||||
|
||||
Reference in New Issue
Block a user