From 2325ff456177ee40ef89b9c9ff208d44a3838067 Mon Sep 17 00:00:00 2001 From: mkelvers Date: Sun, 26 Apr 2026 23:32:00 +0200 Subject: [PATCH] feat: update video overlay on episode transition --- api/playback/handler.go | 11 +++++++++++ static/player.ts | 15 +++++++++++++++ web/components/watch/video_player.templ | 1 + 3 files changed, 27 insertions(+) diff --git a/api/playback/handler.go b/api/playback/handler.go index 97017d6..15fe259 100644 --- a/api/playback/handler.go +++ b/api/playback/handler.go @@ -392,6 +392,15 @@ func (h *Handler) HandleEpisodeData(w http.ResponseWriter, r *http.Request) { return } + episodeTitle := "" + epNum, epErr := strconv.Atoi(episode) + if epErr == nil && epNum > 0 { + episodeData, epErr := h.jikanClient.GetEpisode(ctx, malID, epNum) + if epErr == nil && episodeData.Data.Title != "" { + episodeTitle = episodeData.Data.Title + } + } + clientModeSources := convertModeSources(data.ModeSources) initialMode := data.InitialMode token := "" @@ -409,6 +418,7 @@ func (h *Handler) HandleEpisodeData(w http.ResponseWriter, r *http.Request) { AvailableModes []string `json:"available_modes"` ModeSources map[string]shared.ModeSource `json:"mode_sources"` Segments []shared.SkipSegment `json:"segments"` + EpisodeTitle string `json:"episode_title"` }{ MalID: malID, Title: data.Title, @@ -419,6 +429,7 @@ func (h *Handler) HandleEpisodeData(w http.ResponseWriter, r *http.Request) { AvailableModes: data.AvailableModes, ModeSources: clientModeSources, Segments: convertToSharedSegments(data.Segments), + EpisodeTitle: episodeTitle, } w.Header().Set("Content-Type", "application/json") diff --git a/static/player.ts b/static/player.ts index 2f4ae2a..da184f3 100644 --- a/static/player.ts +++ b/static/player.ts @@ -30,6 +30,7 @@ interface EpisodeData { available_modes: string[] mode_sources: Record segments: SkipSegment[] + episode_title: string } interface EpisodeData { @@ -42,6 +43,7 @@ interface EpisodeData { available_modes: string[] mode_sources: Record segments: SkipSegment[] + episode_title: string } let playerInitialized = false @@ -144,6 +146,7 @@ const initPlayer = (): void => { const previewPopover = container.querySelector('[data-preview-popover]') as HTMLElement const previewTime = container.querySelector('[data-preview-time]') as HTMLElement + const videoOverlay = container.querySelector('[data-video-overlay]') as HTMLElement const streamUrlForMode = (mode: string): string => { const modeParam = encodeURIComponent(mode) const modeSource = modeSources[mode] @@ -310,6 +313,17 @@ const initPlayer = (): void => { }) } + const updateVideoOverlay = (episode: string, episodeTitle: string): void => { + if (!videoOverlay) return + const episodeText = episodeTitle + ? `Episode ${episode}, ${episodeTitle}` + : `Episode ${episode}` + const secondLine = videoOverlay.querySelector('p') + if (secondLine) { + secondLine.textContent = episodeText + } + } + const formatTime = (seconds: number): string => { if (!Number.isFinite(seconds) || seconds < 0) return '00:00' const mins = Math.floor(seconds / 60) @@ -867,6 +881,7 @@ const loadNextEpisodeInPlace = async (animeID: number, nextEpisode: number): Pro renderSegments() updateSubtitleOptions() updateModeButtons(data.initial_mode) + updateVideoOverlay(String(nextEpisode), data.episode_title) const nextUrl = `/watch/${animeID}/${nextEpisode}` window.history.replaceState(null, '', nextUrl) diff --git a/web/components/watch/video_player.templ b/web/components/watch/video_player.templ index 79c0d84..ccc1a79 100644 --- a/web/components/watch/video_player.templ +++ b/web/components/watch/video_player.templ @@ -38,6 +38,7 @@ templ VideoPlayer(data shared.WatchPageData, displayTitle string) { src={ shared.BuildStreamURL(data.InitialMode, streamToken) } >

{ displayTitle }