From 32586d6b087e81967868de4bdba01fd629c8e5c3 Mon Sep 17 00:00:00 2001 From: mkelvers Date: Fri, 29 May 2026 00:04:05 +0200 Subject: [PATCH] feat: add airing status and end-state helpers to player --- internal/domain/playback.go | 1 + static/player/state.ts | 15 +++++++++++++++ templates/components/video_player.gohtml | 3 ++- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/internal/domain/playback.go b/internal/domain/playback.go index 67999a8..a391d3a 100644 --- a/internal/domain/playback.go +++ b/internal/domain/playback.go @@ -38,6 +38,7 @@ type WatchData struct { ModeSwitchedFrom string AvailableModes []string Segments []SkipSegment + Airing bool } type SubtitleItem struct { diff --git a/static/player/state.ts b/static/player/state.ts index 870c690..dbe1293 100644 --- a/static/player/state.ts +++ b/static/player/state.ts @@ -16,6 +16,7 @@ export interface PlayerState { modeSwitchedFrom: string; currentEpisode: string; totalEpisodes: number; + isAiring: boolean; malID: number; streamURL: string; initialStreamToken: string; @@ -35,6 +36,7 @@ export interface PlayerState { transitionEpisode: number | null; completionSent: boolean; completionAttempts: number; + endedProgressSaved: boolean; lastSavedProgress: { episode: string; seconds: number }; episodeGrid: HTMLElement | null; episodeList: HTMLElement | null; @@ -57,6 +59,7 @@ const createInitialState = (): PlayerState => ({ modeSwitchedFrom: "", currentEpisode: "1", totalEpisodes: 0, + isAiring: false, malID: 0, streamURL: "/watch/proxy/stream", initialStreamToken: "", @@ -76,6 +79,7 @@ const createInitialState = (): PlayerState => ({ transitionEpisode: null, completionSent: false, completionAttempts: 0, + endedProgressSaved: false, lastSavedProgress: { episode: "1", seconds: -1 }, episodeGrid: null, episodeList: null, @@ -86,6 +90,15 @@ const createInitialState = (): PlayerState => ({ export const state: PlayerState = createInitialState(); +export const showEndState = (): void => { + state.container.classList.add("video-ended"); + state.video.pause(); +}; + +export const hideEndState = (): void => { + state.container.classList.remove("video-ended"); +}; + interface RequiredPlayerElements { video: HTMLVideoElement; progress: HTMLElement; @@ -143,7 +156,9 @@ export const initState = (c: HTMLElement): boolean => { // data attributes from server state.malID = Number.parseInt(dataset(c, "malId"), 10); state.currentEpisode = dataset(c, "currentEpisode") || "1"; + state.totalEpisodes = Number.parseInt(dataset(c, "totalEpisodes"), 10); + state.isAiring = dataset(c, "isAiring") === "true"; state.streamURL = dataset(c, "streamUrl") || "/watch/proxy/stream"; state.initialStreamToken = dataset(c, "streamToken") || ""; state.startTimeSeconds = Number.parseFloat(dataset(c, "startTimeSeconds") || "0") || 0; diff --git a/templates/components/video_player.gohtml b/templates/components/video_player.gohtml index 9665be0..b683f59 100644 --- a/templates/components/video_player.gohtml +++ b/templates/components/video_player.gohtml @@ -10,9 +10,10 @@ data-mode-sources='{{json .WatchData.ModeSources}}' data-available-modes='{{json .WatchData.AvailableModes}}' data-segments='{{json .WatchData.Segments}}' + data-is-airing="{{.WatchData.Airing}}" data-anime-title-english="{{.WatchData.Title}}" data-anime-image="{{.WatchData.MalID}}" - class="group relative aspect-video w-full overflow-hidden bg-black [&.show-controls_[data-video-overlay]]:opacity-100 [&.fullscreen:not(.show-controls)_[data-video-overlay]]:opacity-0 [&.fullscreen:not(.show-controls)_[data-video-overlay]]:pointer-events-none [&.fullscreen:not(.show-controls)]:cursor-none [&.fullscreen:not(.show-controls)_video]:cursor-none"> + class="group relative aspect-video w-full overflow-hidden bg-black [&.show-controls_[data-video-overlay]]:opacity-100 [&.fullscreen:not(.show-controls)_[data-video-overlay]]:opacity-0 [&.fullscreen:not(.show-controls)_[data-video-overlay]]:pointer-events-none [&.fullscreen:not(.show-controls)]:cursor-none [&.fullscreen:not(.show-controls)_video]:cursor-none [&.video-ended_video]:opacity-0">