diff --git a/libs/playlist/m3u/feature-player/src/lib/m3u-collection-route/m3u-collection-route.component.ts b/libs/playlist/m3u/feature-player/src/lib/m3u-collection-route/m3u-collection-route.component.ts
index a5374e029..b3375312f 100644
--- a/libs/playlist/m3u/feature-player/src/lib/m3u-collection-route/m3u-collection-route.component.ts
+++ b/libs/playlist/m3u/feature-player/src/lib/m3u-collection-route/m3u-collection-route.component.ts
@@ -1,9 +1,12 @@
import {
+ inject,
ChangeDetectionStrategy,
Component,
input,
} from '@angular/core';
+import { ActivatedRoute } from '@angular/router';
import { UnifiedCollectionPageComponent } from '@iptvnator/portal/shared/ui';
+import { routeParamSignal } from '@iptvnator/portal/shared/util';
@Component({
selector: 'app-m3u-collection-route',
@@ -12,11 +15,19 @@ import { UnifiedCollectionPageComponent } from '@iptvnator/portal/shared/ui';
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class M3uCollectionRouteComponent {
+ private readonly route = inject(ActivatedRoute);
+
readonly mode = input<'favorites' | 'recent'>('favorites');
readonly portalType = input('m3u');
+ readonly playlistId = routeParamSignal(
+ this.route,
+ 'id',
+ (value) => value ?? undefined
+ );
}
diff --git a/libs/playlist/shared/ui/src/lib/playlist-switcher/playlist-switcher.component.spec.ts b/libs/playlist/shared/ui/src/lib/playlist-switcher/playlist-switcher.component.spec.ts
new file mode 100644
index 000000000..4c598fec1
--- /dev/null
+++ b/libs/playlist/shared/ui/src/lib/playlist-switcher/playlist-switcher.component.spec.ts
@@ -0,0 +1,268 @@
+import { signal } from '@angular/core';
+import {
+ ComponentFixture,
+ TestBed,
+ fakeAsync,
+ flushMicrotasks,
+ tick,
+} from '@angular/core/testing';
+import { NoopAnimationsModule } from '@angular/platform-browser/animations';
+import { TranslateModule } from '@ngx-translate/core';
+import { PlaylistContextFacade } from '@iptvnator/playlist/shared/util';
+import { PortalStatusService } from 'services';
+import { PlaylistMeta } from 'shared-interfaces';
+import { PlaylistSwitcherComponent } from './playlist-switcher.component';
+
+const SEARCH_QUERY_STORAGE_KEY = 'playlist-switcher:search-query';
+const PLAYLIST_TYPE_FILTER_STORAGE_KEY = 'playlist-switcher:type-filters';
+
+function createPlaylist(
+ overrides: Partial & { _id: string }
+): PlaylistMeta {
+ return {
+ _id: overrides._id,
+ title: overrides.title ?? overrides.filename ?? overrides._id,
+ filename: overrides.filename,
+ count: overrides.count ?? 0,
+ importDate:
+ overrides.importDate ?? new Date('2026-04-05T10:00:00.000Z').toISOString(),
+ autoRefresh: overrides.autoRefresh ?? false,
+ ...overrides,
+ } as PlaylistMeta;
+}
+
+describe('PlaylistSwitcherComponent', () => {
+ let fixture: ComponentFixture;
+ let component: PlaylistSwitcherComponent;
+ let playlistsSignal: ReturnType>;
+ let resolvedPlaylistIdSignal: ReturnType>;
+ let activePlaylistSignal: ReturnType>;
+ let playlistContext: {
+ playlists: typeof playlistsSignal;
+ allPlaylistsLoaded: ReturnType>;
+ resolvedPlaylistId: typeof resolvedPlaylistIdSignal;
+ activePlaylist: typeof activePlaylistSignal;
+ selectPlaylist: jest.Mock;
+ };
+ let portalStatusService: {
+ checkPortalStatus: jest.Mock;
+ getStatusClass: jest.Mock;
+ };
+
+ const m3uPlaylist = createPlaylist({
+ _id: 'm3u-1',
+ count: 24,
+ importDate: '2026-04-05T09:00:00.000Z',
+ title: 'Morning M3U',
+ url: 'http://example.test/m3u.m3u',
+ });
+ const stalkerPlaylist = createPlaylist({
+ _id: 'stalker-1',
+ importDate: '2026-04-05T11:00:00.000Z',
+ macAddress: '00:1A:79:00:00:01',
+ portalUrl: 'http://127.0.0.1:3210/portal.php',
+ title: 'Living Room Stalker',
+ });
+ const xtreamPlaylist = createPlaylist({
+ _id: 'xtream-1',
+ importDate: '2026-04-05T12:00:00.000Z',
+ password: 'pass1',
+ serverUrl: 'http://127.0.0.1:3211',
+ title: 'Cinema Xtream',
+ updateDate: new Date('2026-04-05T12:30:00.000Z').getTime(),
+ username: 'user1',
+ });
+
+ async function createComponent(): Promise {
+ await TestBed.configureTestingModule({
+ imports: [
+ PlaylistSwitcherComponent,
+ NoopAnimationsModule,
+ TranslateModule.forRoot(),
+ ],
+ providers: [
+ {
+ provide: PlaylistContextFacade,
+ useValue: playlistContext,
+ },
+ {
+ provide: PortalStatusService,
+ useValue: portalStatusService,
+ },
+ ],
+ }).compileComponents();
+
+ fixture = TestBed.createComponent(PlaylistSwitcherComponent);
+ component = fixture.componentInstance;
+ fixture.componentRef.setInput('currentTitle', '');
+ fixture.componentRef.setInput('subtitle', '3 playlists');
+ fixture.detectChanges();
+ }
+
+ beforeEach(() => {
+ localStorage.clear();
+
+ playlistsSignal = signal([m3uPlaylist, stalkerPlaylist, xtreamPlaylist]);
+ resolvedPlaylistIdSignal = signal(xtreamPlaylist._id);
+ activePlaylistSignal = signal(xtreamPlaylist);
+
+ playlistContext = {
+ playlists: playlistsSignal,
+ allPlaylistsLoaded: signal(true),
+ resolvedPlaylistId: resolvedPlaylistIdSignal,
+ activePlaylist: activePlaylistSignal,
+ selectPlaylist: jest.fn((playlist: PlaylistMeta) => {
+ resolvedPlaylistIdSignal.set(playlist._id);
+ activePlaylistSignal.set(playlist);
+ }),
+ };
+ portalStatusService = {
+ checkPortalStatus: jest
+ .fn()
+ .mockResolvedValueOnce('active')
+ .mockResolvedValueOnce('inactive'),
+ getStatusClass: jest.fn((status: string) => `status-${status}`),
+ };
+ });
+
+ afterEach(() => {
+ localStorage.clear();
+ jest.restoreAllMocks();
+ });
+
+ it('reads persisted search and type filters on startup and filters playlists accordingly', async () => {
+ localStorage.setItem(SEARCH_QUERY_STORAGE_KEY, 'room');
+ localStorage.setItem(
+ PLAYLIST_TYPE_FILTER_STORAGE_KEY,
+ JSON.stringify({
+ m3u: false,
+ stalker: true,
+ xtream: true,
+ })
+ );
+
+ await createComponent();
+
+ expect(component.searchQuery()).toBe('room');
+ expect(component.isTypeFilterSelected('m3u')).toBe(false);
+ expect(component.filteredPlaylists()).toEqual([stalkerPlaylist]);
+ });
+
+ it('sorts playlists by import date descending and prevents clearing the last enabled type filter', async () => {
+ await createComponent();
+
+ expect(component.filteredPlaylists().map((playlist) => playlist._id)).toEqual([
+ xtreamPlaylist._id,
+ stalkerPlaylist._id,
+ m3uPlaylist._id,
+ ]);
+
+ component.togglePlaylistTypeFilter('m3u');
+ component.togglePlaylistTypeFilter('stalker');
+ expect(component.playlistTypeFilters()).toEqual({
+ m3u: false,
+ stalker: false,
+ xtream: true,
+ });
+
+ component.togglePlaylistTypeFilter('xtream');
+ expect(component.playlistTypeFilters()).toEqual({
+ m3u: false,
+ stalker: false,
+ xtream: true,
+ });
+ });
+
+ it('selects a playlist, closes the menu, and emits the selected id', async () => {
+ await createComponent();
+
+ const closeMenuSpy = jest.spyOn(component.menuTrigger(), 'closeMenu');
+ const selectedIds: string[] = [];
+ component.playlistSelected.subscribe((playlistId) => {
+ selectedIds.push(playlistId);
+ });
+
+ component.selectPlaylist(stalkerPlaylist);
+ fixture.detectChanges();
+
+ expect(closeMenuSpy).toHaveBeenCalledTimes(1);
+ expect(playlistContext.selectPlaylist).toHaveBeenCalledWith(
+ stalkerPlaylist
+ );
+ expect(selectedIds).toEqual([stalkerPlaylist._id]);
+ expect(component.isSelected(stalkerPlaylist)).toBe(true);
+ });
+
+ it('emits playlist and account info requests through the context actions', async () => {
+ await createComponent();
+
+ const closeMenuSpy = jest.spyOn(component.menuTrigger(), 'closeMenu');
+ const playlistInfoSpy = jest.fn();
+ const accountInfoSpy = jest.fn();
+ component.playlistInfoRequested.subscribe(playlistInfoSpy);
+ component.accountInfoRequested.subscribe(accountInfoSpy);
+
+ component.requestPlaylistInfo();
+ component.requestAccountInfo();
+
+ expect(closeMenuSpy).toHaveBeenCalledTimes(2);
+ expect(playlistInfoSpy).toHaveBeenCalledTimes(1);
+ expect(accountInfoSpy).toHaveBeenCalledTimes(1);
+ });
+
+ it('opens the menu, syncs overlay width, and checks portal statuses for Xtream playlists', fakeAsync(async () => {
+ await createComponent();
+
+ const triggerElement = component.triggerElement().nativeElement;
+ jest.spyOn(triggerElement, 'getBoundingClientRect').mockReturnValue({
+ bottom: 0,
+ height: 0,
+ left: 0,
+ right: 320,
+ toJSON: () => ({}),
+ top: 0,
+ width: 320,
+ x: 0,
+ y: 0,
+ });
+
+ component.onMenuOpened();
+ flushMicrotasks();
+ tick();
+
+ expect(component.isMenuOpen()).toBe(true);
+ expect(
+ document.documentElement.style.getPropertyValue(
+ '--playlist-switcher-overlay-width'
+ )
+ ).toBe('320px');
+ expect(portalStatusService.checkPortalStatus).toHaveBeenCalledTimes(1);
+ expect(portalStatusService.checkPortalStatus).toHaveBeenCalledWith(
+ xtreamPlaylist.serverUrl,
+ xtreamPlaylist.username,
+ xtreamPlaylist.password
+ );
+ expect(component.portalStatuses().get(xtreamPlaylist._id)).toBe('active');
+ expect(component.getStatusClass(xtreamPlaylist._id)).toBe('status-active');
+
+ component.onMenuClosed();
+ expect(component.isMenuOpen()).toBe(false);
+ expect(
+ document.documentElement.style.getPropertyValue(
+ '--playlist-switcher-overlay-width'
+ )
+ ).toBe('');
+ }));
+
+ it('falls back to the active playlist title when no explicit current title is provided', async () => {
+ await createComponent();
+
+ expect(component.displayTitle()).toBe('Cinema Xtream');
+
+ resolvedPlaylistIdSignal.set(null);
+ activePlaylistSignal.set(null);
+ fixture.detectChanges();
+
+ expect(component.displayTitle()).toBe('Select playlist');
+ });
+});
diff --git a/libs/playlist/shared/util/src/lib/playlist-context.facade.spec.ts b/libs/playlist/shared/util/src/lib/playlist-context.facade.spec.ts
new file mode 100644
index 000000000..a78d29105
--- /dev/null
+++ b/libs/playlist/shared/util/src/lib/playlist-context.facade.spec.ts
@@ -0,0 +1,422 @@
+import { signal } from '@angular/core';
+import { TestBed } from '@angular/core/testing';
+import { NavigationEnd, Router } from '@angular/router';
+import { Store } from '@ngrx/store';
+import {
+ PlaylistActions,
+ selectActivePlaylistId,
+ selectAllPlaylistsMeta,
+ selectPlaylistsLoadingFlag,
+} from 'm3u-state';
+import { Subject } from 'rxjs';
+import { PlaylistMeta } from 'shared-interfaces';
+import {
+ PlaylistContextFacade,
+ PlaylistRouteContext,
+} from './playlist-context.facade';
+
+const LAST_SECTION_STORAGE_KEY = 'playlist-switcher:last-sections:v2';
+
+function createPlaylist(
+ overrides: Partial & { _id: string }
+): PlaylistMeta {
+ return {
+ _id: overrides._id,
+ title: overrides.title ?? overrides.filename ?? overrides._id,
+ count: overrides.count ?? 0,
+ importDate:
+ overrides.importDate ?? new Date('2026-04-05T10:00:00.000Z').toISOString(),
+ autoRefresh: overrides.autoRefresh ?? false,
+ ...overrides,
+ } as PlaylistMeta;
+}
+
+describe('PlaylistContextFacade', () => {
+ let facade: PlaylistContextFacade;
+ let routerEvents: Subject;
+ let router: {
+ url: string;
+ events: ReturnType['asObservable']>;
+ navigate: jest.Mock;
+ };
+ let dispatch: jest.Mock;
+ let playlistsSignal: ReturnType>;
+ let loadedSignal: ReturnType>;
+ let activePlaylistIdSignal: ReturnType>;
+ let originalElectron: unknown;
+
+ const xtreamA = createPlaylist({
+ _id: 'xtream-a',
+ password: 'secret',
+ serverUrl: 'http://127.0.0.1:3211',
+ title: 'Xtream A',
+ username: 'user-a',
+ });
+ const xtreamB = createPlaylist({
+ _id: 'xtream-b',
+ password: 'secret',
+ serverUrl: 'http://127.0.0.1:3211',
+ title: 'Xtream B',
+ username: 'user-b',
+ });
+ const stalkerA = createPlaylist({
+ _id: 'stalker-a',
+ macAddress: '00:1A:79:00:00:01',
+ portalUrl: 'http://127.0.0.1:3210/portal.php',
+ title: 'Stalker A',
+ });
+ const stalkerB = createPlaylist({
+ _id: 'stalker-b',
+ macAddress: '00:1A:79:00:00:02',
+ portalUrl: 'http://127.0.0.1:3210/portal.php',
+ title: 'Stalker B',
+ });
+ const m3uA = createPlaylist({
+ _id: 'm3u-a',
+ title: 'M3U A',
+ url: 'http://example.test/a.m3u',
+ });
+ const m3uB = createPlaylist({
+ _id: 'm3u-b',
+ title: 'M3U B',
+ url: 'http://example.test/b.m3u',
+ });
+
+ function setElectronAvailability(enabled: boolean): void {
+ Object.defineProperty(window, 'electron', {
+ configurable: true,
+ value: enabled ? {} : undefined,
+ });
+ }
+
+ function instantiateFacade(): PlaylistContextFacade {
+ facade = TestBed.inject(PlaylistContextFacade);
+ dispatch.mockClear();
+ router.navigate.mockClear();
+ return facade;
+ }
+
+ beforeEach(() => {
+ localStorage.clear();
+ originalElectron = (window as Window & { electron?: unknown }).electron;
+
+ routerEvents = new Subject();
+ router = {
+ url: '/workspace/xtreams/xtream-a/live',
+ events: routerEvents.asObservable(),
+ navigate: jest.fn().mockResolvedValue(true),
+ };
+ dispatch = jest.fn((action: unknown) => action);
+ playlistsSignal = signal([
+ xtreamA,
+ xtreamB,
+ stalkerA,
+ stalkerB,
+ m3uA,
+ m3uB,
+ ]);
+ loadedSignal = signal(true);
+ activePlaylistIdSignal = signal(xtreamA._id);
+ setElectronAvailability(true);
+
+ TestBed.configureTestingModule({
+ providers: [
+ PlaylistContextFacade,
+ {
+ provide: Router,
+ useValue: router,
+ },
+ {
+ provide: Store,
+ useValue: {
+ dispatch,
+ selectSignal: jest.fn((selector: unknown) => {
+ if (selector === selectAllPlaylistsMeta) {
+ return playlistsSignal;
+ }
+ if (selector === selectPlaylistsLoadingFlag) {
+ return loadedSignal;
+ }
+ if (selector === selectActivePlaylistId) {
+ return activePlaylistIdSignal;
+ }
+
+ throw new Error(
+ `Unexpected selector: ${String(selector)}`
+ );
+ }),
+ },
+ },
+ ],
+ });
+ });
+
+ afterEach(() => {
+ localStorage.clear();
+ Object.defineProperty(window, 'electron', {
+ configurable: true,
+ value: originalElectron,
+ });
+ routerEvents.complete();
+ jest.restoreAllMocks();
+ });
+
+ it('preserves same-provider Xtream sections when switching through selectPlaylist', () => {
+ router.url = '/workspace/xtreams/xtream-a/live';
+ const service = instantiateFacade();
+
+ service.selectPlaylist(xtreamB);
+
+ expect(dispatch).toHaveBeenCalledWith(
+ PlaylistActions.setActivePlaylist({ playlistId: xtreamB._id })
+ );
+ expect(router.navigate).toHaveBeenCalledWith([
+ 'workspace',
+ 'xtreams',
+ xtreamB._id,
+ 'live',
+ ]);
+ });
+
+ it('preserves same-provider Stalker sections when resolving target commands', () => {
+ const service = instantiateFacade();
+
+ expect(
+ service.resolveTargetCommands('stalker', stalkerB._id, {
+ inWorkspace: true,
+ provider: 'stalker',
+ playlistId: stalkerA._id,
+ section: 'downloads',
+ })
+ ).toEqual(['workspace', 'stalker', stalkerB._id, 'downloads']);
+ });
+
+ it('preserves same-provider M3U sections when resolving target commands', () => {
+ const service = instantiateFacade();
+
+ expect(
+ service.resolveTargetCommands('playlists', m3uB._id, {
+ inWorkspace: true,
+ provider: 'playlists',
+ playlistId: m3uA._id,
+ section: 'groups',
+ })
+ ).toEqual(['workspace', 'playlists', m3uB._id, 'groups']);
+ });
+
+ it('maps Stalker ITV routes to Xtream live routes', () => {
+ const service = instantiateFacade();
+
+ expect(
+ service.resolveTargetCommands('xtreams', xtreamA._id, {
+ inWorkspace: true,
+ provider: 'stalker',
+ playlistId: stalkerA._id,
+ section: 'itv',
+ })
+ ).toEqual(['workspace', 'xtreams', xtreamA._id, 'live']);
+ });
+
+ it('maps Xtream live routes to Stalker ITV routes', () => {
+ const service = instantiateFacade();
+
+ expect(
+ service.resolveTargetCommands('stalker', stalkerA._id, {
+ inWorkspace: true,
+ provider: 'xtreams',
+ playlistId: xtreamA._id,
+ section: 'live',
+ })
+ ).toEqual(['workspace', 'stalker', stalkerA._id, 'itv']);
+ });
+
+ it('maps Xtream recently-added routes to Stalker recent routes', () => {
+ const service = instantiateFacade();
+
+ expect(
+ service.resolveTargetCommands('stalker', stalkerA._id, {
+ inWorkspace: true,
+ provider: 'xtreams',
+ playlistId: xtreamA._id,
+ section: 'recently-added',
+ })
+ ).toEqual(['workspace', 'stalker', stalkerA._id, 'recent']);
+ });
+
+ it('preserves recent and favorites sections across provider changes when both providers support them', () => {
+ const service = instantiateFacade();
+
+ expect(
+ service.resolveTargetCommands('xtreams', xtreamA._id, {
+ inWorkspace: true,
+ provider: 'playlists',
+ playlistId: m3uA._id,
+ section: 'recent',
+ })
+ ).toEqual(['workspace', 'xtreams', xtreamA._id, 'recent']);
+ expect(
+ service.resolveTargetCommands('stalker', stalkerA._id, {
+ inWorkspace: true,
+ provider: 'playlists',
+ playlistId: m3uA._id,
+ section: 'favorites',
+ })
+ ).toEqual(['workspace', 'stalker', stalkerA._id, 'favorites']);
+ });
+
+ it('falls back to M3U all when the current section has no M3U equivalent', () => {
+ const service = instantiateFacade();
+
+ expect(
+ service.resolveTargetCommands('playlists', m3uA._id, {
+ inWorkspace: true,
+ provider: 'xtreams',
+ playlistId: xtreamA._id,
+ section: 'live',
+ })
+ ).toEqual(['workspace', 'playlists', m3uA._id, 'all']);
+ });
+
+ it('does not let stale M3U memory override the fallback to all for portal-only sections', () => {
+ localStorage.setItem(
+ LAST_SECTION_STORAGE_KEY,
+ JSON.stringify({
+ providers: {
+ playlists: 'recent',
+ },
+ playlists: {
+ [m3uA._id]: {
+ provider: 'playlists',
+ section: 'recent',
+ updatedAt: 1,
+ },
+ },
+ })
+ );
+ const service = instantiateFacade();
+
+ expect(
+ service.resolveTargetCommands('playlists', m3uA._id, {
+ inWorkspace: true,
+ provider: 'xtreams',
+ playlistId: xtreamA._id,
+ section: 'live',
+ })
+ ).toEqual(['workspace', 'playlists', m3uA._id, 'all']);
+ });
+
+ it('uses playlist-specific section memory when the current route has no section', () => {
+ localStorage.setItem(
+ LAST_SECTION_STORAGE_KEY,
+ JSON.stringify({
+ providers: {},
+ playlists: {
+ [xtreamB._id]: {
+ provider: 'xtreams',
+ section: 'series',
+ updatedAt: 1,
+ },
+ },
+ })
+ );
+ const service = instantiateFacade();
+
+ expect(
+ service.resolveTargetCommands('xtreams', xtreamB._id, {
+ inWorkspace: true,
+ provider: 'xtreams',
+ playlistId: xtreamA._id,
+ section: null,
+ })
+ ).toEqual(['workspace', 'xtreams', xtreamB._id, 'series']);
+ });
+
+ it('uses provider-level section memory when no route section or playlist memory exists', () => {
+ localStorage.setItem(
+ LAST_SECTION_STORAGE_KEY,
+ JSON.stringify({
+ providers: {
+ stalker: 'search',
+ },
+ playlists: {},
+ })
+ );
+ const service = instantiateFacade();
+
+ expect(
+ service.resolveTargetCommands('stalker', stalkerB._id, {
+ inWorkspace: true,
+ provider: 'xtreams',
+ playlistId: xtreamA._id,
+ section: null,
+ })
+ ).toEqual(['workspace', 'stalker', stalkerB._id, 'search']);
+ });
+
+ it('omits Xtream sections outside Electron where section navigation is unsupported', () => {
+ setElectronAvailability(false);
+ const service = instantiateFacade();
+
+ expect(
+ service.resolveTargetCommands('xtreams', xtreamB._id, {
+ inWorkspace: true,
+ provider: 'xtreams',
+ playlistId: xtreamA._id,
+ section: 'live',
+ })
+ ).toEqual(['workspace', 'xtreams', xtreamB._id]);
+ });
+
+ it('returns null when switching from the workspace root before a provider route is selected', () => {
+ const service = instantiateFacade();
+
+ expect(
+ service.resolveTargetCommands('playlists', m3uA._id, {
+ inWorkspace: true,
+ provider: null,
+ playlistId: null,
+ section: null,
+ })
+ ).toBeNull();
+ });
+
+ it('syncs section memory from router navigation events', () => {
+ router.url = '/workspace/playlists/m3u-a/favorites';
+ const service = instantiateFacade();
+
+ router.url = '/workspace/xtreams/xtream-a/recently-added';
+ routerEvents.next(
+ new NavigationEnd(
+ 1,
+ '/workspace/xtreams/xtream-a/recently-added',
+ '/workspace/xtreams/xtream-a/recently-added'
+ )
+ );
+
+ expect(service.routeContext()).toEqual({
+ inWorkspace: true,
+ provider: 'xtreams',
+ playlistId: xtreamA._id,
+ section: 'recently-added',
+ });
+ expect(JSON.parse(localStorage.getItem(LAST_SECTION_STORAGE_KEY) ?? '{}'))
+ .toEqual({
+ playlists: {
+ [m3uA._id]: {
+ provider: 'playlists',
+ section: 'favorites',
+ updatedAt: expect.any(Number),
+ },
+ [xtreamA._id]: {
+ provider: 'xtreams',
+ section: 'recently-added',
+ updatedAt: expect.any(Number),
+ },
+ },
+ providers: {
+ playlists: 'favorites',
+ xtreams: 'recently-added',
+ },
+ });
+ });
+});
diff --git a/libs/playlist/shared/util/src/lib/playlist-context.facade.ts b/libs/playlist/shared/util/src/lib/playlist-context.facade.ts
index 1f45d6056..99ee469c6 100644
--- a/libs/playlist/shared/util/src/lib/playlist-context.facade.ts
+++ b/libs/playlist/shared/util/src/lib/playlist-context.facade.ts
@@ -312,6 +312,10 @@ export class PlaylistContextFacade {
return fromCurrent;
}
+ if (provider === 'playlists' && currentSection) {
+ return 'all';
+ }
+
const memory = this.readSectionMemory();
const playlistMemory = memory.playlists[targetPlaylistId];
if (playlistMemory?.provider === provider) {