mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-12 20:16:15 -08:00
feat(stalker): add radio support
Entire-Checkpoint: f957cd9849e0
This commit is contained in:
1 parent
e9875f9f29
commit
ab905af285
59 files changed
+1059
-179
No files matched your search
+37
-1
@@ -14,6 +14,7 @@ import { WorkspaceContextPanelComponent } from './workspace-context-panel.compon
|
||||
|
||||
const translations: Record<string, string> = {
|
||||
'WORKSPACE.CONTEXT.MANAGE_CATEGORIES': 'Manage categories',
|
||||
'WORKSPACE.CONTEXT.RADIO_CATEGORIES': 'Radio Categories',
|
||||
'WORKSPACE.CONTEXT.XTREAM_SYNCING_LIVE': 'Syncing live categories...',
|
||||
'WORKSPACE.CONTEXT.XTREAM_SYNCING_MOVIES': 'Syncing movie categories...',
|
||||
'WORKSPACE.SHELL.XTREAM_IMPORT_LOADING':
|
||||
@@ -53,7 +54,9 @@ describe('WorkspaceContextPanelComponent', () => {
|
||||
reloadCategories: jest.fn(),
|
||||
};
|
||||
const stalkerStore = {
|
||||
getCategoryResource: signal([]),
|
||||
getCategoryResource: signal<
|
||||
Array<{ category_id: string; category_name: string }>
|
||||
>([]),
|
||||
selectedCategoryId: signal<string | null>(null),
|
||||
isCategoryResourceLoading: signal(false),
|
||||
isCategoryResourceFailed: signal(false),
|
||||
@@ -82,6 +85,11 @@ describe('WorkspaceContextPanelComponent', () => {
|
||||
xtreamStore.setSelectedItem.mockClear();
|
||||
xtreamStore.setSelectedCategory.mockClear();
|
||||
xtreamStore.reloadCategories.mockClear();
|
||||
stalkerStore.getCategoryResource.set([]);
|
||||
stalkerStore.selectedCategoryId.set(null);
|
||||
stalkerStore.setSelectedCategory.mockClear();
|
||||
stalkerStore.setPage.mockClear();
|
||||
stalkerStore.clearSelectedItem.mockClear();
|
||||
router.navigate.mockClear();
|
||||
dialog.open.mockClear();
|
||||
|
||||
@@ -217,4 +225,32 @@ describe('WorkspaceContextPanelComponent', () => {
|
||||
2,
|
||||
]);
|
||||
});
|
||||
|
||||
it('labels Stalker radio categories and keeps category selection in the radio layout', () => {
|
||||
fixture.componentRef.setInput('context', {
|
||||
provider: 'stalker',
|
||||
playlistId: 'stalker-1',
|
||||
});
|
||||
fixture.componentRef.setInput('section', 'radio');
|
||||
stalkerStore.getCategoryResource.set([
|
||||
{ category_id: '*', category_name: 'All radio' },
|
||||
]);
|
||||
fixture.detectChanges();
|
||||
|
||||
const title = fixture.nativeElement.querySelector(
|
||||
'.context-header h2'
|
||||
) as HTMLElement;
|
||||
const categoryButton = fixture.nativeElement.querySelector(
|
||||
'.category-item'
|
||||
) as HTMLButtonElement;
|
||||
|
||||
expect(title.textContent).toContain('Radio Categories');
|
||||
|
||||
categoryButton.click();
|
||||
|
||||
expect(stalkerStore.setSelectedCategory).toHaveBeenCalledWith('*');
|
||||
expect(stalkerStore.setPage).toHaveBeenCalledWith(0);
|
||||
expect(stalkerStore.clearSelectedItem).toHaveBeenCalled();
|
||||
expect(router.navigate).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
+6
-2
@@ -69,7 +69,8 @@ export class WorkspaceContextPanelComponent {
|
||||
this.context().provider === 'stalker' &&
|
||||
(this.section() === 'vod' ||
|
||||
this.section() === 'series' ||
|
||||
this.section() === 'itv')
|
||||
this.section() === 'itv' ||
|
||||
this.section() === 'radio')
|
||||
);
|
||||
|
||||
readonly xtreamCategories = this.xtreamStore.getCategoriesBySelectedType;
|
||||
@@ -192,6 +193,9 @@ export class WorkspaceContextPanelComponent {
|
||||
if (this.section() === 'series') {
|
||||
return 'WORKSPACE.CONTEXT.SERIES_CATEGORIES';
|
||||
}
|
||||
if (this.section() === 'radio') {
|
||||
return 'WORKSPACE.CONTEXT.RADIO_CATEGORIES';
|
||||
}
|
||||
return 'WORKSPACE.CONTEXT.LIVE_CATEGORIES';
|
||||
}
|
||||
|
||||
@@ -319,7 +323,7 @@ export class WorkspaceContextPanelComponent {
|
||||
this.stalkerStore.setPage(0);
|
||||
this.stalkerStore.clearSelectedItem();
|
||||
|
||||
if (section === 'itv') {
|
||||
if (section === 'itv' || section === 'radio') {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+5
-1
@@ -19,7 +19,11 @@ import { WorkspaceContextPanelComponent } from '../../../workspace-context-panel
|
||||
import { WorkspaceSettingsContextPanelComponent } from '../../../workspace-context-panel/workspace-settings-context-panel.component';
|
||||
import { WorkspaceSourcesFiltersPanelComponent } from '../../../workspace-sources-filters-panel/workspace-sources-filters-panel.component';
|
||||
|
||||
const LIVE_SECTIONS: ReadonlySet<PortalRailSection> = new Set(['live', 'itv']);
|
||||
const LIVE_SECTIONS: ReadonlySet<PortalRailSection> = new Set([
|
||||
'live',
|
||||
'itv',
|
||||
'radio',
|
||||
]);
|
||||
|
||||
@Component({
|
||||
selector: 'app-workspace-shell-context-sidebar',
|
||||
|
||||
+13
@@ -279,6 +279,18 @@ function getPortalNavigationCommands(
|
||||
section: PortalRailSection
|
||||
): WorkspaceCommandContribution[] {
|
||||
const liveSection = context.provider === 'stalker' ? 'itv' : 'live';
|
||||
const radioCommand =
|
||||
context.provider === 'stalker'
|
||||
? createNavigationCommand(ctx, {
|
||||
id: 'go-to-radio',
|
||||
context,
|
||||
targetSection: 'radio',
|
||||
currentSection: section,
|
||||
icon: 'radio',
|
||||
labelKey: 'WORKSPACE.SHELL.RAIL_RADIO',
|
||||
priority: 115,
|
||||
})
|
||||
: null;
|
||||
|
||||
return [
|
||||
createNavigationCommand(ctx, {
|
||||
@@ -299,6 +311,7 @@ function getPortalNavigationCommands(
|
||||
labelKey: 'WORKSPACE.SHELL.RAIL_LIVE',
|
||||
priority: 110,
|
||||
}),
|
||||
radioCommand,
|
||||
createNavigationCommand(ctx, {
|
||||
id: 'go-to-series',
|
||||
context,
|
||||
|
||||
+1
@@ -24,6 +24,7 @@ export const RAIL_TOOLTIP_KEYS: Readonly<
|
||||
vod: 'WORKSPACE.SHELL.RAIL_MOVIES',
|
||||
live: 'WORKSPACE.SHELL.RAIL_LIVE',
|
||||
itv: 'WORKSPACE.SHELL.RAIL_LIVE',
|
||||
radio: 'WORKSPACE.SHELL.RAIL_RADIO',
|
||||
series: 'WORKSPACE.SHELL.RAIL_SERIES',
|
||||
'recently-added': 'WORKSPACE.SHELL.RAIL_RECENTLY_ADDED',
|
||||
search: 'WORKSPACE.SHELL.RAIL_SEARCH',
|
||||
|
||||
+4
-2
@@ -81,7 +81,8 @@ export function resolveSearchPlaceholderKey(
|
||||
(section === 'vod' ||
|
||||
section === 'series' ||
|
||||
section === 'live' ||
|
||||
section === 'itv')
|
||||
section === 'itv' ||
|
||||
section === 'radio')
|
||||
) {
|
||||
return SEARCH_SECTION_PLACEHOLDER;
|
||||
}
|
||||
@@ -145,7 +146,8 @@ export function resolveSearchScopeLabel(ctx: SearchScopeContext): string {
|
||||
section === 'vod' ||
|
||||
section === 'series' ||
|
||||
section === 'live' ||
|
||||
section === 'itv'
|
||||
section === 'itv' ||
|
||||
section === 'radio'
|
||||
) {
|
||||
const categoryLabel = resolveActiveCategoryLabel(ctx);
|
||||
const sectionLabel = translateRailSection(section, translate);
|
||||
|
||||
+13
@@ -541,6 +541,19 @@ describe('WorkspaceShellFacade', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('treats stalker radio search as a remote section search', () => {
|
||||
facade.currentUrl.set('/workspace/stalker/pl-1/radio?q=jazz');
|
||||
(facade as { syncSearchFromRoute: () => void }).syncSearchFromRoute();
|
||||
TestBed.flushEffects();
|
||||
|
||||
expect(stalkerStore.setSearchPhrase).toHaveBeenCalledWith('jazz');
|
||||
expect(facade.canUseSearch()).toBe(true);
|
||||
expect(facade.searchScopeLabel()).toBe(
|
||||
'WORKSPACE.SHELL.RAIL_RADIO / All Items'
|
||||
);
|
||||
expect(facade.searchStatusLabel()).toBe('');
|
||||
});
|
||||
|
||||
it('applies q to Xtream category search on vod routes', () => {
|
||||
const xtreamStore = TestBed.inject(
|
||||
XtreamStore
|
||||
|
||||
Reference in new issue
Block a user