mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-15 13:46:16 -08:00
fix(sources): decode nested URLs before classifying; narrow Xtream paths
- A URL nested in a parameter or path segment is percent-decoded one round at a time until it reads as a URL or parameter list, so one encoded twice is cleaned too; a value still encoded after the last round is dropped. The name check unwraps nested values the same way. - The two segments after `/live/` and its siblings count as an account only when a stream follows them, so a playlist path such as `/live/news/list.m3u` keeps its file name in the URL and the title. - Adding a playlist from the phone drawer closes the drawer first, so two focus-trapped modals never stack. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ea5bca7e96
commit
d2b0325138
6 files changed
+155
-25
No files matched your search
+13
-2
@@ -7,7 +7,10 @@ import { SourceStatusService } from '@iptvnator/portal/shared/data-access';
|
||||
import { SourceRemovalService } from '@iptvnator/playlist/shared/ui';
|
||||
import { SourcesViewStateService } from '@iptvnator/playlist/shared/util';
|
||||
import { PlaylistMeta } from '@iptvnator/shared/interfaces';
|
||||
import { WORKSPACE_SHELL_ACTIONS } from '@iptvnator/workspace/shell/util';
|
||||
import {
|
||||
WORKSPACE_SHELL_ACTIONS,
|
||||
WorkspaceShellContextDrawerService,
|
||||
} from '@iptvnator/workspace/shell/util';
|
||||
import { WorkspaceSourcesFiltersPanelComponent } from './workspace-sources-filters-panel.component';
|
||||
|
||||
const PLAYLISTS = [
|
||||
@@ -137,7 +140,13 @@ describe('WorkspaceSourcesFiltersPanelComponent', () => {
|
||||
expect(rows(element)).toHaveLength(4);
|
||||
});
|
||||
|
||||
it('adds a playlist from the header', () => {
|
||||
it('adds a playlist from the header, closing the phone drawer first', () => {
|
||||
const drawer = TestBed.inject(WorkspaceShellContextDrawerService);
|
||||
drawer.open();
|
||||
let drawerOpenAtDialog: boolean | null = null;
|
||||
openAddPlaylistDialog.mockImplementation(() => {
|
||||
drawerOpenAtDialog = drawer.isOpen();
|
||||
});
|
||||
const element = render();
|
||||
element
|
||||
.querySelector<HTMLButtonElement>(
|
||||
@@ -145,5 +154,7 @@ describe('WorkspaceSourcesFiltersPanelComponent', () => {
|
||||
)
|
||||
?.click();
|
||||
expect(openAddPlaylistDialog).toHaveBeenCalled();
|
||||
// Two focus-trapped modals must not stack.
|
||||
expect(drawerOpenAtDialog).toBe(false);
|
||||
});
|
||||
});
|
||||
+3
@@ -137,6 +137,9 @@ export class WorkspaceSourcesFiltersPanelComponent {
|
||||
}
|
||||
|
||||
addPlaylist(): void {
|
||||
// On a phone the drawer is a focus-trapped modal of its own: it must
|
||||
// not stay open under the dialog.
|
||||
this.contextDrawer?.close();
|
||||
this.workspaceActions?.openAddPlaylistDialog();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user