Restore the playing playlist when returning to Now Playing

This commit is contained in:
Jonathan Sykes
2026-10-03 18:28:58 +08:00
parent f2c9459a54
commit cdc367a972

View File

@@ -7126,6 +7126,7 @@ const SectionRail = (() => {
const el = elOf(sec);
if (!el) return;
flashLabel(btn);
if (sec.id === 'player' || sec.id === 'meta') restoreNowPlayingList();
if (st.active === sec.id && sec.fold) {
// Already here: this is the second tap — fold or unfold the card.
setFolded(sec.id, !isFolded(sec.id));
@@ -8048,6 +8049,27 @@ function playQueue(index = 0) {
playFromList(data.queue.slice(), index, 'queue');
}
// Browsing replaces the shared list pane independently of the playing queue.
// Rebuild it whenever the player is revealed, including when home-over was
// already false: merely removing that class leaves Search's hidden pane stale.
function restoreNowPlayingList({ remember = true } = {}) {
if (!current?.meta) return;
if (remember && !history.state?.ytpNowPlaying) {
history.replaceState({ ...history.state, ytpBrowseView: view, ytpHomeOver: els.playerPane.classList.contains('home-over') }, '', location.href);
history.pushState({ ...history.state, ytpNowPlaying: true, ytpSettingsSection: null }, '', location.href);
}
setHomeOverPlayer(false);
els.playerPane.classList.remove('empty');
els.placeholder.classList.add('hidden');
const playlistId = queueSource.startsWith('playlist:') ? queueSource.slice(9) : null;
view = playlistId && data.playlists.some(p => p.id === playlistId)
? { type: 'playlist', id: playlistId }
: { type: 'nowPlaying' };
_lastViewKey = [view.type, view.id, view.smartType].join('|');
render();
renderUpNext();
}
function renderUpNext() {
updateServiceUpNext();
Remote.changed();
@@ -8664,6 +8686,7 @@ function updateHomeGridScrollState() {
}
function currentList() {
if (view.type === 'nowPlaying') return queue;
if (view.type === 'search') return searchResults;
if (view.type === 'history') return data.history;
if (view.type === 'queue') return data.queue;
@@ -8758,7 +8781,7 @@ function renderList() {
if (view.type === 'library') { renderLibrary(); return; }
// Filter bar — show for filterable views
const filterableViews = ['history', 'playlist', 'queue', 'channel', 'smart'];
const filterableViews = ['history', 'playlist', 'queue', 'channel', 'smart', 'nowPlaying'];
const showFilter = filterableViews.includes(view.type);
$('listFilterBar').classList.toggle('hidden', !showFilter);
$('batchBar').classList.toggle('hidden', !selectMode);
@@ -8782,7 +8805,9 @@ function renderList() {
Recommendations.inList();
}
if (view.type === 'search') {
if (view.type === 'nowPlaying') {
els.listTitle.textContent = 'Now playing';
} else if (view.type === 'search') {
els.listTitle.textContent = 'Search results';
} else if (view.type === 'history') {
els.listTitle.textContent = 'History';
@@ -10096,7 +10121,7 @@ function renderCard(v, index, list) {
card.addEventListener('click', (e) => {
if (e.target.closest('.card-menu') || e.target.closest('.card-del') || e.target.closest('.card-note-btn') || e.target.closest('.card-channel.link')) return;
if (selectMode) { toggleSelectCard(v.id); return; }
playFromList(list, index, view.type === 'playlist' ? 'playlist:' + view.id : view.type);
playFromList(list, index, view.type === 'playlist' ? 'playlist:' + view.id : view.type === 'nowPlaying' ? queueSource : view.type);
});
card.querySelector('.card-menu').addEventListener('click', (e) => {
e.stopPropagation();
@@ -10175,8 +10200,28 @@ function markPlayingCard() {
});
}
// Only entries created by returning to the player participate here; leave
// unrelated history (including Settings section navigation) to its owner.
window.addEventListener('popstate', event => {
const state = event.state;
if (state?.ytpSettingsSection) return;
if (state?.ytpNowPlaying) {
restoreNowPlayingList({ remember: false });
if (isStackedPlayerLayout()) document.querySelector('.body')?.scrollTo({ top: 0 });
}
else if (state?.ytpBrowseView) {
view = state.ytpBrowseView;
setHomeOverPlayer(!!state.ytpHomeOver);
render();
}
});
let _lastViewKey = null;
function render() {
const key = [view.type, view.id, view.smartType].join('|');
if (history.state?.ytpNowPlaying && _lastViewKey !== null && key !== _lastViewKey) {
history.pushState({ ...history.state, ytpNowPlaying: false, ytpBrowseView: view, ytpHomeOver: els.playerPane.classList.contains('home-over'), ytpSettingsSection: null }, '', location.href);
}
listFilter = '';
const fi = $('listFilterInput');
if (fi) fi.value = '';
@@ -10845,6 +10890,7 @@ function applyPortraitPwaClass() {
// In portrait mode, .body is the single scroll container (player pane on top,
// list pane below). Scrolling it to 0 brings the player fully into view.
function scrollPlayerIntoViewPortrait() {
restoreNowPlayingList();
if (!isStackedPlayerLayout()) return;
const body = document.querySelector('.body');
if (body) {
@@ -11484,14 +11530,16 @@ document.querySelectorAll('.chip').forEach((c) => {
$('updateIconBtn').addEventListener('click', updateFromIcon);
$('chBadge').addEventListener('click', (e) => { e.stopPropagation(); Notes.openChapterPicker(); });
$('miniBar').addEventListener('click', () => {
setHomeOverPlayer(false);
hideMiniBar();
// Scroll the player into view if needed. In portrait PWA, scroll only the
// .body pane (the designated scroll container) — scrollIntoView() also
// scrolls overflow:hidden ancestors up to <html> on iOS, leaving the
// document offset and fixed-element hit testing broken.
if (isStackedPlayerLayout()) scrollPlayerIntoViewPortrait();
else els.playerPane.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
else {
restoreNowPlayingList();
els.playerPane.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}
});
// Opens the set-list view for whatever is already playing. No playlist arg,
// so enterServiceMode leaves the live queue and position untouched.
@@ -11500,7 +11548,7 @@ document.querySelectorAll('.chip').forEach((c) => {
enterServiceMode();
});
// On the home screen the mini bar is the way back, so ✕ returns to the player.
$('miniCloseBtn').addEventListener('click', (e) => { e.stopPropagation(); setHomeOverPlayer(false); hideMiniBar(); });
$('miniCloseBtn').addEventListener('click', (e) => { e.stopPropagation(); restoreNowPlayingList(); hideMiniBar(); });
// Drag-to-reorder: prevent default on cards container
els.cards.addEventListener('dragover', (e) => {