mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-13 20:56:19 -08:00
refactor: update nx monorepo structure
This commit is contained in:
1 parent
aa739f43e0
commit
7ac2fd66b8
175 files changed
+3118
-1076
No files matched your search
@@ -5,14 +5,11 @@ import { Router, RouterOutlet } from '@angular/router';
|
||||
import { Actions, ofType } from '@ngrx/effects';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import {
|
||||
GlobalRecentlyViewedComponent,
|
||||
GlobalSearchResultsComponent,
|
||||
} from '@iptvnator/portal/xtream/feature';
|
||||
import { EpgProgressPanelComponent } from 'components';
|
||||
import { EpgService } from '@iptvnator/epg/data-access';
|
||||
import { EpgProgressPanelComponent } from '@iptvnator/ui/epg';
|
||||
import { PlaylistActions, selectAllPlaylistsMeta } from 'm3u-state';
|
||||
import { filter, take } from 'rxjs';
|
||||
import { DataService, EpgService } from 'services';
|
||||
import { DataService } from 'services';
|
||||
import {
|
||||
AUTO_UPDATE_PLAYLISTS,
|
||||
Language,
|
||||
@@ -149,25 +146,33 @@ export class AppComponent implements OnInit {
|
||||
}
|
||||
|
||||
openGlobalSearch(initialQuery = ''): void {
|
||||
this.dialog.open(GlobalSearchResultsComponent, {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
maxWidth: '100%',
|
||||
panelClass: 'global-search-overlay',
|
||||
data: { isGlobalSearch: true, initialQuery },
|
||||
});
|
||||
void import('@iptvnator/portal/xtream/feature').then(
|
||||
({ GlobalSearchResultsComponent }) => {
|
||||
this.dialog.open(GlobalSearchResultsComponent, {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
maxWidth: '100%',
|
||||
panelClass: 'global-search-overlay',
|
||||
data: { isGlobalSearch: true, initialQuery },
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
openGlobalRecent(): void {
|
||||
this.dialog.open(GlobalRecentlyViewedComponent, {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
maxWidth: '100%',
|
||||
panelClass: 'global-search-overlay',
|
||||
data: { isGlobal: true },
|
||||
hasBackdrop: true,
|
||||
disableClose: false,
|
||||
});
|
||||
void import('@iptvnator/portal/xtream/feature').then(
|
||||
({ GlobalRecentlyViewedComponent }) => {
|
||||
this.dialog.open(GlobalRecentlyViewedComponent, {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
maxWidth: '100%',
|
||||
panelClass: 'global-search-overlay',
|
||||
data: { isGlobal: true },
|
||||
hasBackdrop: true,
|
||||
disableClose: false,
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
PORTAL_EXTERNAL_PLAYBACK,
|
||||
PORTAL_PLAYER,
|
||||
} from '@iptvnator/portal/shared/util';
|
||||
import { PLAYLIST_PLAYER_ACTIONS } from '@iptvnator/playlist/m3u/feature-player';
|
||||
import { PLAYLIST_PLAYER_ACTIONS } from '@iptvnator/playlist/shared/util';
|
||||
import { provideXtreamDataSource } from '@iptvnator/portal/xtream/data-access';
|
||||
import { DataService } from 'services';
|
||||
import { dbConfig } from 'shared-interfaces';
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { Route, Routes } from '@angular/router';
|
||||
import { createStalkerRoutes } from '@iptvnator/portal/stalker/feature';
|
||||
import { createXtreamRoutes } from '@iptvnator/portal/xtream/feature';
|
||||
|
||||
function withWorkspaceLayout(routes: Route[]): Route[] {
|
||||
return routes.map((route) => ({
|
||||
@@ -80,8 +78,20 @@ export const routes: Routes = [
|
||||
(c) => c.DownloadsComponent
|
||||
),
|
||||
},
|
||||
...withWorkspaceLayout(createXtreamRoutes()),
|
||||
...withWorkspaceLayout(createStalkerRoutes()),
|
||||
{
|
||||
path: '',
|
||||
loadChildren: () =>
|
||||
import('@iptvnator/portal/xtream/feature').then((m) =>
|
||||
withWorkspaceLayout(m.createXtreamRoutes())
|
||||
),
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
loadChildren: () =>
|
||||
import('@iptvnator/portal/stalker/feature').then((m) =>
|
||||
withWorkspaceLayout(m.createStalkerRoutes())
|
||||
),
|
||||
},
|
||||
{
|
||||
path: 'settings',
|
||||
data: { layout: 'workspace' },
|
||||
|
||||
@@ -25,10 +25,10 @@ export class ElectronServiceStub {
|
||||
return this.remote.app.getVersion();
|
||||
}
|
||||
|
||||
sendIpcEvent(_type: string, _payload?: unknown): void {
|
||||
sendIpcEvent<T = unknown>(_type: string, _payload?: unknown): T {
|
||||
void _type;
|
||||
void _payload;
|
||||
return undefined;
|
||||
return undefined as T;
|
||||
}
|
||||
|
||||
listenOn(
|
||||
|
||||
@@ -108,10 +108,16 @@ export class ElectronService extends DataService {
|
||||
return AppConfig.version;
|
||||
}
|
||||
|
||||
async sendIpcEvent(type: string, payload?: unknown) {
|
||||
async sendIpcEvent<T = unknown>(
|
||||
type: string,
|
||||
payload?: unknown
|
||||
): Promise<T> {
|
||||
if (type === PLAYLIST_PARSE_BY_URL) {
|
||||
this.fetchM3uPlaylistFromUrl(payload);
|
||||
} else if (type === PLAYLIST_UPDATE) {
|
||||
return undefined as T;
|
||||
}
|
||||
|
||||
if (type === PLAYLIST_UPDATE) {
|
||||
this.updateM3uPlaylistFromFile(
|
||||
payload as {
|
||||
id: string;
|
||||
@@ -120,22 +126,29 @@ export class ElectronService extends DataService {
|
||||
title: string;
|
||||
}
|
||||
);
|
||||
} else if (type === XTREAM_REQUEST) {
|
||||
return await this.forwardXtreamRequest(
|
||||
return undefined as T;
|
||||
}
|
||||
|
||||
if (type === XTREAM_REQUEST) {
|
||||
return (await this.forwardXtreamRequest(
|
||||
payload as { url: string; params: Record<string, string> }
|
||||
);
|
||||
} else if (type === 'STALKER_REQUEST') {
|
||||
return this.fetchStalkerData(
|
||||
)) as T;
|
||||
}
|
||||
|
||||
if (type === 'STALKER_REQUEST') {
|
||||
return (await this.fetchStalkerData(
|
||||
payload as {
|
||||
url: string;
|
||||
macAddress: string;
|
||||
params: Record<string, string>;
|
||||
}
|
||||
);
|
||||
} else if (type === 'OPEN_MPV_PLAYER') {
|
||||
)) as T;
|
||||
}
|
||||
|
||||
if (type === 'OPEN_MPV_PLAYER') {
|
||||
const data = payload as PlayerLaunchPayload;
|
||||
try {
|
||||
return await window.electron.openInMpv(
|
||||
return (await window.electron.openInMpv(
|
||||
data.url,
|
||||
data.title ?? '',
|
||||
data.thumbnail ?? '',
|
||||
@@ -145,8 +158,7 @@ export class ElectronService extends DataService {
|
||||
data.contentInfo,
|
||||
data.startTime,
|
||||
data.headers ?? undefined
|
||||
);
|
||||
/* thumbnail: data.thumbnail ?? '', */
|
||||
)) as T;
|
||||
} catch (error: unknown) {
|
||||
const errorMessage =
|
||||
this.getErrorDetails(error)?.message ?? String(error);
|
||||
@@ -160,10 +172,12 @@ export class ElectronService extends DataService {
|
||||
console.error('MPV launch error:', error);
|
||||
throw error;
|
||||
}
|
||||
} else if (type === 'OPEN_VLC_PLAYER') {
|
||||
}
|
||||
|
||||
if (type === 'OPEN_VLC_PLAYER') {
|
||||
const data = payload as PlayerLaunchPayload;
|
||||
try {
|
||||
return await window.electron.openInVlc(
|
||||
return (await window.electron.openInVlc(
|
||||
data.url,
|
||||
data.title ?? '',
|
||||
data.thumbnail ?? '',
|
||||
@@ -173,7 +187,7 @@ export class ElectronService extends DataService {
|
||||
data.contentInfo,
|
||||
data.startTime,
|
||||
data.headers ?? undefined
|
||||
);
|
||||
)) as T;
|
||||
} catch (error: unknown) {
|
||||
const errorMessage =
|
||||
this.getErrorDetails(error)?.message ?? String(error);
|
||||
@@ -187,7 +201,9 @@ export class ElectronService extends DataService {
|
||||
console.error('VLC launch error:', error);
|
||||
throw error;
|
||||
}
|
||||
} else if (type === AUTO_UPDATE_PLAYLISTS) {
|
||||
}
|
||||
|
||||
if (type === AUTO_UPDATE_PLAYLISTS) {
|
||||
const data = payload as Playlist[];
|
||||
const playlists = await window.electron.autoUpdatePlaylists(data);
|
||||
this.store.dispatch(
|
||||
@@ -202,9 +218,11 @@ export class ElectronService extends DataService {
|
||||
null,
|
||||
{ duration: 2000 }
|
||||
);
|
||||
} else {
|
||||
console.log('Unknown type', type);
|
||||
return playlists as T;
|
||||
}
|
||||
|
||||
console.log('Unknown type', type);
|
||||
return undefined as T;
|
||||
}
|
||||
|
||||
private async fetchStalkerData(payload: {
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import { Injectable, inject } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { ExternalPlayerInfoDialogComponent } from 'components';
|
||||
import {
|
||||
PlayerDialogComponent,
|
||||
PlayerDialogData,
|
||||
} from '@iptvnator/portal/xtream/feature';
|
||||
import { ExternalPlayerInfoDialogComponent } from '@iptvnator/ui/playback';
|
||||
import { DataService } from 'services';
|
||||
import {
|
||||
ExternalPlayerSession,
|
||||
@@ -85,7 +81,9 @@ export class PlayerService {
|
||||
if (!hideExternalInfoDialog) {
|
||||
this.dialog.open(ExternalPlayerInfoDialogComponent);
|
||||
}
|
||||
return await this.dataService.sendIpcEvent(OPEN_MPV_PLAYER, {
|
||||
return await this.dataService.sendIpcEvent<ExternalPlayerSession>(
|
||||
OPEN_MPV_PLAYER,
|
||||
{
|
||||
url: streamUrl,
|
||||
title,
|
||||
thumbnail,
|
||||
@@ -95,12 +93,15 @@ export class PlayerService {
|
||||
headers,
|
||||
contentInfo,
|
||||
startTime,
|
||||
});
|
||||
}
|
||||
);
|
||||
} else if (player === VideoPlayer.VLC) {
|
||||
if (!hideExternalInfoDialog) {
|
||||
this.dialog.open(ExternalPlayerInfoDialogComponent);
|
||||
}
|
||||
return await this.dataService.sendIpcEvent(OPEN_VLC_PLAYER, {
|
||||
return await this.dataService.sendIpcEvent<ExternalPlayerSession>(
|
||||
OPEN_VLC_PLAYER,
|
||||
{
|
||||
url: streamUrl,
|
||||
title,
|
||||
thumbnail,
|
||||
@@ -110,16 +111,18 @@ export class PlayerService {
|
||||
headers,
|
||||
contentInfo,
|
||||
startTime,
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
this.dialog.open<PlayerDialogComponent, PlayerDialogData>(
|
||||
PlayerDialogComponent,
|
||||
{
|
||||
data: { streamUrl, title, contentInfo, startTime },
|
||||
width: '80%',
|
||||
maxWidth: '1200px',
|
||||
maxHeight: '90vh',
|
||||
void import('@iptvnator/portal/xtream/feature').then(
|
||||
({ PlayerDialogComponent }) => {
|
||||
this.dialog.open(PlayerDialogComponent, {
|
||||
data: { streamUrl, title, contentInfo, startTime },
|
||||
width: '80%',
|
||||
maxWidth: '1200px',
|
||||
maxHeight: '90vh',
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { inject, Injectable, Provider } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { PlaylistInfoComponent } from 'components';
|
||||
import { PlaylistInfoComponent } from '@iptvnator/playlist/shared/ui';
|
||||
import {
|
||||
PORTAL_NAVIGATION_ACTIONS,
|
||||
PortalNavigationActions,
|
||||
} from '@iptvnator/portal/shared/util';
|
||||
import { AccountInfoComponent } from '@iptvnator/portal/xtream/feature';
|
||||
import { XtreamStore } from '@iptvnator/portal/xtream/data-access';
|
||||
import { Playlist } from 'shared-interfaces';
|
||||
import { SettingsComponent } from '../settings/settings.component';
|
||||
@@ -18,16 +17,22 @@ export class AppPortalNavigationActionsService
|
||||
private readonly xtreamStore = inject(XtreamStore);
|
||||
|
||||
openAccountInfo(): void {
|
||||
this.dialog.open(AccountInfoComponent, {
|
||||
width: '80%',
|
||||
maxWidth: '1200px',
|
||||
maxHeight: '90vh',
|
||||
data: {
|
||||
vodStreamsCount: this.xtreamStore.vodStreams().length,
|
||||
liveStreamsCount: this.xtreamStore.liveStreams().length,
|
||||
seriesCount: this.xtreamStore.serialStreams().length,
|
||||
},
|
||||
});
|
||||
const data = {
|
||||
vodStreamsCount: this.xtreamStore.vodStreams().length,
|
||||
liveStreamsCount: this.xtreamStore.liveStreams().length,
|
||||
seriesCount: this.xtreamStore.serialStreams().length,
|
||||
};
|
||||
|
||||
void import('@iptvnator/portal/xtream/feature').then(
|
||||
({ AccountInfoComponent }) => {
|
||||
this.dialog.open(AccountInfoComponent, {
|
||||
width: '80%',
|
||||
maxWidth: '1200px',
|
||||
maxHeight: '90vh',
|
||||
data,
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
openPlaylistInfo(playlist: Playlist | null | undefined): void {
|
||||
|
||||
@@ -96,26 +96,34 @@ export class PwaService extends DataService {
|
||||
* @param type ipc command type
|
||||
* @param payload payload
|
||||
*/
|
||||
sendIpcEvent(type: string, payload?: unknown) {
|
||||
sendIpcEvent<T = unknown>(type: string, payload?: unknown): T {
|
||||
if (type === PLAYLIST_PARSE_BY_URL) {
|
||||
this.fetchFromUrl(payload);
|
||||
} else if (type === PLAYLIST_UPDATE) {
|
||||
return undefined as T;
|
||||
}
|
||||
|
||||
if (type === PLAYLIST_UPDATE) {
|
||||
this.refreshPlaylist(payload);
|
||||
} else if (type === XTREAM_REQUEST) {
|
||||
return undefined as T;
|
||||
}
|
||||
|
||||
if (type === XTREAM_REQUEST) {
|
||||
return this.forwardXtreamRequest(
|
||||
payload as { url: string; params: Record<string, string> }
|
||||
);
|
||||
} else if (type === STALKER_REQUEST) {
|
||||
) as T;
|
||||
}
|
||||
|
||||
if (type === STALKER_REQUEST) {
|
||||
return this.forwardStalkerRequest(
|
||||
payload as {
|
||||
url: string;
|
||||
macAddress: string;
|
||||
params: Record<string, string>;
|
||||
}
|
||||
);
|
||||
} else {
|
||||
return Promise.resolve();
|
||||
) as T;
|
||||
}
|
||||
|
||||
return undefined as T;
|
||||
}
|
||||
|
||||
refreshPlaylist(payload: Partial<Playlist & { id: string }>) {
|
||||
|
||||
@@ -2,9 +2,58 @@ import { HttpClient } from '@angular/common/http';
|
||||
import { inject, Injectable } from '@angular/core';
|
||||
import { StorageMap } from '@ngx-pwa/local-storage';
|
||||
import { catchError, map, Observable } from 'rxjs';
|
||||
import * as semver from 'semver';
|
||||
import { STORE_KEY, Theme } from 'shared-interfaces';
|
||||
|
||||
const PRERELEASE_KEYWORDS = [
|
||||
'beta',
|
||||
'alpha',
|
||||
'rc',
|
||||
'preview',
|
||||
'dev',
|
||||
'canary',
|
||||
'nightly',
|
||||
] as const;
|
||||
|
||||
interface ParsedVersion {
|
||||
major: number;
|
||||
minor: number;
|
||||
patch: number;
|
||||
prerelease: boolean;
|
||||
}
|
||||
|
||||
function parseVersion(input: string): ParsedVersion | null {
|
||||
const normalized = input.trim().replace(/^v/i, '');
|
||||
const match = normalized.match(
|
||||
/(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:[-+]?([0-9A-Za-z.-]+))?/
|
||||
);
|
||||
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
major: Number(match[1] ?? 0),
|
||||
minor: Number(match[2] ?? 0),
|
||||
patch: Number(match[3] ?? 0),
|
||||
prerelease: Boolean(match[4]),
|
||||
};
|
||||
}
|
||||
|
||||
function hasPrereleaseKeyword(value: string): boolean {
|
||||
const normalized = value.toLowerCase();
|
||||
return PRERELEASE_KEYWORDS.some((keyword) => normalized.includes(keyword));
|
||||
}
|
||||
|
||||
function compareVersions(a: ParsedVersion, b: ParsedVersion): number {
|
||||
if (a.major !== b.major) {
|
||||
return a.major - b.major;
|
||||
}
|
||||
if (a.minor !== b.minor) {
|
||||
return a.minor - b.minor;
|
||||
}
|
||||
return a.patch - b.patch;
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
@@ -64,34 +113,14 @@ export class SettingsService {
|
||||
map((response) => {
|
||||
// Filter out pre-release versions (beta, alpha, rc, etc.)
|
||||
const stableReleases = response.filter((release) => {
|
||||
const releaseName = release.name.toLowerCase();
|
||||
|
||||
// Check for beta/alpha/rc keywords in the release name
|
||||
const prereleaseKeywords = [
|
||||
'beta',
|
||||
'alpha',
|
||||
'rc',
|
||||
'preview',
|
||||
'dev',
|
||||
'canary',
|
||||
'nightly',
|
||||
];
|
||||
const hasPrereleaseKeyword = prereleaseKeywords.some(
|
||||
(keyword) => releaseName.includes(keyword)
|
||||
);
|
||||
|
||||
if (hasPrereleaseKeyword) {
|
||||
if (hasPrereleaseKeyword(release.name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate version format
|
||||
const version = semver.valid(
|
||||
semver.coerce(release.name)
|
||||
);
|
||||
const version = parseVersion(release.name);
|
||||
if (!version) return false;
|
||||
|
||||
// Check if version has prerelease tags in semver format
|
||||
return !semver.prerelease(release.name);
|
||||
return !version.prerelease;
|
||||
});
|
||||
|
||||
// Sort stable releases by creation date
|
||||
@@ -121,9 +150,8 @@ export class SettingsService {
|
||||
currentVersion: string,
|
||||
latestVersion: string
|
||||
): boolean {
|
||||
// Clean and coerce versions to handle invalid formats
|
||||
const cleanCurrent = semver.coerce(currentVersion);
|
||||
const cleanLatest = semver.coerce(latestVersion);
|
||||
const cleanCurrent = parseVersion(currentVersion);
|
||||
const cleanLatest = parseVersion(latestVersion);
|
||||
|
||||
if (!cleanCurrent || !cleanLatest) {
|
||||
console.warn('Invalid version format:', {
|
||||
@@ -133,6 +161,6 @@ export class SettingsService {
|
||||
return false;
|
||||
}
|
||||
|
||||
return semver.lt(cleanCurrent, cleanLatest);
|
||||
return compareVersions(cleanCurrent, cleanLatest) < 0;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,6 @@
|
||||
import { inject, Injectable, Provider } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { AddPlaylistDialogComponent } from '@iptvnator/playlist/import/feature';
|
||||
import {
|
||||
AccountInfoComponent,
|
||||
GlobalRecentlyViewedComponent,
|
||||
GlobalSearchResultsComponent,
|
||||
} from '@iptvnator/portal/xtream/feature';
|
||||
import { PlaylistType } from 'components';
|
||||
import { PlaylistType } from '@iptvnator/playlist/shared/ui';
|
||||
import {
|
||||
WORKSPACE_SHELL_ACTIONS,
|
||||
WorkspaceAccountInfoData,
|
||||
@@ -18,44 +12,60 @@ export class AppWorkspaceShellActionsService implements WorkspaceShellActions {
|
||||
private readonly dialog = inject(MatDialog);
|
||||
|
||||
openAddPlaylistDialog(type: PlaylistType): void {
|
||||
this.dialog.open(AddPlaylistDialogComponent, {
|
||||
width: '600px',
|
||||
data: { type },
|
||||
});
|
||||
void import('@iptvnator/playlist/import/feature').then(
|
||||
({ AddPlaylistDialogComponent }) => {
|
||||
this.dialog.open(AddPlaylistDialogComponent, {
|
||||
width: '600px',
|
||||
data: { type },
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
openGlobalSearch(initialQuery = ''): void {
|
||||
this.dialog.open(GlobalSearchResultsComponent, {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
maxWidth: '100%',
|
||||
panelClass: 'global-search-overlay',
|
||||
data: {
|
||||
isGlobalSearch: true,
|
||||
initialQuery,
|
||||
},
|
||||
});
|
||||
void import('@iptvnator/portal/xtream/feature').then(
|
||||
({ GlobalSearchResultsComponent }) => {
|
||||
this.dialog.open(GlobalSearchResultsComponent, {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
maxWidth: '100%',
|
||||
panelClass: 'global-search-overlay',
|
||||
data: {
|
||||
isGlobalSearch: true,
|
||||
initialQuery,
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
openGlobalRecent(): void {
|
||||
this.dialog.open(GlobalRecentlyViewedComponent, {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
maxWidth: '100%',
|
||||
panelClass: 'global-search-overlay',
|
||||
data: { isGlobal: true },
|
||||
hasBackdrop: true,
|
||||
disableClose: false,
|
||||
});
|
||||
void import('@iptvnator/portal/xtream/feature').then(
|
||||
({ GlobalRecentlyViewedComponent }) => {
|
||||
this.dialog.open(GlobalRecentlyViewedComponent, {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
maxWidth: '100%',
|
||||
panelClass: 'global-search-overlay',
|
||||
data: { isGlobal: true },
|
||||
hasBackdrop: true,
|
||||
disableClose: false,
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
openAccountInfo(data: WorkspaceAccountInfoData): void {
|
||||
this.dialog.open(AccountInfoComponent, {
|
||||
width: '80%',
|
||||
maxWidth: '1200px',
|
||||
maxHeight: '90vh',
|
||||
data,
|
||||
});
|
||||
void import('@iptvnator/portal/xtream/feature').then(
|
||||
({ AccountInfoComponent }) => {
|
||||
this.dialog.open(AccountInfoComponent, {
|
||||
width: '80%',
|
||||
maxWidth: '1200px',
|
||||
maxHeight: '90vh',
|
||||
data,
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,13 +18,14 @@ import { Router } from '@angular/router';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { provideMockStore } from '@ngrx/store/testing';
|
||||
import { TranslateModule, TranslateService } from '@ngx-translate/core';
|
||||
import { EpgService } from '@iptvnator/epg/data-access';
|
||||
import {
|
||||
MockModule,
|
||||
MockProvider,
|
||||
MockProviders,
|
||||
} from 'ng-mocks';
|
||||
import { DialogService } from 'components';
|
||||
import { DataService, EpgService, PlaylistsService } from 'services';
|
||||
import { DataService, PlaylistsService } from 'services';
|
||||
import { Language, StreamFormat, Theme, VideoPlayer } from 'shared-interfaces';
|
||||
import { SettingsComponent } from './settings.component';
|
||||
|
||||
|
||||
@@ -34,11 +34,12 @@ import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { Router } from '@angular/router';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { TranslateModule, TranslateService } from '@ngx-translate/core';
|
||||
import { EpgService } from '@iptvnator/epg/data-access';
|
||||
import { QRCodeComponent } from 'angularx-qrcode';
|
||||
import { DialogService } from 'components';
|
||||
import { PlaylistActions, selectIsEpgAvailable } from 'm3u-state';
|
||||
import { take } from 'rxjs';
|
||||
import { DataService, EpgService, PlaylistsService } from 'services';
|
||||
import { DataService, PlaylistsService } from 'services';
|
||||
import {
|
||||
Language,
|
||||
Playlist,
|
||||
|
||||
Reference in new issue
Block a user