100 lines
2.9 KiB
Go
100 lines
2.9 KiB
Go
package tver
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"regexp"
|
|
)
|
|
|
|
var tverSeriesIDPattern = regexp.MustCompile(`^[A-Za-z0-9]+$`)
|
|
|
|
type seriesContents struct {
|
|
Code int `json:"code"`
|
|
Result struct {
|
|
Contents []struct {
|
|
Type string `json:"type"`
|
|
Content Episode `json:"content"`
|
|
} `json:"contents"`
|
|
} `json:"result"`
|
|
}
|
|
|
|
func (c *Client) FetchSeriesEpisodes(ctx context.Context, seriesID string) ([]Episode, error) {
|
|
if !tverSeriesIDPattern.MatchString(seriesID) {
|
|
return nil, errors.New("invalid series id")
|
|
}
|
|
seasonsURL := c.serviceURL.ResolveReference(&url.URL{Path: "/api/v1/callSeriesSeasons/" + seriesID})
|
|
request, err := http.NewRequestWithContext(ctx, http.MethodGet, seasonsURL.String(), nil)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("series seasons request: %w", err)
|
|
}
|
|
setTVerHeaders(request)
|
|
var seasons seriesContents
|
|
if err := c.getJSON(request, &seasons); err != nil {
|
|
return nil, fmt.Errorf("series seasons: %w", err)
|
|
}
|
|
if seasons.Code != 0 || seasons.Result.Contents == nil {
|
|
return nil, fmt.Errorf("series seasons: invalid API result (code %d)", seasons.Code)
|
|
}
|
|
var seasonIDs []string
|
|
for _, item := range seasons.Result.Contents {
|
|
if item.Type != "season" {
|
|
continue
|
|
}
|
|
if !tverSeriesIDPattern.MatchString(item.Content.ID) {
|
|
return nil, errors.New("series seasons: invalid season id")
|
|
}
|
|
seasonIDs = append(seasonIDs, item.Content.ID)
|
|
}
|
|
if len(seasonIDs) == 0 {
|
|
return []Episode{}, nil
|
|
}
|
|
session, err := c.CreateSession(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
seen := make(map[string]bool)
|
|
var episodes []Episode
|
|
for _, seasonID := range seasonIDs {
|
|
endpoint := c.baseURL.ResolveReference(&url.URL{Path: "/service/api/v1/callSeasonEpisodes/" + seasonID})
|
|
query := endpoint.Query()
|
|
query.Set("platform_uid", session.PlatformUID)
|
|
query.Set("platform_token", session.PlatformToken)
|
|
endpoint.RawQuery = query.Encode()
|
|
request, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint.String(), nil)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("season episodes request: %w", err)
|
|
}
|
|
setTVerHeaders(request)
|
|
var response seriesContents
|
|
if err := c.getJSON(request, &response); err != nil {
|
|
return nil, fmt.Errorf("season episodes: %w", err)
|
|
}
|
|
if response.Code != 0 || response.Result.Contents == nil {
|
|
return nil, fmt.Errorf("season episodes: invalid API result (code %d)", response.Code)
|
|
}
|
|
for _, item := range response.Result.Contents {
|
|
if item.Type != "episode" {
|
|
continue
|
|
}
|
|
ep := item.Content
|
|
if !tverSeriesIDPattern.MatchString(ep.ID) || ep.SeriesID != seriesID {
|
|
return nil, errors.New("season episodes: invalid episode identity")
|
|
}
|
|
if !seen[ep.ID] {
|
|
episodes = append(episodes, ep)
|
|
seen[ep.ID] = true
|
|
}
|
|
}
|
|
}
|
|
return episodes, nil
|
|
}
|
|
|
|
func setTVerHeaders(request *http.Request) {
|
|
request.Header.Set("x-tver-platform-type", "web")
|
|
request.Header.Set("Origin", "https://tver.jp")
|
|
request.Header.Set("Referer", "https://tver.jp/")
|
|
}
|