feat: use real metadata for fallback episodes
This commit is contained in:
@@ -108,9 +108,9 @@ type searchResult struct {
|
||||
}
|
||||
|
||||
type AvailableEpisodes struct {
|
||||
Sub int
|
||||
Dub int
|
||||
Raw int
|
||||
Sub []string
|
||||
Dub []string
|
||||
Raw []string
|
||||
}
|
||||
|
||||
type allAnimeClient struct {
|
||||
@@ -497,6 +497,7 @@ func (c *allAnimeClient) GetAvailableEpisodes(ctx context.Context, showID string
|
||||
graphqlQuery := `query($showId: String!) {
|
||||
show(_id: $showId) {
|
||||
availableEpisodesDetail
|
||||
lastEpisodeInfo
|
||||
}
|
||||
}`
|
||||
|
||||
@@ -522,18 +523,69 @@ func (c *allAnimeClient) GetAvailableEpisodes(ctx context.Context, showID string
|
||||
|
||||
var count AvailableEpisodes
|
||||
if sub, ok := detail["sub"].([]any); ok {
|
||||
count.Sub = len(sub)
|
||||
for _, s := range sub {
|
||||
if str, ok := s.(string); ok {
|
||||
count.Sub = append(count.Sub, str)
|
||||
}
|
||||
}
|
||||
}
|
||||
if dub, ok := detail["dub"].([]any); ok {
|
||||
count.Dub = len(dub)
|
||||
for _, s := range dub {
|
||||
if str, ok := s.(string); ok {
|
||||
count.Dub = append(count.Dub, str)
|
||||
}
|
||||
}
|
||||
}
|
||||
if raw, ok := detail["raw"].([]any); ok {
|
||||
count.Raw = len(raw)
|
||||
for _, s := range raw {
|
||||
if str, ok := s.(string); ok {
|
||||
count.Raw = append(count.Raw, str)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func (c *allAnimeClient) GetEpisodeMetadata(ctx context.Context, showID string, episode string) (map[string]any, error) {
|
||||
// First try to get it from the standard episode query which often contains metadata
|
||||
// but we'll use a specific query that includes images and titles if available
|
||||
graphqlQuery := `query($showId: String!, $episodeString: String!, $translationType: VaildTranslationTypeEnumType!) {
|
||||
episode(showId: $showId, episodeString: $episodeString, translationType: $translationType) {
|
||||
notes
|
||||
episodeInfo {
|
||||
notes
|
||||
thumbnails
|
||||
vidinfors {
|
||||
vidPath
|
||||
}
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
// We'll try SUB by default for metadata
|
||||
result, err := c.graphqlRequest(ctx, graphqlQuery, map[string]any{
|
||||
"showId": showID,
|
||||
"episodeString": episode,
|
||||
"translationType": "sub",
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data, ok := result["data"].(map[string]any)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid response")
|
||||
}
|
||||
|
||||
ep, ok := data["episode"].(map[string]any)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("episode not found")
|
||||
}
|
||||
|
||||
return ep, nil
|
||||
}
|
||||
|
||||
func buildStreamSource(url, sourceType, provider string) StreamSource {
|
||||
return StreamSource{
|
||||
URL: url,
|
||||
|
||||
@@ -118,17 +118,44 @@ func (h *Handler) HandleWatchPage(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
if maxCount > len(episodes.Data) {
|
||||
// Add dummy episodes for the ones Jikan is missing
|
||||
// Fetch metadata for the missing episodes
|
||||
start := len(episodes.Data) + 1
|
||||
for i := start; i <= maxCount; i++ {
|
||||
dummy := jikan.Episode{
|
||||
epStr := strconv.Itoa(i)
|
||||
meta, err := h.svc.GetEpisodeMetadata(r.Context(), id, epStr)
|
||||
|
||||
title := fmt.Sprintf("Episode %d", i)
|
||||
imgURL := ""
|
||||
|
||||
if err == nil && meta != nil {
|
||||
if info, ok := meta["episodeInfo"].(map[string]any); ok {
|
||||
if thumbs, ok := info["thumbnails"].([]any); ok && len(thumbs) > 0 {
|
||||
if firstThumb, ok := thumbs[0].(string); ok {
|
||||
imgURL = firstThumb
|
||||
}
|
||||
}
|
||||
}
|
||||
if notes, ok := meta["notes"].(string); ok && notes != "" {
|
||||
title = notes
|
||||
}
|
||||
}
|
||||
|
||||
if imgURL == "" {
|
||||
// Last resort fallback
|
||||
tmpEp := jikan.Episode{MalID: i}
|
||||
imgURL = tmpEp.GetFallbackImage(id)
|
||||
}
|
||||
|
||||
episodes.Data = append(episodes.Data, jikan.Episode{
|
||||
MalID: i,
|
||||
Episode: fmt.Sprintf("Episode %d", i),
|
||||
Title: fmt.Sprintf("Episode %d", i),
|
||||
Images: &jikan.EpisodeImages{},
|
||||
}
|
||||
dummy.Images.Jpg.ImageURL = dummy.GetFallbackImage(id)
|
||||
episodes.Data = append(episodes.Data, dummy)
|
||||
Title: title,
|
||||
Images: &jikan.EpisodeImages{
|
||||
Jpg: struct {
|
||||
ImageURL string `json:"image_url"`
|
||||
}{ImageURL: imgURL},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,9 +143,9 @@ func (s *Service) BuildWatchPageData(ctx context.Context, malID int, titleCandid
|
||||
|
||||
fallbackEpisodes := make(map[string]int)
|
||||
if counts, err := s.allAnimeClient.GetAvailableEpisodes(ctx, showID); err == nil {
|
||||
fallbackEpisodes["sub"] = counts.Sub
|
||||
fallbackEpisodes["dub"] = counts.Dub
|
||||
fallbackEpisodes["raw"] = counts.Raw
|
||||
fallbackEpisodes["sub"] = len(counts.Sub)
|
||||
fallbackEpisodes["dub"] = len(counts.Dub)
|
||||
fallbackEpisodes["raw"] = len(counts.Raw)
|
||||
}
|
||||
|
||||
watchTitle := strings.TrimSpace(resolvedTitle)
|
||||
@@ -360,6 +360,14 @@ func clonePlaybackBaseData(data playbackBaseData) playbackBaseData {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) GetEpisodeMetadata(ctx context.Context, malID int, episode string) (map[string]any, error) {
|
||||
showID, _, err := s.resolveShowCached(ctx, malID, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.allAnimeClient.GetEpisodeMetadata(ctx, showID, episode)
|
||||
}
|
||||
|
||||
func cloneSlice[T any](items []T) []T {
|
||||
if items == nil {
|
||||
return []T{}
|
||||
|
||||
Reference in New Issue
Block a user