mirror of
https://github.com/crunchy-labs/crunchy-cli.git
synced 2026-01-21 12:12:00 -06:00
210 lines
5.3 KiB
Go
210 lines
5.3 KiB
Go
package utils
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/ByteDream/crunchyroll-go"
|
|
)
|
|
|
|
// EpisodeWalker is an easy-to-use struct which walks down given urls
|
|
// and triggers functions where you can perform further actions with
|
|
// the delivered objects
|
|
type EpisodeWalker struct {
|
|
// The Crunchyroll instance to perform all actions on
|
|
Crunchyroll *crunchyroll.Crunchyroll
|
|
|
|
// If CheckDuplicates is true, duplicated urls, seasons and episodes
|
|
// are filtered out and the values given in OnSeason for example is
|
|
// always unique
|
|
CheckDuplicates bool
|
|
|
|
// OnUrl gets called when an url is parsed.
|
|
// The error is generally only nil when the url is invalid
|
|
OnUrl func(url string, err error) error
|
|
// OnSeason gets called when a season was parsed
|
|
OnSeason func(season *crunchyroll.Season, err error) error
|
|
// OnEpisode gets called when a season was parsed
|
|
OnEpisode func(episode *crunchyroll.Episode, err error) error
|
|
}
|
|
|
|
// WalkURLs walks through all urls.
|
|
// Urls to seasons and episodes are support, normal as well as beta urls
|
|
func (ew EpisodeWalker) WalkURLs(urls []string) error {
|
|
var episodeIds, seasonIds, seriesNames []string
|
|
var episodeNames map[string][]string
|
|
|
|
for _, url := range urls {
|
|
if episodeId, ok := crunchyroll.ParseBetaEpisodeURL(url); ok && !(ew.CheckDuplicates && sliceContains(episodeIds, episodeId)) {
|
|
episodeIds = append(episodeIds, episodeId)
|
|
} else if seasonId, ok := crunchyroll.ParseBetaSeriesURL(url); ok && !(ew.CheckDuplicates && sliceContains(seasonIds, seasonId)) {
|
|
seasonIds = append(seasonIds, seasonId)
|
|
} else if seriesName, title, _, _, ok := crunchyroll.ParseEpisodeURL(url); ok {
|
|
if eps, ok := episodeNames[seriesName]; ok {
|
|
if !ew.CheckDuplicates || !sliceContains(eps, title) {
|
|
eps = append(eps, title)
|
|
}
|
|
} else {
|
|
episodeNames[seriesName] = []string{title}
|
|
}
|
|
} else if seriesName, ok := crunchyroll.ParseVideoURL(url); ok && !(ew.CheckDuplicates && sliceContains(seriesNames, seriesName)) {
|
|
seriesNames = append(seriesNames, seriesName)
|
|
} else {
|
|
err := fmt.Errorf("invalid url %s", url)
|
|
if ew.OnUrl != nil {
|
|
if err = ew.OnUrl(url, err); err != nil {
|
|
return err
|
|
}
|
|
continue
|
|
} else {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if ew.OnUrl != nil {
|
|
if err := ew.OnUrl(url, nil); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
for _, name := range seriesNames {
|
|
video, err := ew.Crunchyroll.FindVideoByName(name)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// in all cases i've ever tested video was a series - even
|
|
// if it was listed as a movie on the crunchyroll website.
|
|
// i just hope no error occurs here :)
|
|
seasons, err := video.(*crunchyroll.Series).Seasons()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, season := range seasons {
|
|
if ew.CheckDuplicates {
|
|
if sliceContains(seasonIds, season.ID) {
|
|
continue
|
|
}
|
|
seasonIds = append(seasonIds, season.ID)
|
|
}
|
|
if ew.OnSeason != nil {
|
|
if err := ew.OnSeason(season, nil); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if err := ew.walkEpisodeIds(episodeIds); err != nil {
|
|
return err
|
|
} else if err := ew.walkSeasonIds(seasonIds); err != nil {
|
|
return err
|
|
} else if err := ew.walkEpisodeNames(episodeNames); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (ew EpisodeWalker) walkEpisodeIds(episodeIds []string) error {
|
|
var episodeIdsCheck []string
|
|
|
|
for _, id := range episodeIds {
|
|
if ew.CheckDuplicates {
|
|
if sliceContains(episodeIdsCheck, id) {
|
|
continue
|
|
}
|
|
episodeIdsCheck = append(episodeIdsCheck, id)
|
|
}
|
|
|
|
episode, err := crunchyroll.EpisodeFromID(ew.Crunchyroll, id)
|
|
if ew.OnEpisode != nil {
|
|
if err = ew.OnEpisode(episode, err); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (ew EpisodeWalker) walkSeasonIds(seasonIds []string) error {
|
|
var episodeIdsCheck []string
|
|
|
|
for _, id := range seasonIds {
|
|
season, err := crunchyroll.SeasonFromID(ew.Crunchyroll, id)
|
|
if ew.OnSeason != nil {
|
|
if err = ew.OnSeason(season, err); err != nil {
|
|
return err
|
|
}
|
|
} else if err != nil {
|
|
return err
|
|
}
|
|
eps, err := season.Episodes()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, ep := range eps {
|
|
if ew.CheckDuplicates {
|
|
if sliceContains(episodeIdsCheck, ep.ID) {
|
|
continue
|
|
}
|
|
episodeIdsCheck = append(episodeIdsCheck, ep.ID)
|
|
}
|
|
|
|
if ew.OnEpisode != nil {
|
|
if err = ew.OnEpisode(ep, nil); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (ew EpisodeWalker) walkEpisodeNames(episodeNames map[string][]string) error {
|
|
var episodeIdsCheck []string
|
|
|
|
for seriesName, episodeName := range episodeNames {
|
|
video, err := ew.Crunchyroll.FindVideoByName(seriesName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
series := video.(*crunchyroll.Series)
|
|
seasons, err := series.Seasons()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, season := range seasons {
|
|
eps, err := season.Episodes()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, ep := range eps {
|
|
for _, name := range episodeName {
|
|
if ep.SlugTitle == name {
|
|
if ew.OnEpisode != nil {
|
|
if ew.CheckDuplicates {
|
|
if sliceContains(episodeIdsCheck, ep.ID) {
|
|
continue
|
|
}
|
|
episodeIdsCheck = append(episodeIdsCheck, ep.ID)
|
|
}
|
|
|
|
if err = ew.OnEpisode(ep, nil); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func sliceContains(slice []string, elem string) bool {
|
|
for _, s := range slice {
|
|
if elem == s {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|