feat: use real metadata for fallback episodes
This commit is contained in:
@@ -108,9 +108,9 @@ type searchResult struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type AvailableEpisodes struct {
|
type AvailableEpisodes struct {
|
||||||
Sub int
|
Sub []string
|
||||||
Dub int
|
Dub []string
|
||||||
Raw int
|
Raw []string
|
||||||
}
|
}
|
||||||
|
|
||||||
type allAnimeClient struct {
|
type allAnimeClient struct {
|
||||||
@@ -497,6 +497,7 @@ func (c *allAnimeClient) GetAvailableEpisodes(ctx context.Context, showID string
|
|||||||
graphqlQuery := `query($showId: String!) {
|
graphqlQuery := `query($showId: String!) {
|
||||||
show(_id: $showId) {
|
show(_id: $showId) {
|
||||||
availableEpisodesDetail
|
availableEpisodesDetail
|
||||||
|
lastEpisodeInfo
|
||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
|
|
||||||
@@ -522,18 +523,69 @@ func (c *allAnimeClient) GetAvailableEpisodes(ctx context.Context, showID string
|
|||||||
|
|
||||||
var count AvailableEpisodes
|
var count AvailableEpisodes
|
||||||
if sub, ok := detail["sub"].([]any); ok {
|
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 {
|
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 {
|
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
|
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 {
|
func buildStreamSource(url, sourceType, provider string) StreamSource {
|
||||||
return StreamSource{
|
return StreamSource{
|
||||||
URL: url,
|
URL: url,
|
||||||
|
|||||||
@@ -118,17 +118,44 @@ func (h *Handler) HandleWatchPage(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if maxCount > len(episodes.Data) {
|
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
|
start := len(episodes.Data) + 1
|
||||||
for i := start; i <= maxCount; i++ {
|
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,
|
MalID: i,
|
||||||
Episode: fmt.Sprintf("Episode %d", i),
|
Episode: fmt.Sprintf("Episode %d", i),
|
||||||
Title: fmt.Sprintf("Episode %d", i),
|
Title: title,
|
||||||
Images: &jikan.EpisodeImages{},
|
Images: &jikan.EpisodeImages{
|
||||||
}
|
Jpg: struct {
|
||||||
dummy.Images.Jpg.ImageURL = dummy.GetFallbackImage(id)
|
ImageURL string `json:"image_url"`
|
||||||
episodes.Data = append(episodes.Data, dummy)
|
}{ImageURL: imgURL},
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -143,9 +143,9 @@ func (s *Service) BuildWatchPageData(ctx context.Context, malID int, titleCandid
|
|||||||
|
|
||||||
fallbackEpisodes := make(map[string]int)
|
fallbackEpisodes := make(map[string]int)
|
||||||
if counts, err := s.allAnimeClient.GetAvailableEpisodes(ctx, showID); err == nil {
|
if counts, err := s.allAnimeClient.GetAvailableEpisodes(ctx, showID); err == nil {
|
||||||
fallbackEpisodes["sub"] = counts.Sub
|
fallbackEpisodes["sub"] = len(counts.Sub)
|
||||||
fallbackEpisodes["dub"] = counts.Dub
|
fallbackEpisodes["dub"] = len(counts.Dub)
|
||||||
fallbackEpisodes["raw"] = counts.Raw
|
fallbackEpisodes["raw"] = len(counts.Raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
watchTitle := strings.TrimSpace(resolvedTitle)
|
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 {
|
func cloneSlice[T any](items []T) []T {
|
||||||
if items == nil {
|
if items == nil {
|
||||||
return []T{}
|
return []T{}
|
||||||
|
|||||||
Reference in New Issue
Block a user