番組登録を追加(登録時の過去回の選択、一時停止・再開・解除、既知の回の記録)
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
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/")
|
||||
}
|
||||
Reference in New Issue
Block a user