node build fixed
This commit is contained in:
288
seanime-2.9.10/internal/onlinestream/repository.go
Normal file
288
seanime-2.9.10/internal/onlinestream/repository.go
Normal file
@@ -0,0 +1,288 @@
|
||||
package onlinestream
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"seanime/internal/api/anilist"
|
||||
"seanime/internal/api/metadata"
|
||||
"seanime/internal/database/db"
|
||||
"seanime/internal/extension"
|
||||
"seanime/internal/library/anime"
|
||||
"seanime/internal/platforms/platform"
|
||||
"seanime/internal/util/filecache"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
type (
|
||||
Repository struct {
|
||||
logger *zerolog.Logger
|
||||
providerExtensionBank *extension.UnifiedBank
|
||||
fileCacher *filecache.Cacher
|
||||
metadataProvider metadata.Provider
|
||||
platform platform.Platform
|
||||
anilistBaseAnimeCache *anilist.BaseAnimeCache
|
||||
db *db.Database
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNoVideoSourceFound = errors.New("no video source found")
|
||||
)
|
||||
|
||||
type (
|
||||
Episode struct {
|
||||
Number int `json:"number"`
|
||||
Title string `json:"title,omitempty"`
|
||||
Image string `json:"image,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
IsFiller bool `json:"isFiller,omitempty"`
|
||||
}
|
||||
|
||||
EpisodeSource struct {
|
||||
Number int `json:"number"`
|
||||
VideoSources []*VideoSource `json:"videoSources"`
|
||||
Subtitles []*Subtitle `json:"subtitles,omitempty"`
|
||||
}
|
||||
|
||||
VideoSource struct {
|
||||
Server string `json:"server"`
|
||||
Headers map[string]string `json:"headers,omitempty"`
|
||||
URL string `json:"url"`
|
||||
Quality string `json:"quality"`
|
||||
}
|
||||
|
||||
EpisodeListResponse struct {
|
||||
Episodes []*Episode `json:"episodes"`
|
||||
Media *anilist.BaseAnime `json:"media"`
|
||||
}
|
||||
|
||||
Subtitle struct {
|
||||
URL string `json:"url"`
|
||||
Language string `json:"language"`
|
||||
}
|
||||
)
|
||||
|
||||
type (
|
||||
NewRepositoryOptions struct {
|
||||
Logger *zerolog.Logger
|
||||
FileCacher *filecache.Cacher
|
||||
MetadataProvider metadata.Provider
|
||||
Platform platform.Platform
|
||||
Database *db.Database
|
||||
}
|
||||
)
|
||||
|
||||
func NewRepository(opts *NewRepositoryOptions) *Repository {
|
||||
return &Repository{
|
||||
logger: opts.Logger,
|
||||
metadataProvider: opts.MetadataProvider,
|
||||
fileCacher: opts.FileCacher,
|
||||
providerExtensionBank: extension.NewUnifiedBank(),
|
||||
anilistBaseAnimeCache: anilist.NewBaseAnimeCache(),
|
||||
platform: opts.Platform,
|
||||
db: opts.Database,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Repository) InitExtensionBank(bank *extension.UnifiedBank) {
|
||||
r.providerExtensionBank = bank
|
||||
|
||||
r.logger.Debug().Msg("onlinestream: Initialized provider extension bank")
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// getFcEpisodeDataBucket returns a episode data bucket for the provider and mediaId.
|
||||
// "Episode data" refers to the episodeData struct
|
||||
//
|
||||
// e.g., onlinestream_zoro_episode-data_123
|
||||
func (r *Repository) getFcEpisodeDataBucket(provider string, mediaId int) filecache.Bucket {
|
||||
return filecache.NewBucket("onlinestream_"+provider+"_episode-data_"+strconv.Itoa(mediaId), time.Hour*24*2)
|
||||
}
|
||||
|
||||
// getFcEpisodeListBucket returns a episode data bucket for the provider and mediaId.
|
||||
// "Episode list" refers to a slice of onlinestream_providers.EpisodeDetails
|
||||
//
|
||||
// e.g., onlinestream_zoro_episode-list_123
|
||||
func (r *Repository) getFcEpisodeListBucket(provider string, mediaId int) filecache.Bucket {
|
||||
return filecache.NewBucket("onlinestream_"+provider+"_episode-data_"+strconv.Itoa(mediaId), time.Hour*24*1)
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
func (r *Repository) getMedia(ctx context.Context, mId int) (*anilist.BaseAnime, error) {
|
||||
media, err := r.anilistBaseAnimeCache.GetOrSet(mId, func() (*anilist.BaseAnime, error) {
|
||||
media, err := r.platform.GetAnime(ctx, mId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return media, nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return media, nil
|
||||
}
|
||||
|
||||
func (r *Repository) GetMedia(ctx context.Context, mId int) (*anilist.BaseAnime, error) {
|
||||
return r.getMedia(ctx, mId)
|
||||
}
|
||||
|
||||
func (r *Repository) EmptyCache(mediaId int) error {
|
||||
_ = r.fileCacher.RemoveAllBy(func(filename string) bool {
|
||||
return strings.HasPrefix(filename, "onlinestream_") && strings.Contains(filename, strconv.Itoa(mediaId))
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Repository) GetMediaEpisodes(provider string, media *anilist.BaseAnime, dubbed bool) ([]*Episode, error) {
|
||||
episodes := make([]*Episode, 0)
|
||||
|
||||
if provider == "" {
|
||||
return episodes, nil
|
||||
}
|
||||
|
||||
// +---------------------+
|
||||
// | Animap |
|
||||
// +---------------------+
|
||||
|
||||
//animeMetadata, err := r.metadataProvider.GetAnimeMetadata(metadata.AnilistPlatform, mId)
|
||||
// //foundAnimeMetadata := err == nil && animeMetadata != nil
|
||||
//aw := r.metadataProvider.GetAnimeMetadataWrapper(media, animeMetadata)
|
||||
|
||||
episodeCollection, err := anime.NewEpisodeCollection(anime.NewEpisodeCollectionOptions{
|
||||
AnimeMetadata: nil,
|
||||
Media: media,
|
||||
MetadataProvider: r.metadataProvider,
|
||||
Logger: r.logger,
|
||||
})
|
||||
foundEpisodeCollection := err == nil && episodeCollection != nil
|
||||
|
||||
// +---------------------+
|
||||
// | Episode list |
|
||||
// +---------------------+
|
||||
|
||||
// Fetch the episode list from the provider
|
||||
// "from" and "to" are set to 0 in order not to fetch episode servers
|
||||
ec, err := r.getEpisodeContainer(provider, media, 0, 0, dubbed, media.GetStartYearSafe())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, episodeDetails := range ec.ProviderEpisodeList {
|
||||
|
||||
// If the title contains "[{", it means it's an episode part (e.g. "Episode 6 [{6.5}]", the episode number should be 6)
|
||||
if strings.Contains(episodeDetails.Title, "[{") {
|
||||
ep := strings.Split(episodeDetails.Title, "[{")[1]
|
||||
ep = strings.Split(ep, "}]")[0]
|
||||
episodes = append(episodes, &Episode{
|
||||
Number: episodeDetails.Number,
|
||||
Title: fmt.Sprintf("Episode %s", ep),
|
||||
Image: media.GetBannerImageSafe(),
|
||||
Description: "",
|
||||
IsFiller: false,
|
||||
})
|
||||
|
||||
} else {
|
||||
|
||||
if foundEpisodeCollection {
|
||||
episode, found := episodeCollection.FindEpisodeByNumber(episodeDetails.Number)
|
||||
if found {
|
||||
episodes = append(episodes, &Episode{
|
||||
Number: episodeDetails.Number,
|
||||
Title: episode.EpisodeTitle,
|
||||
Image: episode.EpisodeMetadata.Image,
|
||||
Description: episode.EpisodeMetadata.Summary,
|
||||
IsFiller: episode.EpisodeMetadata.IsFiller,
|
||||
})
|
||||
} else {
|
||||
episodes = append(episodes, &Episode{
|
||||
Number: episodeDetails.Number,
|
||||
Title: episodeDetails.Title,
|
||||
Image: media.GetCoverImageSafe(),
|
||||
})
|
||||
}
|
||||
} else {
|
||||
episodes = append(episodes, &Episode{
|
||||
Number: episodeDetails.Number,
|
||||
Title: episodeDetails.Title,
|
||||
Image: media.GetCoverImageSafe(),
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
episodes = lo.Filter(episodes, func(item *Episode, index int) bool {
|
||||
return item != nil
|
||||
})
|
||||
|
||||
return episodes, nil
|
||||
}
|
||||
|
||||
func (r *Repository) GetEpisodeSources(ctx context.Context, provider string, mId int, number int, dubbed bool, year int) (*EpisodeSource, error) {
|
||||
|
||||
// +---------------------+
|
||||
// | Media |
|
||||
// +---------------------+
|
||||
|
||||
media, err := r.getMedia(ctx, mId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// +---------------------+
|
||||
// | Episode servers |
|
||||
// +---------------------+
|
||||
|
||||
ec, err := r.getEpisodeContainer(provider, media, number, number, dubbed, year)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var sources *EpisodeSource
|
||||
for _, ep := range ec.Episodes {
|
||||
if ep.Number == number {
|
||||
s := &EpisodeSource{
|
||||
Number: ep.Number,
|
||||
VideoSources: make([]*VideoSource, 0),
|
||||
}
|
||||
for _, es := range ep.Servers {
|
||||
|
||||
for _, vs := range es.VideoSources {
|
||||
s.VideoSources = append(s.VideoSources, &VideoSource{
|
||||
Server: es.Server,
|
||||
Headers: es.Headers,
|
||||
URL: vs.URL,
|
||||
Quality: vs.Quality,
|
||||
})
|
||||
// Add subtitles if available
|
||||
// Subtitles are stored in each video source, but they are the same, so only add them once.
|
||||
if len(vs.Subtitles) > 0 && s.Subtitles == nil {
|
||||
s.Subtitles = make([]*Subtitle, 0, len(vs.Subtitles))
|
||||
for _, sub := range vs.Subtitles {
|
||||
s.Subtitles = append(s.Subtitles, &Subtitle{
|
||||
URL: sub.URL,
|
||||
Language: sub.Language,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sources = s
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if sources == nil {
|
||||
return nil, ErrNoVideoSourceFound
|
||||
}
|
||||
|
||||
return sources, nil
|
||||
}
|
||||
Reference in New Issue
Block a user