node build fixed
This commit is contained in:
156
seanime-2.9.10/internal/api/anizip/anizip.go
Normal file
156
seanime-2.9.10/internal/api/anizip/anizip.go
Normal file
@@ -0,0 +1,156 @@
|
||||
package anizip
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"seanime/internal/hook"
|
||||
"seanime/internal/util/result"
|
||||
"strconv"
|
||||
|
||||
"github.com/goccy/go-json"
|
||||
)
|
||||
|
||||
// AniZip is the API used for fetching anime metadata and mappings.
|
||||
|
||||
type (
|
||||
Episode struct {
|
||||
TvdbEid int `json:"tvdbEid,omitempty"`
|
||||
AirDate string `json:"airdate,omitempty"`
|
||||
SeasonNumber int `json:"seasonNumber,omitempty"`
|
||||
EpisodeNumber int `json:"episodeNumber,omitempty"`
|
||||
AbsoluteEpisodeNumber int `json:"absoluteEpisodeNumber,omitempty"`
|
||||
Title map[string]string `json:"title,omitempty"`
|
||||
Image string `json:"image,omitempty"`
|
||||
Summary string `json:"summary,omitempty"`
|
||||
Overview string `json:"overview,omitempty"`
|
||||
Runtime int `json:"runtime,omitempty"`
|
||||
Length int `json:"length,omitempty"`
|
||||
Episode string `json:"episode,omitempty"`
|
||||
AnidbEid int `json:"anidbEid,omitempty"`
|
||||
Rating string `json:"rating,omitempty"`
|
||||
}
|
||||
|
||||
Mappings struct {
|
||||
AnimeplanetID string `json:"animeplanet_id,omitempty"`
|
||||
KitsuID int `json:"kitsu_id,omitempty"`
|
||||
MalID int `json:"mal_id,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
AnilistID int `json:"anilist_id,omitempty"`
|
||||
AnisearchID int `json:"anisearch_id,omitempty"`
|
||||
AnidbID int `json:"anidb_id,omitempty"`
|
||||
NotifymoeID string `json:"notifymoe_id,omitempty"`
|
||||
LivechartID int `json:"livechart_id,omitempty"`
|
||||
ThetvdbID int `json:"thetvdb_id,omitempty"`
|
||||
ImdbID string `json:"imdb_id,omitempty"`
|
||||
ThemoviedbID string `json:"themoviedb_id,omitempty"`
|
||||
}
|
||||
|
||||
Media struct {
|
||||
Titles map[string]string `json:"titles"`
|
||||
Episodes map[string]Episode `json:"episodes"`
|
||||
EpisodeCount int `json:"episodeCount"`
|
||||
SpecialCount int `json:"specialCount"`
|
||||
Mappings *Mappings `json:"mappings"`
|
||||
}
|
||||
)
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
type Cache struct {
|
||||
*result.Cache[string, *Media]
|
||||
}
|
||||
|
||||
func NewCache() *Cache {
|
||||
return &Cache{result.NewCache[string, *Media]()}
|
||||
}
|
||||
|
||||
func GetCacheKey(from string, id int) string {
|
||||
return from + strconv.Itoa(id)
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// FetchAniZipMedia fetches anizip.Media from the AniZip API.
|
||||
func FetchAniZipMedia(from string, id int) (*Media, error) {
|
||||
|
||||
// Event
|
||||
reqEvent := &AnizipMediaRequestedEvent{
|
||||
From: from,
|
||||
Id: id,
|
||||
Media: &Media{},
|
||||
}
|
||||
err := hook.GlobalHookManager.OnAnizipMediaRequested().Trigger(reqEvent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If the hook prevented the default behavior, return the data
|
||||
if reqEvent.DefaultPrevented {
|
||||
return reqEvent.Media, nil
|
||||
}
|
||||
|
||||
from = reqEvent.From
|
||||
id = reqEvent.Id
|
||||
|
||||
apiUrl := "https://api.ani.zip/v1/episodes?" + from + "_id=" + strconv.Itoa(id)
|
||||
|
||||
// Send an HTTP GET request
|
||||
response, err := http.Get(apiUrl)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
|
||||
if response.StatusCode != 200 {
|
||||
return nil, errors.New("not found on AniZip")
|
||||
}
|
||||
|
||||
// Read the response body
|
||||
responseBody, err := io.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Unmarshal the JSON data into AniZipData
|
||||
var media Media
|
||||
if err := json.Unmarshal(responseBody, &media); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Event
|
||||
event := &AnizipMediaEvent{
|
||||
Media: &media,
|
||||
}
|
||||
err = hook.GlobalHookManager.OnAnizipMedia().Trigger(event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If the hook prevented the default behavior, return the data
|
||||
if event.DefaultPrevented {
|
||||
return event.Media, nil
|
||||
}
|
||||
|
||||
return event.Media, nil
|
||||
}
|
||||
|
||||
// FetchAniZipMediaC is the same as FetchAniZipMedia but uses a cache.
|
||||
// If the media is found in the cache, it will be returned.
|
||||
// If the media is not found in the cache, it will be fetched and then added to the cache.
|
||||
func FetchAniZipMediaC(from string, id int, cache *Cache) (*Media, error) {
|
||||
|
||||
cacheV, ok := cache.Get(GetCacheKey(from, id))
|
||||
if ok {
|
||||
return cacheV, nil
|
||||
}
|
||||
|
||||
media, err := FetchAniZipMedia(from, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cache.Set(GetCacheKey(from, id), media)
|
||||
|
||||
return media, nil
|
||||
}
|
||||
65
seanime-2.9.10/internal/api/anizip/anizip_helper.go
Normal file
65
seanime-2.9.10/internal/api/anizip/anizip_helper.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package anizip
|
||||
|
||||
func (m *Media) GetTitle() string {
|
||||
if m == nil {
|
||||
return ""
|
||||
}
|
||||
if len(m.Titles["en"]) > 0 {
|
||||
return m.Titles["en"]
|
||||
}
|
||||
return m.Titles["ro"]
|
||||
}
|
||||
|
||||
func (m *Media) GetMappings() *Mappings {
|
||||
if m == nil {
|
||||
return &Mappings{}
|
||||
}
|
||||
return m.Mappings
|
||||
}
|
||||
|
||||
func (m *Media) FindEpisode(ep string) (*Episode, bool) {
|
||||
if m.Episodes == nil {
|
||||
return nil, false
|
||||
}
|
||||
episode, found := m.Episodes[ep]
|
||||
if !found {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
return &episode, true
|
||||
}
|
||||
|
||||
func (m *Media) GetMainEpisodeCount() int {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
return m.EpisodeCount
|
||||
}
|
||||
|
||||
// GetOffset returns the offset of the first episode relative to the absolute episode number.
|
||||
// e.g, if the first episode's absolute number is 13, then the offset is 12.
|
||||
func (m *Media) GetOffset() int {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
firstEp, found := m.FindEpisode("1")
|
||||
if !found {
|
||||
return 0
|
||||
}
|
||||
if firstEp.AbsoluteEpisodeNumber == 0 {
|
||||
return 0
|
||||
}
|
||||
return firstEp.AbsoluteEpisodeNumber - 1
|
||||
}
|
||||
|
||||
func (e *Episode) GetTitle() string {
|
||||
eng, ok := e.Title["en"]
|
||||
if ok {
|
||||
return eng
|
||||
}
|
||||
rom, ok := e.Title["x-jat"]
|
||||
if ok {
|
||||
return rom
|
||||
}
|
||||
return ""
|
||||
}
|
||||
37
seanime-2.9.10/internal/api/anizip/anizip_test.go
Normal file
37
seanime-2.9.10/internal/api/anizip/anizip_test.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package anizip
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFetchAniZipMedia(t *testing.T) {
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
provider string
|
||||
id int
|
||||
expectedTitle string
|
||||
}{
|
||||
{
|
||||
name: "Cowboy Bebop",
|
||||
provider: "anilist",
|
||||
id: 1,
|
||||
expectedTitle: "Cowboy Bebop",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
media, err := FetchAniZipMedia(test.provider, test.id)
|
||||
if assert.NoError(t, err) {
|
||||
if assert.NotNil(t, media) {
|
||||
assert.Equal(t, media.GetTitle(), test.expectedTitle)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
19
seanime-2.9.10/internal/api/anizip/hook_events.go
Normal file
19
seanime-2.9.10/internal/api/anizip/hook_events.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package anizip
|
||||
|
||||
import "seanime/internal/hook_resolver"
|
||||
|
||||
// AnizipMediaRequestedEvent is triggered when the AniZip media is requested.
|
||||
// Prevent default to skip the default behavior and return your own data.
|
||||
type AnizipMediaRequestedEvent struct {
|
||||
hook_resolver.Event
|
||||
From string `json:"from"`
|
||||
Id int `json:"id"`
|
||||
// Empty data object, will be used if the hook prevents the default behavior
|
||||
Media *Media `json:"media"`
|
||||
}
|
||||
|
||||
// AnizipMediaEvent is triggered after processing AnizipMedia.
|
||||
type AnizipMediaEvent struct {
|
||||
hook_resolver.Event
|
||||
Media *Media `json:"media"`
|
||||
}
|
||||
Reference in New Issue
Block a user