mirror of
https://github.com/crunchy-labs/crunchy-cli.git
synced 2026-01-21 04:02:00 -06:00
Merge pull request #38 from ByteDream/v3/feature/non-premium-support
Extend support for non premium accounts
This commit is contained in:
commit
170fb2efb8
10 changed files with 104 additions and 75 deletions
|
|
@ -186,8 +186,10 @@ func archive(urls []string) error {
|
|||
episodes, err := archiveExtractEpisodes(url)
|
||||
if err != nil {
|
||||
out.StopProgress("Failed to parse url %d", i+1)
|
||||
out.Debug("If the error says no episodes could be found but the passed url is correct and a crunchyroll classic url, " +
|
||||
"try the corresponding crunchyroll beta url instead and try again. See https://github.com/ByteDream/crunchyroll-go/issues/22 for more information")
|
||||
if crunchy.Config.Premium {
|
||||
out.Debug("If the error says no episodes could be found but the passed url is correct and a crunchyroll classic url, " +
|
||||
"try the corresponding crunchyroll beta url instead and try again. See https://github.com/ByteDream/crunchyroll-go/issues/22 for more information")
|
||||
}
|
||||
return err
|
||||
}
|
||||
out.StopProgress("Parsed url %d", i+1)
|
||||
|
|
|
|||
|
|
@ -132,8 +132,10 @@ func download(urls []string) error {
|
|||
episodes, err := downloadExtractEpisodes(url)
|
||||
if err != nil {
|
||||
out.StopProgress("Failed to parse url %d", i+1)
|
||||
out.Debug("If the error says no episodes could be found but the passed url is correct and a crunchyroll classic url, " +
|
||||
"try the corresponding crunchyroll beta url instead and try again. See https://github.com/ByteDream/crunchyroll-go/issues/22 for more information")
|
||||
if crunchy.Config.Premium {
|
||||
out.Debug("If the error says no episodes could be found but the passed url is correct and a crunchyroll classic url, " +
|
||||
"try the corresponding crunchyroll beta url instead and try again. See https://github.com/ByteDream/crunchyroll-go/issues/22 for more information")
|
||||
}
|
||||
return err
|
||||
}
|
||||
out.StopProgress("Parsed url %d", i+1)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
|
@ -50,7 +51,7 @@ const (
|
|||
type Crunchyroll struct {
|
||||
// Client is the http.Client to perform all requests over.
|
||||
Client *http.Client
|
||||
// Context can be used to stop requests with Client and is context.Background by default.
|
||||
// Context can be used to stop requests with Client.
|
||||
Context context.Context
|
||||
// Locale specifies in which language all results should be returned / requested.
|
||||
Locale LOCALE
|
||||
|
|
@ -67,7 +68,6 @@ type Crunchyroll struct {
|
|||
|
||||
CountryCode string
|
||||
Premium bool
|
||||
Channel string
|
||||
Policy string
|
||||
Signature string
|
||||
KeyPairID string
|
||||
|
|
@ -111,6 +111,9 @@ type loginResponse struct {
|
|||
Scope string `json:"scope"`
|
||||
Country string `json:"country"`
|
||||
AccountID string `json:"account_id"`
|
||||
|
||||
Error bool `json:"error"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// LoginWithCredentials logs in via crunchyroll username or email and password.
|
||||
|
|
@ -136,6 +139,11 @@ func LoginWithCredentials(user string, password string, locale LOCALE, client *h
|
|||
|
||||
var loginResp loginResponse
|
||||
json.NewDecoder(resp.Body).Decode(&loginResp)
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("failed to auth with credentials: %s", resp.Status)
|
||||
} else if loginResp.Error {
|
||||
return nil, fmt.Errorf("an unexpected login error occoured: %s", loginResp.Message)
|
||||
}
|
||||
|
||||
var etpRt string
|
||||
for _, cookie := range resp.Cookies() {
|
||||
|
|
@ -173,9 +181,16 @@ func LoginWithSessionID(sessionID string, locale LOCALE, client *http.Client) (*
|
|||
if err = json.NewDecoder(resp.Body).Decode(&jsonBody); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse start session with session id response: %w", err)
|
||||
}
|
||||
|
||||
if isError, ok := jsonBody["error"]; ok && isError.(bool) {
|
||||
return nil, fmt.Errorf("invalid session id (%s): %s", jsonBody["message"].(string), jsonBody["code"])
|
||||
}
|
||||
data := jsonBody["data"].(map[string]interface{})
|
||||
|
||||
user := data["user"]
|
||||
if user == nil {
|
||||
return nil, errors.New("invalid session id, user is not logged in")
|
||||
}
|
||||
|
||||
var etpRt string
|
||||
for _, cookie := range resp.Cookies() {
|
||||
|
|
@ -244,22 +259,11 @@ func postLogin(loginResp loginResponse, etpRt string, locale LOCALE, client *htt
|
|||
|
||||
cms := jsonBody["cms"].(map[string]any)
|
||||
crunchy.Config.Bucket = strings.TrimPrefix(cms["bucket"].(string), "/")
|
||||
if strings.HasSuffix(crunchy.Config.Bucket, "crunchyroll") {
|
||||
crunchy.Config.Premium = true
|
||||
crunchy.Config.Channel = "crunchyroll"
|
||||
} else {
|
||||
crunchy.Config.Premium = false
|
||||
crunchy.Config.Channel = "-"
|
||||
}
|
||||
|
||||
if strings.Contains(cms["bucket"].(string), "crunchyroll") {
|
||||
crunchy.Config.Premium = true
|
||||
crunchy.Config.Channel = "crunchyroll"
|
||||
} else {
|
||||
crunchy.Config.Premium = false
|
||||
crunchy.Config.Channel = "-"
|
||||
}
|
||||
crunchy.Config.Premium = strings.HasSuffix(crunchy.Config.Bucket, "crunchyroll")
|
||||
|
||||
// / is trimmed so that urls which require it must be in .../{bucket}/... like format.
|
||||
// this just looks cleaner
|
||||
crunchy.Config.Bucket = strings.TrimPrefix(cms["bucket"].(string), "/")
|
||||
crunchy.Config.Policy = cms["policy"].(string)
|
||||
crunchy.Config.Signature = cms["signature"].(string)
|
||||
crunchy.Config.KeyPairID = cms["key_pair_id"].(string)
|
||||
|
|
|
|||
19
episode.go
19
episode.go
|
|
@ -89,10 +89,8 @@ type HistoryEpisode struct {
|
|||
|
||||
// EpisodeFromID returns an episode by its api id.
|
||||
func EpisodeFromID(crunchy *Crunchyroll, id string) (*Episode, error) {
|
||||
resp, err := crunchy.request(fmt.Sprintf("https://beta-api.crunchyroll.com/cms/v2/%s/%s/%s/episodes/%s?locale=%s&Signature=%s&Policy=%s&Key-Pair-Id=%s",
|
||||
crunchy.Config.CountryCode,
|
||||
crunchy.Config.MaturityRating,
|
||||
crunchy.Config.Channel,
|
||||
resp, err := crunchy.request(fmt.Sprintf("https://beta-api.crunchyroll.com/cms/v2/%s/episodes/%s?locale=%s&Signature=%s&Policy=%s&Key-Pair-Id=%s",
|
||||
crunchy.Config.Bucket,
|
||||
id,
|
||||
crunchy.Locale,
|
||||
crunchy.Config.Signature,
|
||||
|
|
@ -126,6 +124,8 @@ func EpisodeFromID(crunchy *Crunchyroll, id string) (*Episode, error) {
|
|||
// Every episode in a season (should) have the same audio locale,
|
||||
// so if you want to get the audio locale of a season, just call
|
||||
// this method on the first episode of the season.
|
||||
// Will fail if no streams are available, thus use Episode.Available
|
||||
// to prevent any misleading errors.
|
||||
func (e *Episode) AudioLocale() (LOCALE, error) {
|
||||
streams, err := e.Streams()
|
||||
if err != nil {
|
||||
|
|
@ -134,6 +134,11 @@ func (e *Episode) AudioLocale() (LOCALE, error) {
|
|||
return streams[0].AudioLocale, nil
|
||||
}
|
||||
|
||||
// Available returns if downloadable streams for this episodes are available.
|
||||
func (e *Episode) Available() bool {
|
||||
return e.crunchy.Config.Premium || !e.IsPremiumOnly
|
||||
}
|
||||
|
||||
// GetFormat returns the format which matches the given resolution and subtitle locale.
|
||||
func (e *Episode) GetFormat(resolution string, subtitle LOCALE, hardsub bool) (*Format, error) {
|
||||
streams, err := e.Streams()
|
||||
|
|
@ -206,10 +211,8 @@ func (e *Episode) Streams() ([]*Stream, error) {
|
|||
return e.children, nil
|
||||
}
|
||||
|
||||
streams, err := fromVideoStreams(e.crunchy, fmt.Sprintf("https://beta-api.crunchyroll.com/cms/v2/%s/%s/%s/videos/%s/streams?locale=%s&Signature=%s&Policy=%s&Key-Pair-Id=%s",
|
||||
e.crunchy.Config.CountryCode,
|
||||
e.crunchy.Config.MaturityRating,
|
||||
e.crunchy.Config.Channel,
|
||||
streams, err := fromVideoStreams(e.crunchy, fmt.Sprintf("https://beta-api.crunchyroll.com/cms/v2/%s/videos/%s/streams?locale=%s&Signature=%s&Policy=%s&Key-Pair-Id=%s",
|
||||
e.crunchy.Config.Bucket,
|
||||
e.StreamID,
|
||||
e.crunchy.Locale,
|
||||
e.crunchy.Config.Signature,
|
||||
|
|
|
|||
|
|
@ -41,10 +41,8 @@ type MovieListing struct {
|
|||
|
||||
// MovieListingFromID returns a movie listing by its api id.
|
||||
func MovieListingFromID(crunchy *Crunchyroll, id string) (*MovieListing, error) {
|
||||
resp, err := crunchy.request(fmt.Sprintf("https://beta-api.crunchyroll.com/cms/v2/%s/%s/%s/movie_listing/%s&locale=%s&Signature=%s&Policy=%s&Key-Pair-Id=%s",
|
||||
crunchy.Config.CountryCode,
|
||||
crunchy.Config.MaturityRating,
|
||||
crunchy.Config.Channel,
|
||||
resp, err := crunchy.request(fmt.Sprintf("https://beta-api.crunchyroll.com/cms/v2/%s/movie_listing/%s&locale=%s&Signature=%s&Policy=%s&Key-Pair-Id=%s",
|
||||
crunchy.Config.Bucket,
|
||||
id,
|
||||
crunchy.Locale,
|
||||
crunchy.Config.Signature,
|
||||
|
|
@ -70,10 +68,8 @@ func MovieListingFromID(crunchy *Crunchyroll, id string) (*MovieListing, error)
|
|||
|
||||
// AudioLocale is same as Episode.AudioLocale.
|
||||
func (ml *MovieListing) AudioLocale() (LOCALE, error) {
|
||||
resp, err := ml.crunchy.request(fmt.Sprintf("https://beta-api.crunchyroll.com/cms/v2/%s/%s/%s/videos/%s/streams?locale=%s&Signature=%s&Policy=%s&Key-Pair-Id=%s",
|
||||
ml.crunchy.Config.CountryCode,
|
||||
ml.crunchy.Config.MaturityRating,
|
||||
ml.crunchy.Config.Channel,
|
||||
resp, err := ml.crunchy.request(fmt.Sprintf("https://beta-api.crunchyroll.com/cms/v2/%s/videos/%s/streams?locale=%s&Signature=%s&Policy=%s&Key-Pair-Id=%s",
|
||||
ml.crunchy.Config.Bucket,
|
||||
ml.ID,
|
||||
ml.crunchy.Locale,
|
||||
ml.crunchy.Config.Signature,
|
||||
|
|
@ -91,10 +87,8 @@ func (ml *MovieListing) AudioLocale() (LOCALE, error) {
|
|||
|
||||
// Streams returns all streams which are available for the movie listing.
|
||||
func (ml *MovieListing) Streams() ([]*Stream, error) {
|
||||
return fromVideoStreams(ml.crunchy, fmt.Sprintf("https://beta-api.crunchyroll.com/cms/v2/%s/%s/%s/videos/%s/streams?locale=%s&Signature=%s&Policy=%s&Key-Pair-Id=%s",
|
||||
ml.crunchy.Config.CountryCode,
|
||||
ml.crunchy.Config.MaturityRating,
|
||||
ml.crunchy.Config.Channel,
|
||||
return fromVideoStreams(ml.crunchy, fmt.Sprintf("https://beta-api.crunchyroll.com/cms/v2/%s/videos/%s/streams?locale=%s&Signature=%s&Policy=%s&Key-Pair-Id=%s",
|
||||
ml.crunchy.Config.Bucket,
|
||||
ml.ID,
|
||||
ml.crunchy.Locale,
|
||||
ml.crunchy.Config.Signature,
|
||||
|
|
|
|||
29
season.go
29
season.go
|
|
@ -38,17 +38,15 @@ type Season struct {
|
|||
|
||||
AvailabilityNotes string `json:"availability_notes"`
|
||||
|
||||
// the locales are always empty, idk why this may change in the future
|
||||
// the locales are always empty, idk why, this may change in the future
|
||||
AudioLocales []LOCALE
|
||||
SubtitleLocales []LOCALE
|
||||
}
|
||||
|
||||
// SeasonFromID returns a season by its api id.
|
||||
func SeasonFromID(crunchy *Crunchyroll, id string) (*Season, error) {
|
||||
resp, err := crunchy.Client.Get(fmt.Sprintf("https://beta-api.crunchyroll.com/cms/v2/%s/%s/%s/seasons/%s?locale=%s&Signature=%s&Policy=%s&Key-Pair-Id=%s",
|
||||
crunchy.Config.CountryCode,
|
||||
crunchy.Config.MaturityRating,
|
||||
crunchy.Config.Channel,
|
||||
resp, err := crunchy.Client.Get(fmt.Sprintf("https://beta-api.crunchyroll.com/cms/v2/%s/seasons?series_id=%s&locale=%s&Signature=%s&Policy=%s&Key-Pair-Id=%s",
|
||||
crunchy.Config.Bucket,
|
||||
id,
|
||||
crunchy.Locale,
|
||||
crunchy.Config.Signature,
|
||||
|
|
@ -73,6 +71,8 @@ func SeasonFromID(crunchy *Crunchyroll, id string) (*Season, error) {
|
|||
}
|
||||
|
||||
// AudioLocale returns the audio locale of the season.
|
||||
// Will fail if no streams are available, thus use Season.Available
|
||||
// to prevent any misleading errors.
|
||||
func (s *Season) AudioLocale() (LOCALE, error) {
|
||||
episodes, err := s.Episodes()
|
||||
if err != nil {
|
||||
|
|
@ -81,16 +81,23 @@ func (s *Season) AudioLocale() (LOCALE, error) {
|
|||
return episodes[0].AudioLocale()
|
||||
}
|
||||
|
||||
// Available returns if downloadable streams for this season are available.
|
||||
func (s *Season) Available() (bool, error) {
|
||||
episodes, err := s.Episodes()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return episodes[0].Available(), nil
|
||||
}
|
||||
|
||||
// Episodes returns all episodes which are available for the season.
|
||||
func (s *Season) Episodes() (episodes []*Episode, err error) {
|
||||
if s.children != nil {
|
||||
return s.children, nil
|
||||
}
|
||||
|
||||
resp, err := s.crunchy.request(fmt.Sprintf("https://beta-api.crunchyroll.com/cms/v2/%s/%s/%s/episodes?season_id=%s&locale=%s&Signature=%s&Policy=%s&Key-Pair-Id=%s",
|
||||
s.crunchy.Config.CountryCode,
|
||||
s.crunchy.Config.MaturityRating,
|
||||
s.crunchy.Config.Channel,
|
||||
resp, err := s.crunchy.request(fmt.Sprintf("https://beta-api.crunchyroll.com/cms/v2/%s/episodes?season_id=%s&locale=%s&Signature=%s&Policy=%s&Key-Pair-Id=%s",
|
||||
s.crunchy.Config.Bucket,
|
||||
s.ID,
|
||||
s.crunchy.Locale,
|
||||
s.crunchy.Config.Signature,
|
||||
|
|
@ -112,8 +119,10 @@ func (s *Season) Episodes() (episodes []*Episode, err error) {
|
|||
}
|
||||
if episode.Playback != "" {
|
||||
streamHref := item.(map[string]interface{})["__links__"].(map[string]interface{})["streams"].(map[string]interface{})["href"].(string)
|
||||
if match := regexp.MustCompile(`(?m)^/cms/v2/\S+videos/(\w+)/streams$`).FindAllStringSubmatch(streamHref, -1); len(match) > 0 {
|
||||
if match := regexp.MustCompile(`(?m)(\w+)/streams$`).FindAllStringSubmatch(streamHref, -1); len(match) > 0 {
|
||||
episode.StreamID = match[0][1]
|
||||
} else {
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
episodes = append(episodes, episode)
|
||||
|
|
|
|||
16
stream.go
16
stream.go
|
|
@ -25,10 +25,8 @@ type Stream struct {
|
|||
|
||||
// StreamsFromID returns a stream by its api id.
|
||||
func StreamsFromID(crunchy *Crunchyroll, id string) ([]*Stream, error) {
|
||||
return fromVideoStreams(crunchy, fmt.Sprintf("https://beta-api.crunchyroll.com/cms/v2/%s/%s/%s/videos/%s/streams?locale=%s&Signature=%s&Policy=%s&Key-Pair-Id=%s",
|
||||
crunchy.Config.CountryCode,
|
||||
crunchy.Config.MaturityRating,
|
||||
crunchy.Config.Channel,
|
||||
return fromVideoStreams(crunchy, fmt.Sprintf("https://beta-api.crunchyroll.com/cms/v2/%s/videos/%s/streams?locale=%s&Signature=%s&Policy=%s&Key-Pair-Id=%s",
|
||||
crunchy.Config.Bucket,
|
||||
id,
|
||||
crunchy.Locale,
|
||||
crunchy.Config.Signature,
|
||||
|
|
@ -82,8 +80,12 @@ func fromVideoStreams(crunchy *Crunchyroll, endpoint string) (streams []*Stream,
|
|||
json.NewDecoder(resp.Body).Decode(&jsonBody)
|
||||
|
||||
if len(jsonBody) == 0 {
|
||||
// this may get thrown when the crunchyroll account has just a normal account and not one with premium
|
||||
return nil, fmt.Errorf("no stream available")
|
||||
// this may get thrown when the crunchyroll account is just a normal account and not one with premium
|
||||
if !crunchy.Config.Premium {
|
||||
return nil, fmt.Errorf("no stream available, this might be the result of using a non-premium account")
|
||||
} else {
|
||||
return nil, fmt.Errorf("no stream available")
|
||||
}
|
||||
}
|
||||
|
||||
audioLocale := jsonBody["audio_locale"].(string)
|
||||
|
|
@ -105,7 +107,7 @@ func fromVideoStreams(crunchy *Crunchyroll, endpoint string) (streams []*Stream,
|
|||
var id string
|
||||
var formatType FormatType
|
||||
href := jsonBody["__links__"].(map[string]interface{})["resource"].(map[string]interface{})["href"].(string)
|
||||
if match := regexp.MustCompile(`(?sm)^/cms/v2/\S+/crunchyroll/(\w+)/(\w+)$`).FindAllStringSubmatch(href, -1); len(match) > 0 {
|
||||
if match := regexp.MustCompile(`(?sm)/(\w+)/(\w+)$`).FindAllStringSubmatch(href, -1); len(match) > 0 {
|
||||
formatType = FormatType(match[0][1])
|
||||
id = match[0][2]
|
||||
}
|
||||
|
|
|
|||
20
url.go
20
url.go
|
|
@ -13,6 +13,7 @@ func (c *Crunchyroll) ExtractEpisodesFromUrl(url string, audio ...LOCALE) ([]*Ep
|
|||
}
|
||||
|
||||
var eps []*Episode
|
||||
var notAvailableContinue bool
|
||||
|
||||
if series != nil {
|
||||
seasons, err := series.Seasons()
|
||||
|
|
@ -21,6 +22,13 @@ func (c *Crunchyroll) ExtractEpisodesFromUrl(url string, audio ...LOCALE) ([]*Ep
|
|||
}
|
||||
for _, season := range seasons {
|
||||
if audio != nil {
|
||||
if available, err := season.Available(); err != nil {
|
||||
return nil, err
|
||||
} else if !available {
|
||||
notAvailableContinue = true
|
||||
continue
|
||||
}
|
||||
|
||||
locale, err := season.AudioLocale()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -49,6 +57,12 @@ func (c *Crunchyroll) ExtractEpisodesFromUrl(url string, audio ...LOCALE) ([]*Ep
|
|||
}
|
||||
|
||||
for _, episode := range episodes {
|
||||
// if no episode streams are available, calling episode.AudioLocale
|
||||
// will result in an unwanted error
|
||||
if !episode.Available() {
|
||||
notAvailableContinue = true
|
||||
continue
|
||||
}
|
||||
locale, err := episode.AudioLocale()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -71,7 +85,11 @@ func (c *Crunchyroll) ExtractEpisodesFromUrl(url string, audio ...LOCALE) ([]*Ep
|
|||
}
|
||||
|
||||
if len(eps) == 0 {
|
||||
return nil, fmt.Errorf("could not find any matching episode")
|
||||
if notAvailableContinue {
|
||||
return nil, fmt.Errorf("could not find any matching episode which is accessable with a non-premium account")
|
||||
} else {
|
||||
return nil, fmt.Errorf("could not find any matching episode")
|
||||
}
|
||||
}
|
||||
|
||||
return eps, nil
|
||||
|
|
|
|||
|
|
@ -52,6 +52,9 @@ func SortEpisodesByAudio(episodes []*crunchyroll.Episode) (map[crunchyroll.LOCAL
|
|||
var wg sync.WaitGroup
|
||||
var lock sync.Mutex
|
||||
for _, episode := range episodes {
|
||||
if !episode.Available() {
|
||||
continue
|
||||
}
|
||||
episode := episode
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
|
|
|
|||
24
video.go
24
video.go
|
|
@ -70,10 +70,8 @@ type Movie struct {
|
|||
|
||||
// MovieFromID returns a movie by its api id.
|
||||
func MovieFromID(crunchy *Crunchyroll, id string) (*Movie, error) {
|
||||
resp, err := crunchy.request(fmt.Sprintf("https://beta-api.crunchyroll.com/cms/v2/%s/%s/%s/movies/%s&locale=%s&Signature=%s&Policy=%s&Key-Pair-Id=%s",
|
||||
crunchy.Config.CountryCode,
|
||||
crunchy.Config.MaturityRating,
|
||||
crunchy.Config.Channel,
|
||||
resp, err := crunchy.request(fmt.Sprintf("https://beta-api.crunchyroll.com/cms/v2/%s/movies/%s&locale=%s&Signature=%s&Policy=%s&Key-Pair-Id=%s",
|
||||
crunchy.Config.Bucket,
|
||||
id,
|
||||
crunchy.Locale,
|
||||
crunchy.Config.Signature,
|
||||
|
|
@ -103,10 +101,8 @@ func (m *Movie) MovieListing() (movieListings []*MovieListing, err error) {
|
|||
return m.children, nil
|
||||
}
|
||||
|
||||
resp, err := m.crunchy.request(fmt.Sprintf("https://beta-api.crunchyroll.com/cms/v2/%s/%s/%s/movies?movie_listing_id=%s&locale=%s&Signature=%s&Policy=%s&Key-Pair-Id=%s",
|
||||
m.crunchy.Config.CountryCode,
|
||||
m.crunchy.Config.MaturityRating,
|
||||
m.crunchy.Config.Channel,
|
||||
resp, err := m.crunchy.request(fmt.Sprintf("https://beta-api.crunchyroll.com/cms/v2/%s/movies?movie_listing_id=%s&locale=%s&Signature=%s&Policy=%s&Key-Pair-Id=%s",
|
||||
m.crunchy.Config.Bucket,
|
||||
m.ID,
|
||||
m.crunchy.Locale,
|
||||
m.crunchy.Config.Signature,
|
||||
|
|
@ -166,10 +162,8 @@ type Series struct {
|
|||
|
||||
// SeriesFromID returns a series by its api id.
|
||||
func SeriesFromID(crunchy *Crunchyroll, id string) (*Series, error) {
|
||||
resp, err := crunchy.request(fmt.Sprintf("https://beta-api.crunchyroll.com/cms/v2/%s/%s/%s/movies?movie_listing_id=%s&locale=%s&Signature=%s&Policy=%s&Key-Pair-Id=%s",
|
||||
crunchy.Config.CountryCode,
|
||||
crunchy.Config.MaturityRating,
|
||||
crunchy.Config.Channel,
|
||||
resp, err := crunchy.request(fmt.Sprintf("https://beta-api.crunchyroll.com/cms/v2/%s/movies?movie_listing_id=%s&locale=%s&Signature=%s&Policy=%s&Key-Pair-Id=%s",
|
||||
crunchy.Config.Bucket,
|
||||
id,
|
||||
crunchy.Locale,
|
||||
crunchy.Config.Signature,
|
||||
|
|
@ -199,10 +193,8 @@ func (s *Series) Seasons() (seasons []*Season, err error) {
|
|||
return s.children, nil
|
||||
}
|
||||
|
||||
resp, err := s.crunchy.request(fmt.Sprintf("https://beta-api.crunchyroll.com/cms/v2/%s/%s/%s/seasons?series_id=%s&locale=%s&Signature=%s&Policy=%s&Key-Pair-Id=%s",
|
||||
s.crunchy.Config.CountryCode,
|
||||
s.crunchy.Config.MaturityRating,
|
||||
s.crunchy.Config.Channel,
|
||||
resp, err := s.crunchy.request(fmt.Sprintf("https://beta-api.crunchyroll.com/cms/v2/%s/seasons?series_id=%s&locale=%s&Signature=%s&Policy=%s&Key-Pair-Id=%s",
|
||||
s.crunchy.Config.Bucket,
|
||||
s.ID,
|
||||
s.crunchy.Locale,
|
||||
s.crunchy.Config.Signature,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue