feat: show release info on anime detail page
This commit is contained in:
@@ -10,6 +10,7 @@ import (
|
|||||||
"mal/internal/server"
|
"mal/internal/server"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@@ -27,15 +28,10 @@ type animeEpisodeCountDisplay struct {
|
|||||||
Label string
|
Label string
|
||||||
}
|
}
|
||||||
|
|
||||||
func listedEpisodeCount(episodes []domain.EpisodeData) int {
|
type animeReleaseInfoDisplay struct {
|
||||||
count := 0
|
Count int
|
||||||
for _, episode := range episodes {
|
Label string
|
||||||
if episode.MalID <= 0 || episode.IsRecap {
|
Status string
|
||||||
continue
|
|
||||||
}
|
|
||||||
count++
|
|
||||||
}
|
|
||||||
return count
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func releasedEpisodeCount(anime domain.Anime, now time.Time) int {
|
func releasedEpisodeCount(anime domain.Anime, now time.Time) int {
|
||||||
@@ -56,15 +52,18 @@ func releasedEpisodeCount(anime domain.Anime, now time.Time) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *AnimeHandler) animeEpisodeCount(ctx context.Context, anime domain.Anime, now time.Time) animeEpisodeCountDisplay {
|
func (h *AnimeHandler) animeEpisodeCount(ctx context.Context, anime domain.Anime, now time.Time) animeEpisodeCountDisplay {
|
||||||
|
info := h.animeReleaseInfo(ctx, anime, now)
|
||||||
|
return animeEpisodeCountDisplay{Count: info.Count, Label: info.Label}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *AnimeHandler) animeReleaseInfo(ctx context.Context, anime domain.Anime, now time.Time) animeReleaseInfoDisplay {
|
||||||
if h.episodeSvc != nil {
|
if h.episodeSvc != nil {
|
||||||
episodeCtx, cancel := context.WithTimeout(ctx, episodeCountTimeout)
|
episodeCtx, cancel := context.WithTimeout(ctx, episodeCountTimeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
episodeList, err := h.episodeSvc.GetCanonicalEpisodes(episodeCtx, anime, false)
|
episodeList, err := h.episodeSvc.GetCanonicalEpisodes(episodeCtx, anime, false)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if count := len(episodeList.Episodes); count > 0 {
|
return releaseInfoFromCanonical(anime, episodeList)
|
||||||
return animeEpisodeCountDisplay{Count: count, Label: "Available episodes"}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
observability.Warn(
|
observability.Warn(
|
||||||
"anime_episode_availability_count_fetch_failed",
|
"anime_episode_availability_count_fetch_failed",
|
||||||
@@ -78,45 +77,63 @@ func (h *AnimeHandler) animeEpisodeCount(ctx context.Context, anime domain.Anime
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if h.svc != nil && anime.Airing {
|
return animeInitialReleaseInfo(anime, now)
|
||||||
episodeCtx, cancel := context.WithTimeout(ctx, episodeCountTimeout)
|
}
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
episodes, err := h.svc.GetAllEpisodes(episodeCtx, anime.MalID)
|
func releaseInfoFromCanonical(anime domain.Anime, episodeList domain.CanonicalEpisodeList) animeReleaseInfoDisplay {
|
||||||
if err == nil {
|
info := animeReleaseInfoDisplay{Status: trustedAnimeStatus(anime, len(episodeList.Episodes))}
|
||||||
if count := listedEpisodeCount(episodes); count > 0 {
|
if count := len(episodeList.Episodes); count > 0 {
|
||||||
return animeEpisodeCountDisplay{Count: count, Label: "Listed episodes"}
|
info.Count = count
|
||||||
}
|
info.Label = canonicalEpisodeCountLabel(episodeList.Source)
|
||||||
} else {
|
}
|
||||||
observability.Warn(
|
return info
|
||||||
"anime_episode_count_fetch_failed",
|
}
|
||||||
"anime",
|
|
||||||
"",
|
func canonicalEpisodeCountLabel(source string) string {
|
||||||
map[string]any{
|
if source == "jikan_fallback" || source == "legacy_disabled" {
|
||||||
"anime_id": anime.MalID,
|
return "Estimated aired episodes"
|
||||||
},
|
}
|
||||||
err,
|
return "Available episodes"
|
||||||
)
|
}
|
||||||
}
|
|
||||||
|
func animeInitialReleaseInfo(anime domain.Anime, now time.Time) animeReleaseInfoDisplay {
|
||||||
|
if isCurrentlyAiring(anime) {
|
||||||
|
return animeReleaseInfoDisplay{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
info := animeReleaseInfoDisplay{Status: strings.TrimSpace(anime.Status)}
|
||||||
if anime.Episodes > 0 {
|
if anime.Episodes > 0 {
|
||||||
return animeEpisodeCountDisplay{Count: anime.Episodes, Label: "Total episodes"}
|
info.Count = anime.Episodes
|
||||||
|
info.Label = "Total episodes"
|
||||||
|
return info
|
||||||
}
|
}
|
||||||
if count := releasedEpisodeCount(anime, now); count > 0 {
|
if count := releasedEpisodeCount(anime, now); count > 0 {
|
||||||
return animeEpisodeCountDisplay{Count: count, Label: "Estimated aired episodes"}
|
info.Count = count
|
||||||
|
info.Label = "Estimated aired episodes"
|
||||||
}
|
}
|
||||||
return animeEpisodeCountDisplay{}
|
return info
|
||||||
}
|
}
|
||||||
|
|
||||||
func animeInitialEpisodeCount(anime domain.Anime, now time.Time) animeEpisodeCountDisplay {
|
func animeInitialEpisodeCount(anime domain.Anime, now time.Time) animeEpisodeCountDisplay {
|
||||||
if anime.Episodes > 0 {
|
info := animeInitialReleaseInfo(anime, now)
|
||||||
return animeEpisodeCountDisplay{Count: anime.Episodes, Label: "Total episodes"}
|
return animeEpisodeCountDisplay{Count: info.Count, Label: info.Label}
|
||||||
|
}
|
||||||
|
|
||||||
|
func trustedAnimeStatus(anime domain.Anime, canonicalEpisodes int) string {
|
||||||
|
if canonicalEpisodes == 0 && isCurrentlyAiring(anime) {
|
||||||
|
return "Not yet aired"
|
||||||
}
|
}
|
||||||
if count := releasedEpisodeCount(anime, now); count > 0 {
|
if status := strings.TrimSpace(anime.Status); status != "" {
|
||||||
return animeEpisodeCountDisplay{Count: count, Label: "Estimated aired episodes"}
|
return status
|
||||||
}
|
}
|
||||||
return animeEpisodeCountDisplay{}
|
if anime.Airing {
|
||||||
|
return "Currently Airing"
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func isCurrentlyAiring(anime domain.Anime) bool {
|
||||||
|
return anime.Airing || strings.EqualFold(strings.TrimSpace(anime.Status), "Currently Airing")
|
||||||
}
|
}
|
||||||
|
|
||||||
func animeAudioAvailabilityLabel(episodes []domain.CanonicalEpisode) string {
|
func animeAudioAvailabilityLabel(episodes []domain.CanonicalEpisode) string {
|
||||||
@@ -203,7 +220,7 @@ func (h *AnimeHandler) HandleAnimeDetails(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
episodesCount := animeInitialEpisodeCount(anime, time.Now())
|
releaseInfo := animeInitialReleaseInfo(anime, time.Now())
|
||||||
|
|
||||||
c.HTML(http.StatusOK, "anime.gohtml", gin.H{
|
c.HTML(http.StatusOK, "anime.gohtml", gin.H{
|
||||||
"Anime": anime,
|
"Anime": anime,
|
||||||
@@ -213,8 +230,7 @@ func (h *AnimeHandler) HandleAnimeDetails(c *gin.Context) {
|
|||||||
"WatchlistIDs": watchlistIDs,
|
"WatchlistIDs": watchlistIDs,
|
||||||
"ContinueWatchingEp": ep,
|
"ContinueWatchingEp": ep,
|
||||||
"ContinueWatchingTime": cwSeconds,
|
"ContinueWatchingTime": cwSeconds,
|
||||||
"EpisodesCount": episodesCount.Count,
|
"ReleaseInfo": releaseInfo,
|
||||||
"EpisodesCountLabel": episodesCount.Label,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,12 +281,12 @@ func (h *AnimeHandler) loadAnimeDetailsSection(ctx context.Context, id int, sect
|
|||||||
case "statistics":
|
case "statistics":
|
||||||
data, err := h.svc.GetStatistics(ctx, id)
|
data, err := h.svc.GetStatistics(ctx, id)
|
||||||
return data, "anime_statistics", err
|
return data, "anime_statistics", err
|
||||||
case "episode-count":
|
case "episode-count", "release-info":
|
||||||
anime, err := h.svc.GetAnimeByID(ctx, id)
|
anime, err := h.svc.GetAnimeByID(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
return h.animeEpisodeCount(ctx, anime, time.Now()), "anime_episode_count", nil
|
return h.animeReleaseInfo(ctx, anime, time.Now()), "anime_release_info", nil
|
||||||
case "audio-availability":
|
case "audio-availability":
|
||||||
anime, err := h.svc.GetAnimeByID(ctx, id)
|
anime, err := h.svc.GetAnimeByID(ctx, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -115,20 +115,6 @@ func TestReleasedEpisodeCount(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestListedEpisodeCount(t *testing.T) {
|
|
||||||
episodes := []domain.EpisodeData{
|
|
||||||
{MalID: 1, Title: "Episode 1"},
|
|
||||||
{MalID: 2, Title: "Episode 2"},
|
|
||||||
{MalID: 3, Title: "Recap", IsRecap: true},
|
|
||||||
{Title: "missing id"},
|
|
||||||
}
|
|
||||||
|
|
||||||
got := listedEpisodeCount(episodes)
|
|
||||||
if got != 2 {
|
|
||||||
t.Fatalf("listedEpisodeCount() = %d, want 2", got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAnimeEpisodeCountUsesCanonicalEpisodes(t *testing.T) {
|
func TestAnimeEpisodeCountUsesCanonicalEpisodes(t *testing.T) {
|
||||||
episodeSvc := &stubEpisodeService{
|
episodeSvc := &stubEpisodeService{
|
||||||
episodes: domain.CanonicalEpisodeList{
|
episodes: domain.CanonicalEpisodeList{
|
||||||
@@ -160,6 +146,117 @@ func TestAnimeEpisodeCountUsesCanonicalEpisodes(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAnimeReleaseInfoUsesCanonicalEpisodes(t *testing.T) {
|
||||||
|
episodeSvc := &stubEpisodeService{
|
||||||
|
episodes: domain.CanonicalEpisodeList{
|
||||||
|
Source: "AllAnime",
|
||||||
|
Episodes: []domain.CanonicalEpisode{
|
||||||
|
{Number: 1},
|
||||||
|
{Number: 2},
|
||||||
|
{Number: 3},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
handler := NewAnimeHandler(nil, nil, episodeSvc, nil)
|
||||||
|
|
||||||
|
got := handler.animeReleaseInfo(context.Background(), domain.Anime{Anime: jikan.Anime{
|
||||||
|
MalID: 59970,
|
||||||
|
Status: "Currently Airing",
|
||||||
|
Airing: true,
|
||||||
|
Episodes: 12,
|
||||||
|
}}, time.Date(2026, time.July, 1, 12, 0, 0, 0, time.UTC))
|
||||||
|
|
||||||
|
if got.Count != 3 || got.Label != "Available episodes" || got.Status != "Currently Airing" {
|
||||||
|
t.Fatalf("animeReleaseInfo() = %+v, want 3 available episodes and current status", got)
|
||||||
|
}
|
||||||
|
if episodeSvc.called != 1 {
|
||||||
|
t.Fatalf("GetCanonicalEpisodes() calls = %d, want 1", episodeSvc.called)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAnimeReleaseInfoDoesNotCallJikanFallbackAvailable(t *testing.T) {
|
||||||
|
episodeSvc := &stubEpisodeService{
|
||||||
|
episodes: domain.CanonicalEpisodeList{
|
||||||
|
Source: "jikan_fallback",
|
||||||
|
Episodes: []domain.CanonicalEpisode{
|
||||||
|
{Number: 1},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
handler := NewAnimeHandler(nil, nil, episodeSvc, nil)
|
||||||
|
|
||||||
|
got := handler.animeReleaseInfo(context.Background(), domain.Anime{Anime: jikan.Anime{
|
||||||
|
MalID: 62076,
|
||||||
|
Status: "Currently Airing",
|
||||||
|
Airing: true,
|
||||||
|
}}, time.Date(2026, time.July, 10, 12, 0, 0, 0, time.UTC))
|
||||||
|
|
||||||
|
if got.Count != 1 || got.Label != "Estimated aired episodes" {
|
||||||
|
t.Fatalf("animeReleaseInfo() = %+v, want estimated aired episode count", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAnimeReleaseInfoMarksAiringAnimeWithoutCanonicalEpisodesAsNotYetAired(t *testing.T) {
|
||||||
|
episodeSvc := &stubEpisodeService{
|
||||||
|
episodes: domain.CanonicalEpisodeList{
|
||||||
|
Source: "jikan_fallback",
|
||||||
|
ReleaseChecked: true,
|
||||||
|
Episodes: []domain.CanonicalEpisode{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
handler := NewAnimeHandler(nil, nil, episodeSvc, nil)
|
||||||
|
|
||||||
|
got := handler.animeReleaseInfo(context.Background(), domain.Anime{Anime: jikan.Anime{
|
||||||
|
MalID: 62076,
|
||||||
|
Status: "Currently Airing",
|
||||||
|
Airing: true,
|
||||||
|
Episodes: 6,
|
||||||
|
Aired: jikan.Aired{From: "2026-06-03T00:00:00+00:00"},
|
||||||
|
}}, time.Date(2026, time.July, 1, 12, 0, 0, 0, time.UTC))
|
||||||
|
|
||||||
|
if got.Count != 0 || got.Label != "" || got.Status != "Not yet aired" {
|
||||||
|
t.Fatalf("animeReleaseInfo() = %+v, want not-yet-aired status without count", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAnimeEpisodeCountStopsWhenCanonicalEpisodesAreEmpty(t *testing.T) {
|
||||||
|
episodeSvc := &stubEpisodeService{
|
||||||
|
episodes: domain.CanonicalEpisodeList{
|
||||||
|
Source: "AllAnime",
|
||||||
|
Episodes: []domain.CanonicalEpisode{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
handler := NewAnimeHandler(nil, nil, episodeSvc, nil)
|
||||||
|
|
||||||
|
got := handler.animeEpisodeCount(context.Background(), domain.Anime{Anime: jikan.Anime{
|
||||||
|
MalID: 62076,
|
||||||
|
Airing: true,
|
||||||
|
Episodes: 12,
|
||||||
|
Aired: jikan.Aired{From: "2026-06-03T00:00:00+00:00"},
|
||||||
|
}}, time.Date(2026, time.July, 1, 12, 0, 0, 0, time.UTC))
|
||||||
|
|
||||||
|
if got.Count != 0 || got.Label != "" {
|
||||||
|
t.Fatalf("animeEpisodeCount() = %+v, want empty display", got)
|
||||||
|
}
|
||||||
|
if episodeSvc.called != 1 {
|
||||||
|
t.Fatalf("GetCanonicalEpisodes() calls = %d, want 1", episodeSvc.called)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAnimeInitialReleaseInfoDoesNotTrustCurrentlyAiringMetadata(t *testing.T) {
|
||||||
|
got := animeInitialReleaseInfo(domain.Anime{Anime: jikan.Anime{
|
||||||
|
MalID: 62076,
|
||||||
|
Status: "Currently Airing",
|
||||||
|
Airing: true,
|
||||||
|
Episodes: 6,
|
||||||
|
Aired: jikan.Aired{From: "2026-06-03T00:00:00+00:00"},
|
||||||
|
}}, time.Date(2026, time.July, 1, 12, 0, 0, 0, time.UTC))
|
||||||
|
|
||||||
|
if got.Count != 0 || got.Label != "" || got.Status != "" {
|
||||||
|
t.Fatalf("animeInitialReleaseInfo() = %+v, want empty unverified airing display", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestAnimeEpisodeCountFallsBackToMetadata(t *testing.T) {
|
func TestAnimeEpisodeCountFallsBackToMetadata(t *testing.T) {
|
||||||
episodeSvc := &stubEpisodeService{err: errors.New("provider unavailable")}
|
episodeSvc := &stubEpisodeService{err: errors.New("provider unavailable")}
|
||||||
handler := NewAnimeHandler(nil, nil, episodeSvc, nil)
|
handler := NewAnimeHandler(nil, nil, episodeSvc, nil)
|
||||||
@@ -175,7 +272,7 @@ func TestAnimeEpisodeCountFallsBackToMetadata(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAnimeInitialEpisodeCountDoesNotCallEpisodeService(t *testing.T) {
|
func TestAnimeInitialEpisodeCountDoesNotTrustCurrentlyAiringMetadata(t *testing.T) {
|
||||||
episodeSvc := &stubEpisodeService{
|
episodeSvc := &stubEpisodeService{
|
||||||
episodes: domain.CanonicalEpisodeList{
|
episodes: domain.CanonicalEpisodeList{
|
||||||
Episodes: []domain.CanonicalEpisode{{Number: 1}, {Number: 2}, {Number: 3}},
|
Episodes: []domain.CanonicalEpisode{{Number: 1}, {Number: 2}, {Number: 3}},
|
||||||
@@ -185,12 +282,13 @@ func TestAnimeInitialEpisodeCountDoesNotCallEpisodeService(t *testing.T) {
|
|||||||
got := animeInitialEpisodeCount(domain.Anime{Anime: jikan.Anime{
|
got := animeInitialEpisodeCount(domain.Anime{Anime: jikan.Anime{
|
||||||
MalID: 59970,
|
MalID: 59970,
|
||||||
Airing: true,
|
Airing: true,
|
||||||
|
Status: "Currently Airing",
|
||||||
Episodes: 12,
|
Episodes: 12,
|
||||||
Aired: jikan.Aired{From: "2026-04-03T00:00:00+00:00"},
|
Aired: jikan.Aired{From: "2026-04-03T00:00:00+00:00"},
|
||||||
}}, time.Date(2026, time.June, 21, 0, 0, 0, 0, time.UTC))
|
}}, time.Date(2026, time.June, 21, 0, 0, 0, 0, time.UTC))
|
||||||
|
|
||||||
if got.Count != 12 || got.Label != "Total episodes" {
|
if got.Count != 0 || got.Label != "" {
|
||||||
t.Fatalf("animeInitialEpisodeCount() = %+v, want count=12 label=%q", got, "Total episodes")
|
t.Fatalf("animeInitialEpisodeCount() = %+v, want empty display", got)
|
||||||
}
|
}
|
||||||
if episodeSvc.called != 0 {
|
if episodeSvc.called != 0 {
|
||||||
t.Fatalf("GetCanonicalEpisodes() calls = %d, want 0", episodeSvc.called)
|
t.Fatalf("GetCanonicalEpisodes() calls = %d, want 0", episodeSvc.called)
|
||||||
|
|||||||
@@ -31,8 +31,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if $anime.Type}}<span class="flex min-w-0 items-center gap-1.5 before:mr-1 before:block before:size-0.75 before:shrink-0 before:rounded-full before:bg-current before:opacity-65 first:before:hidden">{{$anime.Type}}</span>{{end}}
|
{{if $anime.Type}}<span class="flex min-w-0 items-center gap-1.5 before:mr-1 before:block before:size-0.75 before:shrink-0 before:rounded-full before:bg-current before:opacity-65 first:before:hidden">{{$anime.Type}}</span>{{end}}
|
||||||
{{template "anime_episode_count_loading" dict "AnimeID" $anime.MalID "Count" .EpisodesCount "Label" .EpisodesCountLabel}}
|
{{template "anime_release_info_loading" dict "AnimeID" $anime.MalID "Count" .ReleaseInfo.Count "Label" .ReleaseInfo.Label "Status" .ReleaseInfo.Status}}
|
||||||
{{if $anime.Status}}<span class="flex min-w-0 items-center gap-1.5 before:mr-1 before:block before:size-0.75 before:shrink-0 before:rounded-full before:bg-current before:opacity-65 first:before:hidden">{{$anime.Status}}</span>{{end}}
|
|
||||||
{{if $anime.Season}}<span class="flex min-w-0 items-center gap-1.5 before:mr-1 before:block before:size-0.75 before:shrink-0 before:rounded-full before:bg-current before:opacity-65 first:before:hidden">{{$anime.Premiered}}</span>{{end}}
|
{{if $anime.Season}}<span class="flex min-w-0 items-center gap-1.5 before:mr-1 before:block before:size-0.75 before:shrink-0 before:rounded-full before:bg-current before:opacity-65 first:before:hidden">{{$anime.Premiered}}</span>{{end}}
|
||||||
{{if $anime.ShortRating}}<span class="flex min-w-0 items-center gap-1.5 before:mr-1 before:block before:size-0.75 before:shrink-0 before:rounded-full before:bg-current before:opacity-65 first:before:hidden">{{$anime.ShortRating}}</span>{{end}}
|
{{if $anime.ShortRating}}<span class="flex min-w-0 items-center gap-1.5 before:mr-1 before:block before:size-0.75 before:shrink-0 before:rounded-full before:bg-current before:opacity-65 first:before:hidden">{{$anime.ShortRating}}</span>{{end}}
|
||||||
{{template "anime_audio_availability_loading" dict "AnimeID" $anime.MalID}}
|
{{template "anime_audio_availability_loading" dict "AnimeID" $anime.MalID}}
|
||||||
|
|||||||
@@ -6,8 +6,6 @@
|
|||||||
total eps
|
total eps
|
||||||
{{else if eq .Items.Label "Available episodes"}}
|
{{else if eq .Items.Label "Available episodes"}}
|
||||||
available eps
|
available eps
|
||||||
{{else if eq .Items.Label "Listed episodes"}}
|
|
||||||
listed eps
|
|
||||||
{{else}}
|
{{else}}
|
||||||
aired eps
|
aired eps
|
||||||
{{end}}
|
{{end}}
|
||||||
@@ -15,6 +13,26 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
{{define "anime_release_info"}}
|
||||||
|
<span class="contents">
|
||||||
|
{{if .Items.Count}}
|
||||||
|
<span class="flex min-w-0 items-center gap-1.5 before:mr-1 before:block before:size-0.75 before:shrink-0 before:rounded-full before:bg-current before:opacity-65 first:before:hidden">
|
||||||
|
<span class="text-foreground">{{.Items.Count}}</span>
|
||||||
|
{{if eq .Items.Label "Total episodes"}}
|
||||||
|
total eps
|
||||||
|
{{else if eq .Items.Label "Available episodes"}}
|
||||||
|
available eps
|
||||||
|
{{else}}
|
||||||
|
aired eps
|
||||||
|
{{end}}
|
||||||
|
</span>
|
||||||
|
{{end}}
|
||||||
|
{{if .Items.Status}}
|
||||||
|
<span class="flex min-w-0 items-center gap-1.5 before:mr-1 before:block before:size-0.75 before:shrink-0 before:rounded-full before:bg-current before:opacity-65 first:before:hidden">{{.Items.Status}}</span>
|
||||||
|
{{end}}
|
||||||
|
</span>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
{{define "anime_audio_availability"}}
|
{{define "anime_audio_availability"}}
|
||||||
{{if .Items}}
|
{{if .Items}}
|
||||||
<span class="flex min-w-0 items-center gap-1.5 before:mr-1 before:block before:size-0.75 before:shrink-0 before:rounded-full before:bg-current before:opacity-65 first:before:hidden">
|
<span class="flex min-w-0 items-center gap-1.5 before:mr-1 before:block before:size-0.75 before:shrink-0 before:rounded-full before:bg-current before:opacity-65 first:before:hidden">
|
||||||
@@ -54,3 +72,14 @@
|
|||||||
</span>
|
</span>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
{{define "anime_release_info_loading"}}
|
||||||
|
<span
|
||||||
|
hx-get="/anime/{{.AnimeID}}?section=release-info"
|
||||||
|
hx-trigger="load"
|
||||||
|
hx-swap="outerHTML"
|
||||||
|
class="contents"
|
||||||
|
>
|
||||||
|
{{template "anime_release_info" dict "Items" .}}
|
||||||
|
</span>
|
||||||
|
{{end}}
|
||||||
|
|||||||
Reference in New Issue
Block a user