From d6eda663603d5afaed42b2ea8dae06a790eb8fa3 Mon Sep 17 00:00:00 2001 From: Trevor Mears Date: Sun, 18 Jan 2026 00:58:57 -0800 Subject: [PATCH] fix: favorites arrow navigation stays in same group, add cross-player stop on new playback --- public/js/components/ChannelList.js | 49 +++++++++++++++++++++++------ public/js/components/VideoPlayer.js | 3 ++ public/js/pages/WatchPage.js | 3 ++ 3 files changed, 46 insertions(+), 9 deletions(-) diff --git a/public/js/components/ChannelList.js b/public/js/components/ChannelList.js index 1dd4e83..e8da5ad 100644 --- a/public/js/components/ChannelList.js +++ b/public/js/components/ChannelList.js @@ -497,6 +497,7 @@ class ChannelList { const isFavorite = this.isFavorite(channel.sourceId, channel.id); const renderId = this.renderedChannels[renderIndex]?._renderId || ''; + const renderGroup = this.renderedChannels[renderIndex]?._renderGroup || groupName; renderIndex++; html += ` @@ -506,7 +507,8 @@ class ChannelList { data-source-type="${channel.sourceType}" data-stream-id="${channel.streamId || ''}" data-url="${channel.url || ''}" - data-render-id="${renderId}"> + data-render-id="${renderId}" + data-render-group="${renderGroup}">
@@ -604,13 +606,22 @@ class ChannelList { const isActive = this.currentChannel?.id === channel.id; const isFavorite = this.isFavorite(channel.sourceId, channel.id); + // Find the matching rendered channel to get its unique IDs + const renderedChannel = this.renderedChannels.find(rc => + rc.id === channel.id && rc.sourceId === channel.sourceId && rc._renderGroup === groupName + ); + const renderId = renderedChannel?._renderId || ''; + const renderGroup = renderedChannel?._renderGroup || groupName; + html += `
+ data-url="${channel.url || ''}" + data-render-id="${renderId}" + data-render-group="${renderGroup}">
@@ -1079,6 +1090,7 @@ class ChannelList { this.currentChannel = channel; this.currentRenderId = dataset.renderId; // Track which visual instance is active + this.currentRenderGroup = dataset.renderGroup; // Track which group the selection came from // Update active state in DOM this.container.querySelectorAll('.channel-item.active').forEach(el => { @@ -1359,11 +1371,20 @@ class ChannelList { currentIndex = this.renderedChannels.findIndex(c => c._renderId === this.currentRenderId); } - // Fallback: Find first matching channel ID (if render ID lost or invalid) + // Fallback: Find matching channel ID, prioritizing same render group if (currentIndex === -1) { - currentIndex = this.renderedChannels.findIndex(c => - c.id === this.currentChannel.id && c.sourceId === this.currentChannel.sourceId - ); + // First try to find in same group (for Favorites containing duplicates) + if (this.currentRenderGroup) { + currentIndex = this.renderedChannels.findIndex(c => + c.id === this.currentChannel.id && c.sourceId === this.currentChannel.sourceId && c._renderGroup === this.currentRenderGroup + ); + } + // Final fallback: any matching channel + if (currentIndex === -1) { + currentIndex = this.renderedChannels.findIndex(c => + c.id === this.currentChannel.id && c.sourceId === this.currentChannel.sourceId + ); + } } if (currentIndex === -1) return; @@ -1393,10 +1414,20 @@ class ChannelList { currentIndex = this.renderedChannels.findIndex(c => c._renderId === this.currentRenderId); } + // Fallback: Find matching channel ID, prioritizing same render group if (currentIndex === -1) { - currentIndex = this.renderedChannels.findIndex(c => - c.id === this.currentChannel.id && c.sourceId === this.currentChannel.sourceId - ); + // First try to find in same group (for Favorites containing duplicates) + if (this.currentRenderGroup) { + currentIndex = this.renderedChannels.findIndex(c => + c.id === this.currentChannel.id && c.sourceId === this.currentChannel.sourceId && c._renderGroup === this.currentRenderGroup + ); + } + // Final fallback: any matching channel + if (currentIndex === -1) { + currentIndex = this.renderedChannels.findIndex(c => + c.id === this.currentChannel.id && c.sourceId === this.currentChannel.sourceId + ); + } } if (currentIndex === -1) return; diff --git a/public/js/components/VideoPlayer.js b/public/js/components/VideoPlayer.js index 3781e6a..a0e3a5d 100644 --- a/public/js/components/VideoPlayer.js +++ b/public/js/components/VideoPlayer.js @@ -752,6 +752,9 @@ class VideoPlayer { this.currentChannel = channel; try { + // Stop any WatchPage playback (movies/series) before starting Live TV + window.app?.pages?.watch?.stop?.(); + // Stop current playback this.stop(); this.updateTranscodeStatus('hidden'); diff --git a/public/js/pages/WatchPage.js b/public/js/pages/WatchPage.js index 630c826..336430e 100644 --- a/public/js/pages/WatchPage.js +++ b/public/js/pages/WatchPage.js @@ -200,6 +200,9 @@ class WatchPage { this.currentEpisode = content.currentEpisode || null; this.returnPage = content.type === 'movie' ? 'movies' : 'series'; + // Stop any Live TV playback before starting movie/series + this.app?.player?.stop?.(); + // Reset state this.cancelNextEpisode();