diff --git a/crunchyroll.go b/crunchyroll.go index 6b1854f..60b4320 100644 --- a/crunchyroll.go +++ b/crunchyroll.go @@ -11,6 +11,7 @@ import ( "net/url" "regexp" "strconv" + "strings" ) // LOCALE represents a locale / language. @@ -33,7 +34,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 @@ -45,9 +46,10 @@ type Crunchyroll struct { TokenType string AccessToken string + Bucket string + CountryCode string Premium bool - Channel string Policy string Signature string KeyPairID string @@ -141,13 +143,7 @@ func LoginWithSessionID(sessionID string, locale LOCALE, client *http.Client) (* if user == nil { return nil, errors.New("invalid session id, user is not logged in") } - if user.(map[string]interface{})["premium"] == "" { - crunchy.Config.Premium = false - crunchy.Config.Channel = "-" - } else { - crunchy.Config.Premium = true - crunchy.Config.Channel = "crunchyroll" - } + crunchy.Config.Premium = user.(map[string]interface{})["premium"] != "" var etpRt string for _, cookie := range resp.Cookies() { @@ -200,6 +196,9 @@ func LoginWithSessionID(sessionID string, locale LOCALE, client *http.Client) (* } cms := jsonBody["cms"].(map[string]interface{}) + // / 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) diff --git a/episode.go b/episode.go index a25844c..3c9d38f 100644 --- a/episode.go +++ b/episode.go @@ -77,10 +77,8 @@ type Episode 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, @@ -194,10 +192,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, diff --git a/movie_listing.go b/movie_listing.go index 63d7fab..80b7b46 100644 --- a/movie_listing.go +++ b/movie_listing.go @@ -40,10 +40,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, @@ -69,10 +67,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, @@ -90,10 +86,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, diff --git a/season.go b/season.go index 825a816..b83d214 100644 --- a/season.go +++ b/season.go @@ -44,10 +44,8 @@ type Season struct { // 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, @@ -86,10 +84,8 @@ func (s *Season) Episodes() (episodes []*Episode, err error) { 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, @@ -111,8 +107,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) diff --git a/stream.go b/stream.go index d8957e6..b1193ed 100644 --- a/stream.go +++ b/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, @@ -105,7 +103,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] } diff --git a/video.go b/video.go index 00b7734..8a7ee76 100644 --- a/video.go +++ b/video.go @@ -69,10 +69,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, @@ -102,10 +100,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, @@ -165,10 +161,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, @@ -198,10 +192,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,