迁移 TheIntroDB 接口到 v4

v1 已删除、v2/v3 已弃用,仅保留只读的 GET /media。本次把 base URL 切到 v4,并适配响应以 tvdb_id 为身份(tmdb_id 字段已移除)。请求仍用 tmdb_id 寻址,v4 仍接受并由服务端解析季集映射。
This commit is contained in:
truewhile
2026-10-19 22:23:06 +08:00
parent f1974a179e
commit 90bfac3b09
2 changed files with 15 additions and 11 deletions
+6 -3
View File
@@ -22,8 +22,9 @@ import (
const ( const (
// IntroDBBaseURL is the public read endpoint. Overridable on the service // IntroDBBaseURL is the public read endpoint. Overridable on the service
// for tests and for pointing at a mirror. // for tests and for pointing at a mirror. v1 已删除,v2/v3 冻结在只读的
IntroDBBaseURL = "https://api.theintrodb.org/v3" // GET /media 上并被官方标记为弃用,所以这里直接跟 v4。
IntroDBBaseURL = "https://api.theintrodb.org/v4"
// IntroDBSource tags rows that came from this provider. // IntroDBSource tags rows that came from this provider.
IntroDBSource = "theintrodb" IntroDBSource = "theintrodb"
@@ -92,8 +93,10 @@ type introDBRange struct {
EndMs *int64 `json:"end_ms"` EndMs *int64 `json:"end_ms"`
} }
// introDBResponse 对应 v4 的 MediaResponse。v4 以 TVDB 为身份,响应只带
// tvdb_id —— tmdb_id 字段已被官方移除,需要 tmdb_id 只能从请求侧自己记。
type introDBResponse struct { type introDBResponse struct {
TMDbID int `json:"tmdb_id"` TVDBID int `json:"tvdb_id"`
Type string `json:"type"` Type string `json:"type"`
Intro []introDBRange `json:"intro"` Intro []introDBRange `json:"intro"`
Recap []introDBRange `json:"recap"` Recap []introDBRange `json:"recap"`
+9 -8
View File
@@ -11,11 +11,12 @@ import (
"go.uber.org/zap" "go.uber.org/zap"
) )
// 这两段响应是从 api.theintrodb.org/v3/media 实测抓下来的原文, // 这两段响应是从 api.theintrodb.org/v4/media 实测抓下来的原文(v4 以 TVDB 为身份,
// 用来锁住 null 语义:start_ms: null = 从片头开始,end_ms: null = 一直到片尾。 // 响应里只有 tvdb_id),用来锁住 null 语义:start_ms: null = 从片头开始,
// end_ms: null = 一直到片尾。
const ( const (
introDBTVPayload = `{"tmdb_id":1396,"type":"tv","season":1,"episode":1,"intro":[{"start_ms":228664,"end_ms":246143}],"credits":[{"start_ms":3431000,"end_ms":null}]}` introDBTVPayload = `{"tvdb_id":81189,"type":"tv","season":1,"episode":1,"intro":[{"start_ms":228664,"end_ms":246143}],"credits":[{"start_ms":3431000,"end_ms":null}]}`
introDBMoviePayload = `{"tmdb_id":27205,"type":"movie","intro":[{"start_ms":null,"end_ms":38000}]}` introDBMoviePayload = `{"tvdb_id":113,"type":"movie","intro":[{"start_ms":null,"end_ms":38000}]}`
) )
func TestParseIntroDBResponseResolvesNullBounds(t *testing.T) { func TestParseIntroDBResponseResolvesNullBounds(t *testing.T) {
@@ -48,7 +49,7 @@ func TestParseIntroDBResponseResolvesNullBounds(t *testing.T) {
} }
func TestParseIntroDBResponseDropsEmptyRanges(t *testing.T) { func TestParseIntroDBResponseDropsEmptyRanges(t *testing.T) {
body := `{"tmdb_id":1,"type":"movie", body := `{"tvdb_id":1,"type":"movie",
"intro":[{"start_ms":5000,"end_ms":5000},{"start_ms":9000,"end_ms":8000},{"start_ms":1000,"end_ms":2000}], "intro":[{"start_ms":5000,"end_ms":5000},{"start_ms":9000,"end_ms":8000},{"start_ms":1000,"end_ms":2000}],
"recap":[],"credits":[],"preview":[]}` "recap":[],"credits":[],"preview":[]}`
spans, err := parseIntroDBResponse([]byte(body)) spans, err := parseIntroDBResponse([]byte(body))
@@ -62,7 +63,7 @@ func TestParseIntroDBResponseDropsEmptyRanges(t *testing.T) {
} }
func TestParseIntroDBResponseOrdersByType(t *testing.T) { func TestParseIntroDBResponseOrdersByType(t *testing.T) {
body := `{"tmdb_id":1,"type":"tv","credits":[{"start_ms":900,"end_ms":1000}], body := `{"tvdb_id":1,"type":"tv","credits":[{"start_ms":900,"end_ms":1000}],
"intro":[{"start_ms":100,"end_ms":200}],"recap":[{"start_ms":50,"end_ms":60}]}` "intro":[{"start_ms":100,"end_ms":200}],"recap":[{"start_ms":50,"end_ms":60}]}`
spans, err := parseIntroDBResponse([]byte(body)) spans, err := parseIntroDBResponse([]byte(body))
if err != nil { if err != nil {
@@ -82,12 +83,12 @@ func TestParseIntroDBResponseOrdersByType(t *testing.T) {
func TestIntroDBMediaURLOnlyAddsSeasonEpisodeForTV(t *testing.T) { func TestIntroDBMediaURLOnlyAddsSeasonEpisodeForTV(t *testing.T) {
svc := NewIntroDBService(zap.NewNop()) svc := NewIntroDBService(zap.NewNop())
if got, want := svc.mediaURL(1396, 1, 1), if got, want := svc.mediaURL(1396, 1, 1),
"https://api.theintrodb.org/v3/media?tmdb_id=1396&season=1&episode=1"; got != want { "https://api.theintrodb.org/v4/media?tmdb_id=1396&season=1&episode=1"; got != want {
t.Fatalf("tv url = %q, want %q", got, want) t.Fatalf("tv url = %q, want %q", got, want)
} }
// 电影(season/episode 为 0)不能带季集参数,否则会被当成剧集查不到。 // 电影(season/episode 为 0)不能带季集参数,否则会被当成剧集查不到。
if got, want := svc.mediaURL(27205, 0, 0), if got, want := svc.mediaURL(27205, 0, 0),
"https://api.theintrodb.org/v3/media?tmdb_id=27205"; got != want { "https://api.theintrodb.org/v4/media?tmdb_id=27205"; got != want {
t.Fatalf("movie url = %q, want %q", got, want) t.Fatalf("movie url = %q, want %q", got, want)
} }
} }