Merge pull request #628 from 4gray/refactor(nx)-more-app-restructuring

refactor(nx): app restructuring
This commit is contained in:
4gray authored and GitHub committed 2025-10-14 09:01:42 +02:00
commit ad75cb2f1a
52 files changed
+171 -169

No files matched your search

+9 -3
View File
@@ -13,17 +13,23 @@ const routes: Routes = [
{
path: 'playlists',
loadComponent: () =>
import('components').then((c) => c.VideoPlayerComponent),
import('./home/video-player/video-player.component').then(
(c) => c.VideoPlayerComponent
),
},
{
path: 'iptv',
loadComponent: () =>
import('components').then((c) => c.VideoPlayerComponent),
import('./home/video-player/video-player.component').then(
(c) => c.VideoPlayerComponent
),
},
{
path: 'playlists/:id',
loadComponent: () =>
import('components').then((c) => c.VideoPlayerComponent),
import('./home/video-player/video-player.component').then(
(c) => c.VideoPlayerComponent
),
},
{
path: 'settings',
+1 -2
View File
@@ -5,6 +5,7 @@ import { Router } from '@angular/router';
import { Store } from '@ngrx/store';
import { TranslateService } from '@ngx-translate/core';
/* import * as semver from 'semver'; */
import { DataService, EpgService } from '@iptvnator/services';
import * as PlaylistActions from 'm3u-state';
import {
ERROR,
@@ -18,8 +19,6 @@ import {
VIEW_ADD_PLAYLIST,
VIEW_SETTINGS,
} from 'shared-interfaces';
import { DataService } from '../../../../libs/services/src/lib/data.service';
import { EpgService } from '../../../../libs/services/src/lib/epg.service';
import { SettingsService } from './services/settings.service';
import { RecentlyViewedComponent } from './xtream-tauri/recently-viewed/recently-viewed.component';
import { SearchResultsComponent } from './xtream-tauri/search-results/search-results.component';
+1 -1
View File
@@ -4,9 +4,9 @@ import { MatSnackBar } from '@angular/material/snack-bar';
import { DataService } from '@iptvnator/services';
import { Store } from '@ngrx/store';
import { TranslatePipe } from '@ngx-translate/core';
import { RecentPlaylistsComponent } from 'components';
import { addPlaylist } from 'm3u-state';
import { ERROR, Playlist, PLAYLIST_PARSE_RESPONSE } from 'shared-interfaces';
import { RecentPlaylistsComponent } from '../../../../../libs/ui/components/src/lib/recent-playlists/recent-playlists.component';
import { HeaderComponent } from '../shared/components/header/header.component';
@Component({
@@ -9,12 +9,12 @@ import {
import { MatButtonModule } from '@angular/material/button';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { DataService } from '@iptvnator/services';
import { Store } from '@ngrx/store';
import { TranslatePipe } from '@ngx-translate/core';
import { addPlaylist } from 'm3u-state';
import { Playlist } from 'shared-interfaces';
import { v4 as uuid } from 'uuid';
import { DataService } from '../../../../../../libs/services/src/lib/data.service';
@Component({
imports: [
@@ -17,6 +17,7 @@
(toggleRightDrawerClicked)="drawerRight.toggle()"
(multiEpgClicked)="openMultiEpgView()"
[activeChannel]="activeChannel"
(settingsClicked)="openSettings()"
/>
@if (activeChannel.radio === 'true') {
<app-audio-player
@@ -10,14 +10,14 @@ import { RouterTestingModule } from '@angular/router/testing';
import { MockStore, provideMockStore } from '@ngrx/store/testing';
import { TranslateModule } from '@ngx-translate/core';
import { MockComponent, MockModule, MockProviders } from 'ng-mocks';
import { ElectronServiceStub } from '../../../../../../apps/web/src/app/services/electron.service.stub';
import { DataService } from '../../../../../services/src/lib/data.service';
import { VideoPlayer } from '../../../../../shared/interfaces/src/lib/settings.interface';
import { ChannelListContainerComponent } from '../channel-list-container/channel-list-container.component';
import { EpgListComponent } from '../epg-list/epg-list.component';
import { HtmlVideoPlayerComponent } from '../html-video-player/html-video-player.component';
import { VjsPlayerComponent } from '../vjs-player/vjs-player.component';
import { InfoOverlayComponent } from './../info-overlay/info-overlay.component';
import { DataService } from '../../../../../../libs/services/src/lib/data.service';
import { VideoPlayer } from '../../../../../../libs/shared/interfaces/src/lib/settings.interface';
import { ChannelListContainerComponent } from '../../../../../../libs/ui/components/src/lib/channel-list-container/channel-list-container.component';
import { EpgListComponent } from '../../../../../../libs/ui/components/src/lib/epg-list/epg-list.component';
import { HtmlVideoPlayerComponent } from '../../../../../../libs/ui/components/src/lib/html-video-player/html-video-player.component';
import { InfoOverlayComponent } from '../../../../../../libs/ui/components/src/lib/info-overlay/info-overlay.component';
import { VjsPlayerComponent } from '../../../../../../libs/ui/components/src/lib/vjs-player/vjs-player.component';
import { ElectronServiceStub } from '../../services/electron.service.stub';
import { VideoPlayerComponent } from './video-player.component';
import { CommonModule } from '@angular/common';
@@ -27,7 +27,7 @@ import { NgxIndexedDBService } from 'ngx-indexed-db';
import { NgxSkeletonLoaderComponent } from 'ngx-skeleton-loader';
import { Observable, of } from 'rxjs';
import { initialState } from '../../../../../../apps/web/src/app/state/state';
import { PlaylistsService } from '../../../../../services/src/lib/playlists.service';
import { PlaylistsService } from '../../../../../../libs/services/src/lib/playlists.service';
class MatSnackBarStub {
open(): void {}
@@ -3,19 +3,30 @@ import { ComponentPortal } from '@angular/cdk/portal';
import { AsyncPipe, CommonModule } from '@angular/common';
import {
Component,
InjectionToken,
Injector,
NgZone,
OnInit,
effect,
inject,
} from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { MatSidenavModule } from '@angular/material/sidenav';
import { MatSnackBar } from '@angular/material/snack-bar';
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
import { DataService, PlaylistsService } from '@iptvnator/services';
import { Store } from '@ngrx/store';
import { StorageMap } from '@ngx-pwa/local-storage';
import {
ArtPlayerComponent,
AudioPlayerComponent,
EpgListComponent,
HtmlVideoPlayerComponent,
InfoOverlayComponent,
MultiEpgContainerComponent,
SidebarComponent,
ToolbarComponent,
VjsPlayerComponent,
} from 'components';
import * as PlaylistActions from 'm3u-state';
import {
selectActive,
@@ -25,6 +36,7 @@ import {
import { Observable, combineLatestWith, filter, map, switchMap } from 'rxjs';
import {
CHANNEL_SET_USER_AGENT,
COMPONENT_OVERLAY_REF,
Channel,
ERROR,
PLAYLIST_PARSE_BY_URL,
@@ -34,24 +46,12 @@ import {
Settings,
VideoPlayer,
} from 'shared-interfaces';
import { SettingsStore } from '../../../../../../apps/web/src/app/services/settings-store.service';
import { ArtPlayerComponent } from '../art-player/art-player.component';
import { AudioPlayerComponent } from '../audio-player/audio-player.component';
import { EpgListComponent } from '../epg-list/epg-list.component';
import { HtmlVideoPlayerComponent } from '../html-video-player/html-video-player.component';
import { InfoOverlayComponent } from '../info-overlay/info-overlay.component';
import { MultiEpgContainerComponent } from '../multi-epg/multi-epg-container.component';
import { VjsPlayerComponent } from '../vjs-player/vjs-player.component';
import { SidebarComponent } from './sidebar/sidebar.component';
import { ToolbarComponent } from './toolbar/toolbar.component';
import { SettingsStore } from '../../services/settings-store.service';
import { SettingsComponent } from '../../settings/settings.component';
/** Possible sidebar view options */
export type SidebarView = 'CHANNELS' | 'PLAYLISTS';
export const COMPONENT_OVERLAY_REF = new InjectionToken(
'COMPONENT_OVERLAY_REF'
);
@Component({
imports: [
AsyncPipe,
@@ -73,6 +73,7 @@ export const COMPONENT_OVERLAY_REF = new InjectionToken(
export class VideoPlayerComponent implements OnInit {
private activatedRoute = inject(ActivatedRoute);
private dataService = inject(DataService);
private readonly dialog = inject(MatDialog);
private ngZone = inject(NgZone);
private overlay = inject(Overlay);
private playlistsService = inject(PlaylistsService);
@@ -299,4 +300,12 @@ export class VideoPlayerComponent implements OnInit {
navigateHome() {
this.router.navigate(['/']);
}
openSettings() {
this.dialog.open(SettingsComponent, {
width: '1000px',
height: '90%',
data: { isDialog: true },
});
}
}
@@ -10,15 +10,12 @@ import { MatButton } from '@angular/material/button';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIcon } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { PortalStatus, PortalStatusService } from '@iptvnator/services';
import { Store } from '@ngrx/store';
import { TranslatePipe } from '@ngx-translate/core';
import { addPlaylist } from 'm3u-state';
import { Playlist } from 'shared-interfaces';
import { v4 as uuid } from 'uuid';
import {
PortalStatus,
PortalStatusService,
} from '../../../../../../libs/services/src/lib/portal-status.service';
@Component({
imports: [
+1 -1
View File
@@ -1,11 +1,11 @@
import { Injectable, inject } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { DataService } from '@iptvnator/services';
import {
OPEN_MPV_PLAYER,
OPEN_VLC_PLAYER,
VideoPlayer,
} from 'shared-interfaces';
import { DataService } from '../../../../../libs/services/src/lib/data.service';
import { ExternalPlayerInfoDialogComponent } from '../shared/components/external-player-info-dialog/external-player-info-dialog.component';
import {
PlayerDialogComponent,
+1 -1
View File
@@ -3,6 +3,7 @@ import { inject, Injectable } from '@angular/core';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Params } from '@angular/router';
import { SwUpdate } from '@angular/service-worker';
import { DataService } from '@iptvnator/services';
import { Store } from '@ngrx/store';
import { TranslateService } from '@ngx-translate/core';
import * as PlaylistActions from 'm3u-state';
@@ -17,7 +18,6 @@ import {
XTREAM_REQUEST,
XTREAM_RESPONSE,
} from 'shared-interfaces';
import { DataService } from '../../../../../libs/services/src/lib/data.service';
import { AppConfig } from '../../environments/environment';
@Injectable({
@@ -8,14 +8,14 @@ import {
} from '@ngrx/signals';
import { StorageMap } from '@ngx-pwa/local-storage';
import { firstValueFrom } from 'rxjs';
import { Language } from '../../../../../libs/shared/interfaces/src/lib/language.enum';
import {
Language,
Settings,
STORE_KEY,
StreamFormat,
Theme,
VideoPlayer,
} from '../../../../../libs/shared/interfaces/src/lib/settings.interface';
import { STORE_KEY } from '../../../../../libs/shared/interfaces/src/lib/store-keys.enum';
import { StreamFormat } from '../../../../../libs/shared/interfaces/src/lib/stream-format.enum';
import { Theme } from '../../../../../libs/shared/interfaces/src/lib/theme.enum';
} from 'shared-interfaces';
const DEFAULT_SETTINGS: Settings = {
player: VideoPlayer.VideoJs,
+7 -10
View File
@@ -1,18 +1,15 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { inject, Injectable } from '@angular/core';
import { StorageMap } from '@ngx-pwa/local-storage';
import { catchError, map, Observable } from 'rxjs';
import { STORE_KEY } from '../../../../../libs/shared/interfaces/src/lib/store-keys.enum';
import { Theme } from '../../../../../libs/shared/interfaces/src/lib/theme.enum';
import { STORE_KEY, Theme } from 'shared-interfaces';
@Injectable({
providedIn: 'root',
})
export class SettingsService {
constructor(
private http: HttpClient,
private storage: StorageMap
) {}
private http = inject(HttpClient);
private storage = inject(StorageMap);
/**
* Changes the visual theme of the application
@@ -58,9 +55,9 @@ export class SettingsService {
*/
getAppVersion() {
return this.http
.get<
{ created_at: string; name: string }[]
>('https://api.github.com/repos/4gray/iptvnator/releases')
.get<{ created_at: string; name: string }[]>(
'https://api.github.com/repos/4gray/iptvnator/releases'
)
.pipe(
map(
(response) =>
@@ -34,9 +34,9 @@ import { signal } from '@angular/core';
import { NgxIndexedDBService } from 'ngx-indexed-db';
import { of } from 'rxjs';
import { SETTINGS_UPDATE } from 'shared-interfaces';
import { DialogService } from '../../../../../libs/services/src/lib/dialog.service';
import { EpgService } from '../../../../../libs/services/src/lib/epg.service';
import { PlaylistsService } from '../../../../../libs/services/src/lib/playlists.service';
import { DialogService } from '../../../../../libs/ui/components/src/lib/confirm-dialog/dialog.service';
import { ElectronServiceStub } from '../services/electron.service.stub';
import { SettingsStore } from '../services/settings-store.service';
import { SettingsService } from '../services/settings.service';
@@ -30,8 +30,10 @@ import { MatSelectModule } from '@angular/material/select';
import { MatSnackBar } from '@angular/material/snack-bar';
import { MatTooltipModule } from '@angular/material/tooltip';
import { Router } from '@angular/router';
import { DataService, EpgService, PlaylistsService } from '@iptvnator/services';
import { Store } from '@ngrx/store';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { DialogService } from 'components';
import * as PlaylistActions from 'm3u-state';
import { selectIsEpgAvailable } from 'm3u-state';
import { take } from 'rxjs';
@@ -46,10 +48,6 @@ import {
Theme,
VideoPlayer,
} from 'shared-interfaces';
import { DataService } from '../../../../../libs/services/src/lib/data.service';
import { DialogService } from '../../../../../libs/services/src/lib/dialog.service';
import { EpgService } from '../../../../../libs/services/src/lib/epg.service';
import { PlaylistsService } from '../../../../../libs/services/src/lib/playlists.service';
import { SettingsStore } from '../services/settings-store.service';
import { HeaderComponent } from '../shared/components/header/header.component';
import { SettingsService } from './../services/settings.service';
@@ -6,12 +6,12 @@ import {
MatDialogRef,
} from '@angular/material/dialog';
import { MatSnackBar } from '@angular/material/snack-bar';
import { DataService } from '@iptvnator/services';
import { Store } from '@ngrx/store';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { parsePlaylist } from 'm3u-state';
import { getFilenameFromUrl } from 'm3u-utils';
import { PLAYLIST_PARSE_BY_URL } from 'shared-interfaces';
import { DataService } from '../../../../../../../libs/services/src/lib/data.service';
import { FileUploadComponent } from '../../../home/file-upload/file-upload.component';
import { StalkerPortalImportComponent } from '../../../home/stalker-portal-import/stalker-portal-import.component';
import { TextImportComponent } from '../../../home/text-import/text-import.component';
@@ -35,11 +35,13 @@ import { PlaylistErrorViewComponent } from '../../../xtream-tauri/playlist-error
$event.target.src =
'./assets/images/default-poster.png'
"
alt="logo"
/>
} @else {
<img
class="stream-icon"
src="./assets/images/default-poster.png"
alt="logo"
/>
}
@let rating = i.rating ?? i.rating_imdb;
@@ -2,8 +2,8 @@ import { Component, computed, inject, signal } from '@angular/core';
import { rxResource } from '@angular/core/rxjs-interop';
import { MatButton } from '@angular/material/button';
import { MatIcon } from '@angular/material/icon';
import { PlaylistsService } from '@iptvnator/services';
import { TranslatePipe, TranslateService } from '@ngx-translate/core';
import { PlaylistsService } from '../../../../../../libs/services/src/lib/playlists.service';
import { FavoritesLayoutComponent } from '../../shared/components/favorites-layout/favorites-layout.component';
import { VodDetailsComponent } from '../../xtream/vod-details/vod-details.component';
import { StalkerSeriesViewComponent } from '../stalker-series-view/stalker-series-view.component';
@@ -2,8 +2,8 @@ import { Component, computed, inject, signal } from '@angular/core';
import { rxResource } from '@angular/core/rxjs-interop';
import { MatButton } from '@angular/material/button';
import { MatIcon } from '@angular/material/icon';
import { PlaylistsService } from '@iptvnator/services';
import { TranslatePipe, TranslateService } from '@ngx-translate/core';
import { PlaylistsService } from '../../../../../../libs/services/src/lib/playlists.service';
import { FavoritesLayoutComponent } from '../../shared/components/favorites-layout/favorites-layout.component';
import { VodDetailsComponent } from '../../xtream/vod-details/vod-details.component';
import { StalkerSeriesViewComponent } from '../stalker-series-view/stalker-series-view.component';
@@ -5,9 +5,9 @@ import { MatListModule } from '@angular/material/list';
import { MatPaginatorModule } from '@angular/material/paginator';
import { MatSnackBar } from '@angular/material/snack-bar';
import { ActivatedRoute, Router, RouterOutlet } from '@angular/router';
import { PlaylistsService } from '@iptvnator/services';
import { TranslatePipe } from '@ngx-translate/core';
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
import { PlaylistsService } from '../../../../../libs/services/src/lib/playlists.service';
import { MpvPlayerBarComponent } from '../shared/components/mpv-player-bar/mpv-player-bar.component';
import { CategoryViewComponent } from '../xtream-tauri/category-view/category-view.component';
import { PlaylistErrorViewComponent } from '../xtream/playlist-error-view/playlist-error-view.component';
@@ -2,10 +2,10 @@ import { Component, Inject, inject } from '@angular/core';
import { MatButton } from '@angular/material/button';
import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
import { MatListModule } from '@angular/material/list';
import { DataService } from '@iptvnator/services';
import { Store } from '@ngrx/store';
import { TranslatePipe } from '@ngx-translate/core';
import { selectActivePlaylist } from 'm3u-state';
import { DataService } from '../../../../../../libs/services/src/lib/data.service';
import { XtreamAccountInfo } from './account-info.interface';
@Component({
@@ -15,9 +15,9 @@ import { XtreamAccountInfo } from './account-info.interface';
<h2 mat-dialog-title>Account Information</h2>
<mat-dialog-content class="mat-typography">
@if (accountInfo?.user_info?.message) {
<div class="welcome-message">
{{ accountInfo?.user_info?.message }}
</div>
<div class="welcome-message">
{{ accountInfo?.user_info?.message }}
</div>
}
<div class="info-grid">
<div class="info-section">
@@ -3,10 +3,10 @@ import { MatButtonModule } from '@angular/material/button';
import { MatDialog } from '@angular/material/dialog';
import { MatIconModule } from '@angular/material/icon';
import { Router, RouterLink } from '@angular/router';
import { DatabaseService, DialogService } from '@iptvnator/services';
import { DatabaseService } from '@iptvnator/services';
import { Store } from '@ngrx/store';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { PlaylistInfoComponent } from 'components';
import { DialogService, PlaylistInfoComponent } from 'components';
import * as PlaylistActions from 'm3u-state';
import { selectCurrentPlaylist } from 'm3u-state';
import { Playlist } from 'shared-interfaces';
@@ -23,10 +23,10 @@ import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIcon } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { ActivatedRoute, Router } from '@angular/router';
import { DatabaseService } from '@iptvnator/services';
import { TranslatePipe } from '@ngx-translate/core';
import groupBy from 'lodash/groupBy';
import { DatabaseService } from '../../../../../../libs/services/src/lib/database.service';
import { XtreamItem } from '../../../../../../libs/shared/interfaces/src/lib/xtream-item.interface';
import { XtreamItem } from 'shared-interfaces';
import { SearchFormComponent } from '../../shared/components/search-form/search-form.component';
import { SearchResultItemComponent } from '../../shared/components/search-result-item/search-result-item.component';
import { XtreamStore } from '../xtream.store';
@@ -1,6 +1,6 @@
import { inject, Injectable } from '@angular/core';
import { DatabaseService } from '@iptvnator/services';
import { from, map, mergeMap, Observable } from 'rxjs';
import { DatabaseService } from '../../../../../../libs/services/src/lib/database.service';
import { FavoriteItem } from './favorite-item.interface';
@Injectable({
@@ -1,11 +1,11 @@
import { inject } from '@angular/core';
import { DatabaseService } from '@iptvnator/services';
import {
patchState,
signalStoreFeature,
withMethods,
withState,
} from '@ngrx/signals';
import { DatabaseService } from '../../../../../libs/services/src/lib/database.service';
import { FavoritesService } from './services/favorites.service';
export const withFavorites = function () {
@@ -1,4 +1,5 @@
import { inject, Signal } from '@angular/core';
import { DatabaseService } from '@iptvnator/services';
import {
patchState,
signalStoreFeature,
@@ -7,7 +8,6 @@ import {
} from '@ngrx/signals';
import { rxMethod } from '@ngrx/signals/rxjs-interop';
import { pipe, switchMap, tap } from 'rxjs';
import { DatabaseService } from '../../../../../libs/services/src/lib/database.service';
export interface RecentlyViewedItem {
id: number;
@@ -5,7 +5,7 @@ import { MatIconModule } from '@angular/material/icon';
import { MatTooltipModule } from '@angular/material/tooltip';
import { FilterPipe, SortPipe } from '@iptvnator/pipes';
import { TranslateModule } from '@ngx-translate/core';
import { XtreamItem } from '../../../../../../libs/shared/interfaces/src/lib/xtream-item.interface';
import { XtreamItem } from 'shared-interfaces';
import { PlaylistErrorViewComponent } from '../playlist-error-view/playlist-error-view.component';
import { PortalStore } from '../portal.store';
@@ -3,10 +3,9 @@ import { MatButtonModule } from '@angular/material/button';
import { MatDialog } from '@angular/material/dialog';
import { MatIconModule } from '@angular/material/icon';
import { Router, RouterLink } from '@angular/router';
import { DialogService } from '@iptvnator/services';
import { Store } from '@ngrx/store';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { PlaylistInfoComponent } from 'components';
import { DialogService, PlaylistInfoComponent } from 'components';
import * as PlaylistActions from 'm3u-state';
import { selectCurrentPlaylist } from 'm3u-state';
import { Playlist } from 'shared-interfaces';
@@ -18,13 +17,13 @@ import { Playlist } from 'shared-interfaces';
imports: [MatButtonModule, MatIconModule, RouterLink, TranslateModule],
})
export class PlaylistErrorViewComponent {
dialog = inject(MatDialog);
dialogService = inject(DialogService);
router = inject(Router);
store = inject(Store);
translate = inject(TranslateService);
readonly dialog = inject(MatDialog);
readonly dialogService = inject(DialogService);
readonly router = inject(Router);
readonly store = inject(Store);
readonly translate = inject(TranslateService);
currentPlaylist = this.store.selectSignal(selectCurrentPlaylist);
readonly currentPlaylist = this.store.selectSignal(selectCurrentPlaylist);
@Input() description: string;
@Input() showActionButtons = true;
+1 -1
View File
@@ -14,7 +14,7 @@
"src/**/*.spec.ts",
"src/**/*.d.ts",
"../../libs/services/src/lib/epg.service.spec.ts",
"../../libs/services/src/lib/dialog.service.spec.ts",
"../../libs/ui/components/src/lib/confirm-dialog/dialog.service.spec.ts",
"../../libs/ui/pipes/src/lib/moment-date.pipe.spec.ts"
]
}
-1
View File
@@ -1,6 +1,5 @@
export * from './lib/data.service';
export * from './lib/database.service';
export * from './lib/dialog.service';
export * from './lib/epg.service';
export * from './lib/playlists.service';
export * from './lib/portal-status.service';
+3
View File
@@ -16,6 +16,7 @@ export * from './lib/stalker-portal-actions.enum';
export * from './lib/store-keys.enum';
export * from './lib/stream-format.enum';
export * from './lib/theme.enum';
export * from './lib/tokens';
export * from './lib/xtream-category.interface';
export * from './lib/xtream-code-actions';
export * from './lib/xtream-item.interface';
@@ -25,3 +26,5 @@ export * from './lib/xtream-serie-details.interface';
export * from './lib/xtream-serie-item.interface';
export * from './lib/xtream-vod-details.interface';
export * from './lib/xtream-vod-stream.interface';
import './lib/global.d';
@@ -1,9 +1,9 @@
import 'jest-extended';
import { Playlist } from 'shared-interfaces';
import { Playlist } from './playlist.interface';
declare module 'video.js' {
export interface VideoJsPlayer {
hlsQualitySelector(options?: any): void;
hlsQualitySelector(options?: Record<string, unknown>): void;
}
}
@@ -22,5 +22,13 @@ declare global {
) => Promise<Playlist>;
openPlaylistFromFile: () => Promise<Playlist>;
};
process: NodeJS.Process;
require: NodeRequire;
}
}
// SystemJS module definition
declare const nodeModule: NodeModule;
interface NodeModule {
id: string;
}
+5
View File
@@ -0,0 +1,5 @@
import { InjectionToken } from '@angular/core';
export const COMPONENT_OVERLAY_REF = new InjectionToken(
'COMPONENT_OVERLAY_REF'
);
@@ -1,4 +1,4 @@
import { XtreamItem } from 'shared-interfaces';
import { XtreamItem } from './xtream-item.interface';
export interface XtreamLiveStream extends XtreamItem {
stream_type: 'live';
@@ -1,4 +1,4 @@
import { XtreamItem } from 'shared-interfaces';
import { XtreamItem } from './xtream-item.interface';
export interface XtreamVodStream extends XtreamItem {
stream_type: 'movie';
+1 -1
View File
@@ -2,6 +2,7 @@ export * from './lib/art-player/art-player.component';
export * from './lib/audio-player/audio-player.component';
export * from './lib/channel-list-container/channel-list-container.component';
export * from './lib/confirm-dialog/confirm-dialog.component';
export * from './lib/confirm-dialog/dialog.service';
export * from './lib/epg-list/epg-item-description/epg-item-description.component';
export * from './lib/epg-list/epg-list-item/epg-list-item.component';
export * from './lib/epg-list/epg-list.component';
@@ -13,5 +14,4 @@ export * from './lib/recent-playlists/playlist-item/playlist-item.component';
export * from './lib/recent-playlists/recent-playlists.component';
export * from './lib/video-player/sidebar/sidebar.component';
export * from './lib/video-player/toolbar/toolbar.component';
export * from './lib/video-player/video-player.component';
export * from './lib/vjs-player/vjs-player.component';
@@ -3,7 +3,7 @@ import { MatDialog, MatDialogModule } from '@angular/material/dialog';
import { TranslateModule } from '@ngx-translate/core';
import { MockComponent, MockModule } from 'ng-mocks';
import { EMPTY } from 'rxjs';
import { ConfirmDialogData } from '../../../../apps/web/src/app/shared/components/confirm-dialog/confirm-dialog-data.interface';
import { ConfirmDialogData } from '../<../../../apps/web/src/app/shared/components/confirm-dialog/confirm-dialog-data.interface';
import { ConfirmDialogComponent } from '../../../../apps/web/src/app/shared/components/confirm-dialog/confirm-dialog.component';
import { DialogService } from './dialog.service';
@@ -1,6 +1,9 @@
import { inject, Injectable } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { ConfirmDialogComponent, ConfirmDialogData } from 'components';
import {
ConfirmDialogComponent,
ConfirmDialogData,
} from './confirm-dialog.component';
@Injectable({
providedIn: 'root',
@@ -1,8 +1,8 @@
import { Component, Inject } from '@angular/core';
import { Component, inject } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
import { TranslatePipe } from '@ngx-translate/core';
import { EpgProgram } from '../../../../../../shared/interfaces/src/lib/epg-program.model';
import { EpgProgram } from 'shared-interfaces';
@Component({
selector: 'app-epg-item-description',
@@ -11,6 +11,8 @@ import { EpgProgram } from '../../../../../../shared/interfaces/src/lib/epg-prog
imports: [MatButtonModule, MatDialogModule, TranslatePipe],
})
export class EpgItemDescriptionComponent {
dialogData = inject<EpgProgram>(MAT_DIALOG_DATA);
/** EPG program object */
epgProgram: EpgProgram;
@@ -18,7 +20,7 @@ export class EpgItemDescriptionComponent {
* Creates an instance of the component and injects the program of the clicked epg program
* @param epgProgram epg program
*/
constructor(@Inject(MAT_DIALOG_DATA) epgProgram: EpgProgram) {
this.epgProgram = epgProgram;
constructor() {
this.epgProgram = this.dialogData;
}
}
@@ -1,10 +1,10 @@
import { Component, Input } from '@angular/core';
import { Component, inject, Input } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { MatIcon } from '@angular/material/icon';
import { MatTooltip } from '@angular/material/tooltip';
import { MomentDatePipe } from '@iptvnator/pipes';
import { TranslatePipe } from '@ngx-translate/core';
import { EpgProgram } from '../../../../../../shared/interfaces/src/lib/epg-program.model';
import { MomentDatePipe } from '../../../../../pipes/src/lib/moment-date.pipe';
import { EpgProgram } from 'shared-interfaces';
import { EpgItemDescriptionComponent } from '../epg-item-description/epg-item-description.component';
@Component({
@@ -14,20 +14,16 @@ import { EpgItemDescriptionComponent } from '../epg-item-description/epg-item-de
styleUrls: ['./epg-list-item.component.scss'],
})
export class EpgListItemComponent {
private dialog = inject(MatDialog);
/** EPG Program to render */
@Input() item: EpgProgram;
@Input() item!: EpgProgram;
/** Actual time */
@Input() timeNow: string;
@Input() timeNow!: string;
/** Aviability of the timeshift function until date */
@Input() timeshiftUntil: string;
/**
* Creates an instance of EpgListItemComponent
* @param dialog angular material dialog
*/
constructor(private dialog: MatDialog) {}
@Input() timeshiftUntil!: string;
/**
* Opens the dialog with details about the selected program
@@ -6,7 +6,8 @@ import { MatDividerModule } from '@angular/material/divider';
import { MatIconModule } from '@angular/material/icon';
import { MatListModule } from '@angular/material/list';
import { MatTooltipModule } from '@angular/material/tooltip';
import { DataService } from '@iptvnator/services';
import { MomentDatePipe } from '@iptvnator/pipes';
import { DataService, EpgService } from '@iptvnator/services';
import { Store } from '@ngrx/store';
import { TranslatePipe } from '@ngx-translate/core';
import {
@@ -23,8 +24,6 @@ import {
EpgChannel,
EpgProgram,
} from 'shared-interfaces';
import { EpgService } from '../../../../../services/src/lib/epg.service';
import { MomentDatePipe } from '../../../../pipes/src/lib/moment-date.pipe';
import { EpgListItemComponent } from './epg-list-item/epg-list-item.component';
export interface EpgData {
@@ -1,8 +1,8 @@
import { NgStyle } from '@angular/common';
import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
import { MomentDatePipe } from '@iptvnator/pipes';
import moment from 'moment';
import { Channel, EpgProgram } from 'shared-interfaces';
import { MomentDatePipe } from '../../../../pipes/src/lib/moment-date.pipe';
@Component({
imports: [MomentDatePipe, NgStyle],
@@ -27,28 +27,28 @@ export class InfoOverlayComponent implements OnChanges {
finishedDuration!: number;
/** Program start time */
start;
start: any | undefined;
/** Program end time */
stop;
stop: any | undefined;
/** Timeout for the overlay visibility */
currentTimeout;
currentTimeout: number | undefined;
/**
* Calculates the necessary information for the visualization in the overview popup
* @param changes component input changes
*/
ngOnChanges(changes: SimpleChanges): void {
if (changes.channel) {
if (changes['channel'] && changes['channel'].currentValue) {
clearTimeout(this.currentTimeout);
this.isVisible = true;
this.currentTimeout = setTimeout(() => {
this.isVisible = false;
}, 4000);
}
if (changes.epgProgram && changes.epgProgram.currentValue) {
const { stop, start } = changes.epgProgram.currentValue;
if (changes['epgProgram'] && changes['epgProgram'].currentValue) {
const { stop, start } = changes['epgProgram'].currentValue;
this.setProgramDuration(start, stop);
}
}
@@ -16,16 +16,18 @@ import { MatButtonModule } from '@angular/material/button';
import { MatDialog } from '@angular/material/dialog';
import { MatIcon } from '@angular/material/icon';
import { MatTooltip } from '@angular/material/tooltip';
import { MomentDatePipe } from '@iptvnator/pipes';
import { TranslatePipe } from '@ngx-translate/core';
import { invoke } from '@tauri-apps/api/core';
import { addDays, differenceInMinutes, format, parse, subDays } from 'date-fns';
import { BehaviorSubject, Observable } from 'rxjs';
import { Channel } from 'shared-interfaces';
import { EpgChannel } from '../../../../../shared/interfaces/src/lib/epg-channel.model';
import { EpgProgram } from '../../../../../shared/interfaces/src/lib/epg-program.model';
import { MomentDatePipe } from '../../../../pipes/src/lib/moment-date.pipe';
import {
Channel,
COMPONENT_OVERLAY_REF,
EpgChannel,
EpgProgram,
} from 'shared-interfaces';
import { EpgItemDescriptionComponent } from '../epg-list/epg-item-description/epg-item-description.component';
import { COMPONENT_OVERLAY_REF } from '../video-player/video-player.component';
interface EnrichedProgram extends EpgProgram {
startDate: Date;
@@ -55,7 +57,7 @@ interface EnrichedChannel extends EpgChannel {
export class MultiEpgContainerComponent
implements OnInit, AfterViewInit, OnDestroy
{
@ViewChild('epgContainer') epgContainer: ElementRef;
@ViewChild('epgContainer') epgContainer!: ElementRef;
@Input() set playlistChannels(value: Observable<Channel[]>) {
if (value) {
@@ -17,7 +17,7 @@ import { NgxSkeletonLoaderComponent } from 'ngx-skeleton-loader';
import { Observable } from 'rxjs';
import { PLAYLIST_UPDATE, PlaylistMeta } from 'shared-interfaces';
import { ElectronServiceStub } from '../../../../../../apps/web/src/app/services/electron.service.stub';
import { DialogService } from '../../../../../services/src/lib/dialog.service';
import { DialogService } from '../confirm-dialog/dialog.service';
import { PlaylistItemComponent } from './playlist-item/playlist-item.component';
import { RecentPlaylistsComponent } from './recent-playlists.component';
@@ -18,12 +18,7 @@ import { MatInputModule } from '@angular/material/input';
import { MatListModule } from '@angular/material/list';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Router } from '@angular/router';
import {
DatabaseService,
DataService,
DialogService,
SortService,
} from '@iptvnator/services';
import { DatabaseService, DataService, SortService } from '@iptvnator/services';
import { Store } from '@ngrx/store';
import { TranslatePipe, TranslateService } from '@ngx-translate/core';
import * as PlaylistActions from 'm3u-state';
@@ -42,6 +37,7 @@ import {
PLAYLIST_UPDATE_RESPONSE,
PlaylistMeta,
} from 'shared-interfaces';
import { DialogService } from '../confirm-dialog/dialog.service';
import { PlaylistInfoComponent } from './playlist-info/playlist-info.component';
import { PlaylistItemComponent } from './playlist-item/playlist-item.component';
@@ -9,8 +9,8 @@ import { TranslatePipe } from '@ngx-translate/core';
import * as PlaylistActions from 'm3u-state';
import { selectPlaylistTitle } from 'm3u-state';
import { Channel } from 'shared-interfaces';
import { SidebarView } from '../../../../../../../apps/web/src/app/home/video-player/video-player.component';
import { RecentPlaylistsComponent } from '../../recent-playlists/recent-playlists.component';
import { SidebarView } from '../video-player.component';
import { ChannelListContainerComponent } from './../../channel-list-container/channel-list-container.component';
@Component({
@@ -26,7 +26,7 @@
<div class="spacer"></div>
<button
mat-icon-button
(click)="openSettings()"
(click)="settingsClicked.emit()"
[matTooltip]="'MENU.SETTINGS' | translate"
>
<mat-icon>settings</mat-icon>
@@ -1,7 +1,7 @@
import { AsyncPipe } from '@angular/common';
import { Component, EventEmitter, inject, Input, Output } from '@angular/core';
import { Component, inject, Input, output } from '@angular/core';
import { MatButton, MatIconButton } from '@angular/material/button';
import { MatDialog, MatDialogModule } from '@angular/material/dialog';
import { MatDialogModule } from '@angular/material/dialog';
import { MatIcon } from '@angular/material/icon';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatTooltip } from '@angular/material/tooltip';
@@ -14,7 +14,6 @@ import {
updateFavorites,
} from 'm3u-state';
import { Channel } from 'shared-interfaces';
import { SettingsComponent } from '../../../../../../../apps/web/src/app/settings/settings.component';
@Component({
imports: [
@@ -33,11 +32,11 @@ import { SettingsComponent } from '../../../../../../../apps/web/src/app/setting
})
export class ToolbarComponent {
@Input() activeChannel!: Channel;
@Output() multiEpgClicked = new EventEmitter<void>();
@Output() toggleLeftDrawerClicked = new EventEmitter<void>();
@Output() toggleRightDrawerClicked = new EventEmitter<void>();
readonly multiEpgClicked = output<void>();
readonly settingsClicked = output<void>();
readonly toggleLeftDrawerClicked = output<void>();
readonly toggleRightDrawerClicked = output<void>();
private readonly dialog = inject(MatDialog);
private readonly store = inject(Store);
readonly favorites$ = this.store.select(selectFavorites);
@@ -47,12 +46,4 @@ export class ToolbarComponent {
updateFavoriteStatus(channel: Channel) {
this.store.dispatch(updateFavorites({ channel }));
}
openSettings() {
this.dialog.open(SettingsComponent, {
width: '1000px',
height: '90%',
data: { isDialog: true },
});
}
}
@@ -26,11 +26,11 @@ import 'videojs-hls-quality-selector';
})
export class VjsPlayerComponent implements OnInit, OnChanges, OnDestroy {
/** DOM-element reference */
@ViewChild('target', { static: true }) target: ElementRef<Element>;
@ViewChild('target', { static: true }) target!: ElementRef<Element>;
/** Options of VideoJs player */
@Input() options: videoJs.PlayerOptions;
@Input() options!: videoJs.PlayerOptions;
/** VideoJs object */
player: videoJs.Player;
player!: videoJs.Player;
@Input() volume = 1;
/**
@@ -67,15 +67,15 @@ export class VjsPlayerComponent implements OnInit, OnChanges, OnDestroy {
* @param changes contains changed channel object
*/
ngOnChanges(changes: SimpleChanges): void {
if (changes.options.previousValue) {
this.player.src(changes.options.currentValue.sources[0]);
if (changes['options'].previousValue) {
this.player.src(changes['options'].currentValue.sources[0]);
}
if (changes.volume?.currentValue !== undefined && this.player) {
if (changes['volume']?.currentValue !== undefined && this.player) {
console.log(
'Setting VideoJS player volume to:',
changes.volume.currentValue
changes['volume'].currentValue
);
this.player.volume(changes.volume.currentValue);
this.player.volume(changes['volume'].currentValue);
}
}
+5 -1
View File
@@ -13,5 +13,9 @@
"jest.config.ts",
"src/**/*.test.ts"
],
"include": ["src/**/*.ts"]
"include": [
"src/**/*.ts",
"../../../apps/web/src/app/home/video-player/video-player.component.spec.ts",
"../../../apps/web/src/app/home/video-player/video-player.component.ts"
]
}
-1
View File
@@ -1,4 +1,3 @@
export * from './lib/filter-by-type.pipe';
export * from './lib/filter.pipe';
export * from './lib/moment-date.pipe';
export * from './lib/sort.pipe';
@@ -1,13 +0,0 @@
import { Pipe, PipeTransform } from '@angular/core';
import { FavoriteItem } from '../../../../../apps/web/src/app/xtream-tauri/services/favorite-item.interface';
@Pipe({
name: 'filterByType',
standalone: true,
})
export class FilterByTypePipe implements PipeTransform {
transform(items: FavoriteItem[] | null, type: string): FavoriteItem[] {
if (!items) return [];
return items.filter((item) => item.type === type);
}
}