147 lines
4.6 KiB
Go
147 lines
4.6 KiB
Go
package scanner
|
|
|
|
import (
|
|
"github.com/rs/zerolog"
|
|
"github.com/samber/lo"
|
|
lop "github.com/samber/lo/parallel"
|
|
"seanime/internal/api/anilist"
|
|
"seanime/internal/library/anime"
|
|
"seanime/internal/util/comparison"
|
|
"strings"
|
|
)
|
|
|
|
type (
|
|
MediaContainerOptions struct {
|
|
AllMedia []*anilist.CompleteAnime
|
|
ScanLogger *ScanLogger
|
|
}
|
|
|
|
MediaContainer struct {
|
|
NormalizedMedia []*anime.NormalizedMedia
|
|
ScanLogger *ScanLogger
|
|
engTitles []*string
|
|
romTitles []*string
|
|
synonyms []*string
|
|
allMedia []*anilist.CompleteAnime
|
|
}
|
|
)
|
|
|
|
// NewMediaContainer will create a list of all English titles, Romaji titles, and synonyms from all anilist.BaseAnime (used by Matcher).
|
|
//
|
|
// The list will include all anilist.BaseAnime and their relations (prequels, sequels, spin-offs, etc...) as NormalizedMedia.
|
|
//
|
|
// It also provides helper functions to get a NormalizedMedia from a title or synonym (used by FileHydrator).
|
|
func NewMediaContainer(opts *MediaContainerOptions) *MediaContainer {
|
|
mc := new(MediaContainer)
|
|
mc.ScanLogger = opts.ScanLogger
|
|
|
|
mc.NormalizedMedia = make([]*anime.NormalizedMedia, 0)
|
|
|
|
normalizedMediaMap := make(map[int]*anime.NormalizedMedia)
|
|
|
|
for _, m := range opts.AllMedia {
|
|
normalizedMediaMap[m.ID] = anime.NewNormalizedMedia(m.ToBaseAnime())
|
|
if m.Relations != nil && m.Relations.Edges != nil && len(m.Relations.Edges) > 0 {
|
|
for _, edgeM := range m.Relations.Edges {
|
|
if edgeM.Node == nil || edgeM.Node.Format == nil || edgeM.RelationType == nil {
|
|
continue
|
|
}
|
|
if *edgeM.Node.Format != anilist.MediaFormatMovie &&
|
|
*edgeM.Node.Format != anilist.MediaFormatOva &&
|
|
*edgeM.Node.Format != anilist.MediaFormatSpecial &&
|
|
*edgeM.Node.Format != anilist.MediaFormatTv {
|
|
continue
|
|
}
|
|
if *edgeM.RelationType != anilist.MediaRelationPrequel &&
|
|
*edgeM.RelationType != anilist.MediaRelationSequel &&
|
|
*edgeM.RelationType != anilist.MediaRelationSpinOff &&
|
|
*edgeM.RelationType != anilist.MediaRelationAlternative &&
|
|
*edgeM.RelationType != anilist.MediaRelationParent {
|
|
continue
|
|
}
|
|
// DEVNOTE: Edges fetched from the AniList AnimeCollection query do not contain NextAiringEpisode
|
|
// Make sure we don't overwrite the original media in the map that contains NextAiringEpisode
|
|
if _, found := normalizedMediaMap[edgeM.Node.ID]; !found {
|
|
normalizedMediaMap[edgeM.Node.ID] = anime.NewNormalizedMedia(edgeM.Node)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for _, m := range normalizedMediaMap {
|
|
mc.NormalizedMedia = append(mc.NormalizedMedia, m)
|
|
}
|
|
|
|
engTitles := lop.Map(mc.NormalizedMedia, func(m *anime.NormalizedMedia, index int) *string {
|
|
if m.Title.English != nil {
|
|
return m.Title.English
|
|
}
|
|
return new(string)
|
|
})
|
|
romTitles := lop.Map(mc.NormalizedMedia, func(m *anime.NormalizedMedia, index int) *string {
|
|
if m.Title.Romaji != nil {
|
|
return m.Title.Romaji
|
|
}
|
|
return new(string)
|
|
})
|
|
_synonymsArr := lop.Map(mc.NormalizedMedia, func(m *anime.NormalizedMedia, index int) []*string {
|
|
if m.Synonyms != nil {
|
|
return m.Synonyms
|
|
}
|
|
return make([]*string, 0)
|
|
})
|
|
synonyms := lo.Flatten(_synonymsArr)
|
|
engTitles = lo.Filter(engTitles, func(s *string, i int) bool { return s != nil && len(*s) > 0 })
|
|
romTitles = lo.Filter(romTitles, func(s *string, i int) bool { return s != nil && len(*s) > 0 })
|
|
synonyms = lo.Filter(synonyms, func(s *string, i int) bool { return comparison.ValueContainsSeason(*s) })
|
|
|
|
mc.engTitles = engTitles
|
|
mc.romTitles = romTitles
|
|
mc.synonyms = synonyms
|
|
mc.allMedia = opts.AllMedia
|
|
|
|
if mc.ScanLogger != nil {
|
|
mc.ScanLogger.LogMediaContainer(zerolog.InfoLevel).
|
|
Any("inputCount", len(opts.AllMedia)).
|
|
Any("mediaCount", len(mc.NormalizedMedia)).
|
|
Any("titles", len(mc.engTitles)+len(mc.romTitles)+len(mc.synonyms)).
|
|
Msg("Created media container")
|
|
}
|
|
|
|
return mc
|
|
}
|
|
|
|
func (mc *MediaContainer) GetMediaFromTitleOrSynonym(title *string) (*anime.NormalizedMedia, bool) {
|
|
if title == nil {
|
|
return nil, false
|
|
}
|
|
t := strings.ToLower(*title)
|
|
res, found := lo.Find(mc.NormalizedMedia, func(m *anime.NormalizedMedia) bool {
|
|
if m.HasEnglishTitle() && t == strings.ToLower(*m.Title.English) {
|
|
return true
|
|
}
|
|
if m.HasRomajiTitle() && t == strings.ToLower(*m.Title.Romaji) {
|
|
return true
|
|
}
|
|
if m.HasSynonyms() {
|
|
for _, syn := range m.Synonyms {
|
|
if t == strings.ToLower(*syn) {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
})
|
|
|
|
return res, found
|
|
}
|
|
|
|
func (mc *MediaContainer) GetMediaFromId(id int) (*anime.NormalizedMedia, bool) {
|
|
res, found := lo.Find(mc.NormalizedMedia, func(m *anime.NormalizedMedia) bool {
|
|
if m.ID == id {
|
|
return true
|
|
}
|
|
return false
|
|
})
|
|
return res, found
|
|
}
|