From 23c64e000abe7dcbea5d78e02ba3e22d0bdff386 Mon Sep 17 00:00:00 2001 From: BoulderBadgeDad Date: Thu, 25 Jun 2026 23:07:15 -0700 Subject: [PATCH] youtube playlists: same settings cog/modal as channels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit playlist cards on the watchlist tab now get the same hover cog → the per-channel settings modal (custom show-name + quality override). the modal is kind-aware so it reads 'Playlist settings' + 'the playlist's real name'. no backend change needed: playlist videos are wishlisted with channel_id = playlist_id, so the existing get/set_channel_settings + enqueue override lookup already key off the playlist id. UI-only: cog on playlistCard + data-kind passed to openChannelSettings(id, title, kind). test covers both cogs. --- tests/test_youtube_channel_settings_ui.py | 13 +++++++++---- webui/static/video/video-watchlist.js | 7 +++++-- webui/static/video/video-youtube.js | 15 +++++++++------ 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/tests/test_youtube_channel_settings_ui.py b/tests/test_youtube_channel_settings_ui.py index 08690501..98808901 100644 --- a/tests/test_youtube_channel_settings_ui.py +++ b/tests/test_youtube_channel_settings_ui.py @@ -12,14 +12,19 @@ _WL = (_ROOT / "webui" / "static" / "video" / "video-watchlist.js").read_text(en _CSS = (_ROOT / "webui" / "static" / "video" / "video-side.css").read_text(encoding="utf-8") -def test_channel_card_has_a_settings_cog(): - assert 'data-vyt-wsettings' in _WL # cog button on the watchlist channel card - assert 'vyt-wcard-cog' in _WL and '.vyt-wcard-cog' in _CSS +def test_channel_and_playlist_cards_both_have_a_settings_cog(): + assert 'data-vyt-wsettings' in _WL # cog button on the watchlist cards + assert _WL.count('vyt-wcard-cog') >= 2 # channel + playlist cards + assert '.vyt-wcard-cog' in _CSS + assert 'data-kind="channel"' in _WL and 'data-kind="playlist"' in _WL -def test_cog_click_opens_the_settings_modal(): +def test_cog_click_opens_the_settings_modal_with_kind(): assert 'VideoYoutube.openChannelSettings(' in _WL assert "cog.getAttribute('data-vyt-wsettings')" in _WL + assert "cog.getAttribute('data-kind')" in _WL # kind passed through + # the modal reads the kind to label channel vs playlist + assert "kind === 'playlist' ? 'Playlist' : 'Channel'" in _YT def test_modal_is_exposed_and_built(): diff --git a/webui/static/video/video-watchlist.js b/webui/static/video/video-watchlist.js index 25fc9f12..c720d36f 100644 --- a/webui/static/video/video-watchlist.js +++ b/webui/static/video/video-watchlist.js @@ -25,7 +25,7 @@ return '
' + '
' + av + '
' + '' + + '" data-kind="channel" data-title="' + esc(ch.title) + '" title="Channel settings">⚙' + '' + '
' + @@ -38,6 +38,8 @@ ? VideoYoutube.avatar({ poster_url: pl.poster_url, title: pl.title }, 'vyt-wcard-avatar') : ''; return '
' + '
' + av + '
' + + '' + '' + '
' + @@ -262,7 +264,8 @@ var cog = e.target.closest('[data-vyt-wsettings]'); if (cog && window.VideoYoutube && VideoYoutube.openChannelSettings) { e.preventDefault(); e.stopPropagation(); - VideoYoutube.openChannelSettings(cog.getAttribute('data-vyt-wsettings'), cog.getAttribute('data-title')); + VideoYoutube.openChannelSettings(cog.getAttribute('data-vyt-wsettings'), + cog.getAttribute('data-title'), cog.getAttribute('data-kind') || 'channel'); return; } var unf = e.target.closest('[data-vyt-wunfollow]'); diff --git a/webui/static/video/video-youtube.js b/webui/static/video/video-youtube.js index 3cb76ff1..3f0127a3 100644 --- a/webui/static/video/video-youtube.js +++ b/webui/static/video/video-youtube.js @@ -215,15 +215,17 @@ }).join(''); } - function _csetForm(title, s, q, dq) { + function _csetForm(title, s, q, dq, kind) { var on = !!s.quality; // a stored override → start enabled var b = (q && q.max_resolution) ? q : dq; // seed fields from override, else default b = b || {}; + var noun = kind === 'playlist' ? 'playlist' : 'channel'; return '' + '' + '' + - '
Overrides the $channel folder/show name when this channel’s videos download. Blank = use the channel’s real name.
' + + '
Overrides the $channel folder/show name when this ' + noun + + '’s videos download. Blank = use the ' + noun + '’s real name.
' + '' + '
' + @@ -236,13 +238,14 @@ '
Off = use the global YouTube quality from Settings.
'; } - function openChannelSettings(channelId, title) { + function openChannelSettings(channelId, title, kind) { if (!channelId) return; + var heading = (kind === 'playlist' ? 'Playlist' : 'Channel') + ' settings'; var prev = document.getElementById('vyt-cset-overlay'); if (prev) prev.remove(); var ov = document.createElement('div'); ov.id = 'vyt-cset-overlay'; ov.className = 'vyt-cset-overlay'; - ov.innerHTML = '