refactor(nx): remove packages, fix build issues

This commit is contained in:
4gray committed 2025-10-14 23:44:33 +02:00
1 parent ad75cb2f1a
commit 7487738a7d
68 files changed
+616 -1496

No files matched your search

@@ -8,4 +8,6 @@ contextBridge.exposeInMainWorld('electron', {
updatePlaylistFromFilePath: (filePath: string, title: string) =>
ipcRenderer.invoke('update-playlist-from-file-path', filePath, title),
openPlaylistFromFile: () => ipcRenderer.invoke('open-playlist-from-file'),
setUserAgent: (userAgent: string, referer?: string) =>
ipcRenderer.send('set-user-agent', userAgent, referer),
});
+34 -4
View File
@@ -1,8 +1,22 @@
import { BrowserWindow, shell, screen } from 'electron';
import { rendererAppName, rendererAppPort } from './constants';
import { environment } from '../environments/environment';
import { BrowserWindow, screen, shell } from 'electron';
import Store from 'electron-store';
import { join } from 'path';
import { format } from 'url';
import { environment } from '../environments/environment';
import { rendererAppName, rendererAppPort } from './constants';
const WINDOW_BOUNDS = 'WINDOW_BOUNDS';
const MPV_PLAYER_PATH = 'MPV_PLAYER_PATH';
const VLC_PLAYER_PATH = 'VLC_PLAYER_PATH';
type StoreType = {
[WINDOW_BOUNDS]: Electron.Rectangle;
[MPV_PLAYER_PATH]: string;
[VLC_PLAYER_PATH]: string;
};
Store.initRenderer();
const store = new Store<StoreType>();
export default class App {
// Keep a global reference of the window object, if you don't, the window will
@@ -10,6 +24,7 @@ export default class App {
static mainWindow: Electron.BrowserWindow;
static application: Electron.App;
static BrowserWindow;
store = new Store<StoreType>();
public static isDevelopmentMode() {
const isEnvironmentSet: boolean = 'ELECTRON_IS_DEV' in process.env;
@@ -63,6 +78,8 @@ export default class App {
const width = Math.min(1280, workAreaSize.width || 1280);
const height = Math.min(720, workAreaSize.height || 720);
const savedWindowBounds = store.get(WINDOW_BOUNDS);
// Create the browser window.
App.mainWindow = new BrowserWindow({
width: width,
@@ -73,9 +90,12 @@ export default class App {
backgroundThrottling: false,
preload: join(__dirname, 'main.preload.js'),
},
...savedWindowBounds,
});
App.mainWindow.setMenu(null);
App.mainWindow.center();
if (!savedWindowBounds) {
App.mainWindow.center();
}
// if main window is ready to show, close the splash window and show the main window
App.mainWindow.once('ready-to-show', () => {
@@ -95,6 +115,12 @@ export default class App {
// when you should delete the corresponding element.
App.mainWindow = null;
});
App.mainWindow.on('close', () => {
if (App.mainWindow) {
store.set(WINDOW_BOUNDS, App.mainWindow.getNormalBounds());
}
});
}
private static loadMainWindow() {
@@ -130,5 +156,9 @@ export default class App {
App.application.on('window-all-closed', App.onWindowAllClosed); // Quit when all windows are closed.
App.application.on('ready', App.onReady); // App is ready to load data
App.application.on('activate', App.onActivate); // App is activated
App.application.on('before-quit', () => {
if (App.mainWindow)
store.set(WINDOW_BOUNDS, App.mainWindow.getNormalBounds());
});
}
}
@@ -0,0 +1,7 @@
import { ipcMain } from 'electron';
export default class PlayerEvents {
static bootstrapPlayerEvents(): Electron.IpcMain {
return ipcMain;
}
}
@@ -0,0 +1,39 @@
import { ipcMain, session } from 'electron';
export default class SharedEvents {
static bootstrapSharedEvents(): Electron.IpcMain {
return ipcMain;
}
}
ipcMain.handle('set-user-agent', (event, userAgent, referer) => {
setUserAgent(userAgent, referer);
return true;
});
/**
* Sets the user agent header for all http requests
* @param userAgent user agent to use
* @param referer referer to use
*/
export function setUserAgent(userAgent: string, referer?: string): void {
if (userAgent === undefined || userAgent === null || userAgent === '') {
userAgent = this.defaultUserAgent;
}
// Remove trailing slash from referer if it exists
let originURL: string;
if (referer?.endsWith('/')) {
originURL = referer.slice(0, -1);
}
session.defaultSession.webRequest.onBeforeSendHeaders(
(details, callback) => {
details.requestHeaders['User-Agent'] = userAgent;
details.requestHeaders['Referer'] = referer as string;
details.requestHeaders['Origin'] = originURL as string;
callback({ requestHeaders: details.requestHeaders });
}
);
console.log(`Success: Set "${userAgent}" as user agent header`);
}
+7
View File
@@ -1,7 +1,10 @@
import { app, BrowserWindow } from 'electron';
import fixPath from 'fix-path';
import App from './app/app';
import ElectronEvents from './app/events/electron.events';
import PlayerEvents from './app/events/player.events';
import PlaylistEvents from './app/events/playlist.events';
import SharedEvents from './app/events/shared.events';
import SquirrelEvents from './app/events/squirrel.events';
export default class Main {
@@ -19,6 +22,8 @@ export default class Main {
static bootstrapAppEvents() {
ElectronEvents.bootstrapElectronEvents();
PlaylistEvents.bootstrapPlaylistEvents();
SharedEvents.bootstrapSharedEvents();
PlayerEvents.bootstrapPlayerEvents();
// initialize auto updater service
if (!App.isDevelopmentMode()) {
@@ -27,6 +32,8 @@ export default class Main {
}
}
fixPath();
// handle setup events as quickly as possible
Main.initialize();
+14 -13
View File
@@ -1,15 +1,16 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"types": ["node"]
},
"exclude": [
"**/*.spec.ts",
"**/*.test.ts",
"jest.config.ts",
"src/**/*.spec.ts",
"src/**/*.test.ts"
],
"include": ["**/*.ts"]
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"types": ["node"]
},
"files": ["../../global.d.ts"],
"exclude": [
"**/*.spec.ts",
"**/*.test.ts",
"jest.config.ts",
"src/**/*.spec.ts",
"src/**/*.test.ts"
],
"include": ["**/*.ts"]
}
+7 -5
View File
@@ -1,7 +1,9 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"types": ["node"]
},
"include": ["**/*.ts"]
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"types": ["node"],
"moduleResolution": "nodenext",
"module": "NodeNext"
},
"include": ["**/*.ts"]
}
+1 -1
View File
@@ -35,7 +35,7 @@
{
"type": "initial",
"maximumWarning": "500kb",
"maximumError": "3mb"
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
+2 -4
View File
@@ -1,8 +1,6 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { isTauri } from '@tauri-apps/api/core';
import { stalkerRoutes } from './stalker/stalker.routes';
import { xtreamRoutes } from './xtream-tauri/xtream.routes';
const routes: Routes = [
{
@@ -38,7 +36,7 @@ const routes: Routes = [
(c) => c.SettingsComponent
),
},
...(isTauri()
/* ...(!!window.electron
? xtreamRoutes
: [
{
@@ -48,7 +46,7 @@ const routes: Routes = [
(c) => c.XtreamMainContainerComponent
),
},
]),
]), */
{
path: 'portals/:id',
loadComponent: () =>
+1 -1
View File
@@ -5,8 +5,8 @@ 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 { DataService, EpgService } from 'services';
import {
ERROR,
IpcCommand,
+1 -1
View File
@@ -7,7 +7,6 @@ import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ServiceWorkerModule } from '@angular/service-worker';
import { DataService } from '@iptvnator/services';
import { EffectsModule } from '@ngrx/effects';
import { StoreRouterConnectingModule, routerReducer } from '@ngrx/router-store';
import { StoreModule } from '@ngrx/store';
@@ -17,6 +16,7 @@ import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { PlaylistEffects, playlistReducer } from 'm3u-state';
import { NgxIndexedDBModule, NgxIndexedDBService } from 'ngx-indexed-db';
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
import { DataService } from 'services';
import { dbConfig } from 'shared-interfaces';
import { AppConfig } from '../environments/environment';
import '../polyfills';
+1 -1
View File
@@ -1,11 +1,11 @@
import { Component, inject, OnDestroy } from '@angular/core';
import { MatProgressBarModule } from '@angular/material/progress-bar';
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 { DataService } from 'services';
import { ERROR, Playlist, PLAYLIST_PARSE_RESPONSE } from 'shared-interfaces';
import { HeaderComponent } from '../shared/components/header/header.component';
@@ -9,10 +9,10 @@ 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 { DataService } from 'services';
import { Playlist } from 'shared-interfaces';
import { v4 as uuid } from 'uuid';
@@ -13,7 +13,6 @@ 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 {
@@ -34,6 +33,7 @@ import {
selectCurrentEpgProgram,
} from 'm3u-state';
import { Observable, combineLatestWith, filter, map, switchMap } from 'rxjs';
import { DataService, PlaylistsService } from 'services';
import {
CHANNEL_SET_USER_AGENT,
COMPONENT_OVERLAY_REF,
@@ -10,10 +10,10 @@ 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 { PortalStatus, PortalStatusService } from 'services';
import { Playlist } from 'shared-interfaces';
import { v4 as uuid } from 'uuid';
+1 -1
View File
@@ -1,6 +1,6 @@
import { Injectable, inject } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { DataService } from '@iptvnator/services';
import { DataService } from 'services';
import {
OPEN_MPV_PLAYER,
OPEN_VLC_PLAYER,
+1 -1
View File
@@ -3,11 +3,11 @@ 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';
import { catchError, firstValueFrom, throwError } from 'rxjs';
import { DataService } from 'services';
import {
ERROR,
Playlist,
+1 -1
View File
@@ -1,13 +1,13 @@
import { inject, Injectable } from '@angular/core';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Params } from '@angular/router';
import { DataService } from '@iptvnator/services';
import { invoke } from '@tauri-apps/api/core';
import { listen } from '@tauri-apps/api/event';
import { readTextFile } from '@tauri-apps/plugin-fs';
import { fetch } from '@tauri-apps/plugin-http';
import { parse } from 'iptv-playlist-parser';
import { createPlaylistObject } from 'm3u-utils';
import { DataService } from 'services';
import {
AUTO_UPDATE_PLAYLISTS,
AUTO_UPDATE_PLAYLISTS_RESPONSE,
@@ -30,7 +30,6 @@ 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';
@@ -38,6 +37,7 @@ import * as PlaylistActions from 'm3u-state';
import { selectIsEpgAvailable } from 'm3u-state';
import { take } from 'rxjs';
import * as semver from 'semver';
import { DataService, EpgService, PlaylistsService } from 'services';
import {
Language,
Playlist,
@@ -6,11 +6,11 @@ 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 { DataService } from 'services';
import { PLAYLIST_PARSE_BY_URL } from 'shared-interfaces';
import { FileUploadComponent } from '../../../home/file-upload/file-upload.component';
import { StalkerPortalImportComponent } from '../../../home/stalker-portal-import/stalker-portal-import.component';
@@ -9,15 +9,10 @@ import { MatMenuModule } from '@angular/material/menu';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatTooltipModule } from '@angular/material/tooltip';
import { ActivatedRoute, Router } from '@angular/router';
import {
DataService,
SortBy,
SortOrder,
SortService,
} from '@iptvnator/services';
import { Store } from '@ngrx/store';
import { TranslateModule } from '@ngx-translate/core';
import { open } from '@tauri-apps/plugin-shell';
import { DataService, SortBy, SortOrder, SortService } from 'services';
//import { shell } from 'electron';
import { selectActiveTypeFilters, setSelectedFilters } from 'm3u-state';
import { HomeComponent } from '../../../home/home.component';
import { AboutDialogComponent } from '../about-dialog/about-dialog.component';
@@ -116,7 +111,8 @@ export class HeaderComponent implements OnInit {
*/
async openUrl(url: string): Promise<void> {
if (this.isDesktop) {
await open(url);
console.log('TODO: implement me');
// await shell.openExternal(url);
} else {
window.open(url, '_blank');
}
@@ -1,5 +1,5 @@
import { Injectable } from '@angular/core';
import { invoke, isTauri } from '@tauri-apps/api/core';
import { invoke } from '@tauri-apps/api/core';
import { listen } from '@tauri-apps/api/event';
import { BehaviorSubject } from 'rxjs';
@@ -20,7 +20,7 @@ export class MpvPlayerService {
public activeProcesses$ = this.activeProcessesSubject.asObservable();
constructor() {
if (!isTauri()) {
if (!window.electron) {
return;
}
this.initializeEventListeners();
@@ -2,9 +2,9 @@ import { AsyncPipe } from '@angular/common';
import { Component, inject, input, output } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { PlaylistsService } from '@iptvnator/services';
import { TranslateModule } from '@ngx-translate/core';
import { BehaviorSubject, map, switchMap } from 'rxjs';
import { PlaylistsService } from 'services';
import { StalkerStore } from '../stalker.store';
@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 'services';
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 'services';
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 'services';
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';
@@ -4,10 +4,10 @@ import { MatCardModule } from '@angular/material/card';
import { MatIcon } from '@angular/material/icon';
import { MatProgressSpinner } from '@angular/material/progress-spinner';
import { ActivatedRoute } from '@angular/router';
import { DataService } from '@iptvnator/services';
import { Store } from '@ngrx/store';
import { TranslatePipe } from '@ngx-translate/core';
import { selectPlaylistById } from 'm3u-state';
import { DataService } from 'services';
import { STALKER_REQUEST, StalkerPortalActions } 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';
+1 -1
View File
@@ -1,6 +1,5 @@
import { computed, inject, resource, signal } from '@angular/core';
import { MatSnackBar } from '@angular/material/snack-bar';
import { DataService, PlaylistsService } from '@iptvnator/services';
import {
patchState,
signalStore,
@@ -10,6 +9,7 @@ import {
withState,
} from '@ngrx/signals';
import { TranslateService } from '@ngx-translate/core';
import { DataService, PlaylistsService } from 'services';
import {
PlaylistMeta,
STALKER_REQUEST,
@@ -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 'services';
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,12 +3,12 @@ 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 } from '@iptvnator/services';
import { Store } from '@ngrx/store';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { DialogService, PlaylistInfoComponent } from 'components';
import * as PlaylistActions from 'm3u-state';
import { selectCurrentPlaylist } from 'm3u-state';
import { DatabaseService } from 'services';
import { Playlist } from 'shared-interfaces';
@Component({
@@ -23,9 +23,9 @@ 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 'services';
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';
@@ -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 'services';
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 'services';
import { FavoritesService } from './services/favorites.service';
export const withFavorites = function () {
@@ -1,5 +1,4 @@
import { inject, Signal } from '@angular/core';
import { DatabaseService } from '@iptvnator/services';
import {
patchState,
signalStoreFeature,
@@ -8,6 +7,7 @@ import {
} from '@ngrx/signals';
import { rxMethod } from '@ngrx/signals/rxjs-interop';
import { pipe, switchMap, tap } from 'rxjs';
import { DatabaseService } from 'services';
export interface RecentlyViewedItem {
id: number;
@@ -1,4 +1,4 @@
import { GlobalSearchResult } from '@iptvnator/services';
import { GlobalSearchResult } from 'services';
import {
EpgItem,
XtreamCategory,
+16 -16
View File
@@ -1,6 +1,5 @@
import { computed, inject } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { DatabaseService, DataService } from '@iptvnator/services';
import {
patchState,
signalStore,
@@ -21,6 +20,7 @@ import {
switchMap,
tap,
} from 'rxjs';
import { DatabaseService, DataService } from 'services';
import {
Playlist,
XtreamCodeActions,
@@ -84,8 +84,8 @@ export const XtreamStore = signalStore(
return type === 'live'
? store.liveCategories()
: type === 'vod'
? store.vodCategories()
: store.serialCategories();
? store.vodCategories()
: store.serialCategories();
}),
getSelectedCategory: computed(() => {
const categoryId = store.selectedCategoryId();
@@ -102,8 +102,8 @@ export const XtreamStore = signalStore(
categoryType === 'live'
? store.liveStreams()
: categoryType === 'vod'
? store.vodStreams()
: store.serialStreams();
? store.vodStreams()
: store.serialStreams();
if (!store.selectedItem()) return null;
@@ -128,8 +128,8 @@ export const XtreamStore = signalStore(
categoryType === 'live'
? store.liveStreams()
: categoryType === 'vod'
? store.vodStreams()
: store.serialStreams();
? store.vodStreams()
: store.serialStreams();
return content
.filter((item) => item.category_id === categoryId)
@@ -148,13 +148,13 @@ export const XtreamStore = signalStore(
.filter((i) => Number((i as any).id) === categoryId)
.length
: categoryType === 'vod'
? store
.vodStreams()
.filter((i) => Number(i.category_id) === categoryId)
.length
: store
.serialStreams()
.filter((i) => i.category_id === categoryId).length;
? store
.vodStreams()
.filter((i) => Number(i.category_id) === categoryId)
.length
: store
.serialStreams()
.filter((i) => i.category_id === categoryId).length;
return Math.ceil(totalItems / store.limit());
}),
@@ -165,8 +165,8 @@ export const XtreamStore = signalStore(
categoryType === 'live'
? store.liveStreams()
: categoryType === 'vod'
? store.vodStreams()
: store.serialStreams();
? store.vodStreams()
: store.serialStreams();
return content.filter((item) => item.category_id === categoryId);
}),
@@ -2,10 +2,10 @@ import { Component, EventEmitter, Input, Output, inject } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { ActivatedRoute } from '@angular/router';
import { PlaylistsService } from '@iptvnator/services';
import { Store } from '@ngrx/store';
import { TranslateModule } from '@ngx-translate/core';
import { selectCurrentPlaylist } from 'm3u-state';
import { PlaylistsService } from 'services';
import { XtreamSerieDetails, XtreamSerieEpisode } from 'shared-interfaces';
import { SeasonContainerComponent } from '../season-container/season-container.component';
@@ -10,8 +10,8 @@ import { MatButtonModule } from '@angular/material/button';
import { MatIcon } from '@angular/material/icon';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { ActivatedRoute } from '@angular/router';
import { PlaylistsService } from '@iptvnator/services';
import { TranslatePipe } from '@ngx-translate/core';
import { PlaylistsService } from 'services';
import { XtreamVodDetails } from 'shared-interfaces';
import { SafePipe } from './safe.pipe';
@@ -14,11 +14,11 @@ import { MatDialog } from '@angular/material/dialog';
import { MatIconModule } from '@angular/material/icon';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatSnackBar } from '@angular/material/snack-bar';
import { DataService, PlaylistsService } from '@iptvnator/services';
import { Store } from '@ngrx/store';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { selectCurrentPlaylist } from 'm3u-state';
import { Observable } from 'rxjs';
import { DataService, PlaylistsService } from 'services';
import {
ERROR,
EpgItem,
+1
View File
@@ -4,6 +4,7 @@
"outDir": "../../dist/out-tsc",
"types": []
},
"files": ["../../global.d.ts"],
"include": ["src/**/*.ts"],
"exclude": [
"jest.config.ts",
+2 -1
View File
@@ -1,5 +1,5 @@
import 'jest-extended';
import { Playlist } from './playlist.interface';
import { Playlist } from './libs/shared/interfaces/src/lib/playlist.interface';
declare module 'video.js' {
export interface VideoJsPlayer {
@@ -21,6 +21,7 @@ declare global {
title: string
) => Promise<Playlist>;
openPlaylistFromFile: () => Promise<Playlist>;
setUserAgent: (userAgent: string, referer?: string) => void;
};
process: NodeJS.Process;
require: NodeRequire;
+1 -1
View File
@@ -1,7 +1,6 @@
import { inject, Injectable } from '@angular/core';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Router } from '@angular/router';
import { DataService, PlaylistsService } from '@iptvnator/services';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { Store } from '@ngrx/store';
import { StorageMap } from '@ngx-pwa/local-storage';
@@ -15,6 +14,7 @@ import {
tap,
withLatestFrom,
} from 'rxjs';
import { DataService, PlaylistsService } from 'services';
import {
CHANNEL_SET_USER_AGENT,
EPG_GET_PROGRAM,
+1 -5
View File
@@ -2,10 +2,6 @@
This library was generated with [Nx](https://nx.dev).
## Building
Run `nx build services` to build the library.
## Running unit tests
Run `nx test services` to execute the unit tests via [Jest](https://jestjs.io).
Run `nx test services` to execute the unit tests.
+21 -8
View File
@@ -1,21 +1,34 @@
import nx from '@nx/eslint-plugin';
import baseConfig from '../../eslint.config.mjs';
export default [
...baseConfig,
...nx.configs['flat/angular'],
...nx.configs['flat/angular-template'],
{
files: ['**/*.json'],
files: ['**/*.ts'],
rules: {
'@nx/dependency-checks': [
'@angular-eslint/directive-selector': [
'error',
{
ignoredFiles: [
'{projectRoot}/eslint.config.{js,cjs,mjs,ts,cts,mts}',
],
type: 'attribute',
prefix: 'lib',
style: 'camelCase',
},
],
'@angular-eslint/component-selector': [
'error',
{
type: 'element',
prefix: 'lib',
style: 'kebab-case',
},
],
},
languageOptions: {
parser: await import('jsonc-eslint-parser'),
},
},
{
files: ['**/*.html'],
// Override or add rules here
rules: {},
},
];
+15 -7
View File
@@ -1,13 +1,21 @@
export default {
displayName: '@iptvnator/services',
displayName: 'services',
preset: '../../jest.preset.js',
testEnvironment: 'node',
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
coverageDirectory: '../../coverage/libs/services',
transform: {
'^.+\\.[tj]s$': [
'ts-jest',
{ tsconfig: '<rootDir>/tsconfig.spec.json' },
'^.+\\.(ts|mjs|js|html)$': [
'jest-preset-angular',
{
tsconfig: '<rootDir>/tsconfig.spec.json',
stringifyContentPathRegex: '\\.(html|svg)$',
},
],
},
moduleFileExtensions: ['ts', 'js', 'html'],
coverageDirectory: '../../coverage/libs/services',
transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'],
snapshotSerializers: [
'jest-preset-angular/build/serializers/no-ng-attributes',
'jest-preset-angular/build/serializers/ng-snapshot',
'jest-preset-angular/build/serializers/html-comment',
],
};
-11
View File
@@ -1,11 +0,0 @@
{
"name": "@iptvnator/services",
"version": "0.0.1",
"private": true,
"type": "commonjs",
"main": "./src/index.js",
"types": "./src/index.d.ts",
"dependencies": {
"tslib": "^2.3.0"
}
}
+7 -12
View File
@@ -1,26 +1,21 @@
{
"name": "@iptvnator/services",
"name": "services",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "libs/services/src",
"prefix": "lib",
"projectType": "library",
"tags": [],
"targets": {
"build": {
"executor": "@nx/js:tsc",
"outputs": ["{options.outputPath}"],
"options": {
"outputPath": "dist/libs/services",
"main": "libs/services/src/index.ts",
"tsConfig": "libs/services/tsconfig.lib.json",
"assets": ["libs/services/*.md"]
}
},
"test": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
"options": {
"jestConfig": "libs/services/jest.config.ts"
"jestConfig": "libs/services/jest.config.ts",
"tsConfig": "libs/services/tsconfig.spec.json"
}
},
"lint": {
"executor": "@nx/eslint:lint"
}
}
}
+1 -1
View File
@@ -15,7 +15,7 @@ export abstract class DataService {
return null;
}
abstract getAppVersion(): string;
abstract sendIpcEvent(type: string, payload?: unknown);
abstract sendIpcEvent(type: string, payload?: unknown): any;
abstract removeAllListeners(type: string): void;
abstract fetchData(url: string, queryParams: Params): any;
abstract listenOn(
+9 -5
View File
@@ -95,7 +95,7 @@ export class EpgService {
* Shows fetch in progress snackbar
*/
showFetchSnackbar(): void {
this.snackBar.open(this.translate.instant('EPG.FETCH_EPG'), null, {
this.snackBar.open(this.translate.instant('EPG.FETCH_EPG'), undefined, {
duration: 2000,
horizontalPosition: 'start',
});
@@ -105,10 +105,14 @@ export class EpgService {
* Shows success snackbar
*/
private showSuccessSnackbar(): void {
this.snackBar.open(this.translate.instant('EPG.FETCH_SUCCESS'), null, {
duration: 2000,
horizontalPosition: 'start',
});
this.snackBar.open(
this.translate.instant('EPG.FETCH_SUCCESS'),
undefined,
{
duration: 2000,
horizontalPosition: 'start',
}
);
}
/**
+6
View File
@@ -0,0 +1,6 @@
import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone';
setupZoneTestEnv({
errorOnUnknownElements: true,
errorOnUnknownProperties: true,
});
+11 -4
View File
@@ -1,14 +1,21 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"module": "commonjs",
"forceConsistentCasingInFileNames": true,
"target": "es2022",
"moduleResolution": "bundler",
"strict": true,
"importHelpers": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"noPropertyAccessFromIndexSignature": true
"module": "preserve"
},
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"typeCheckHostBindings": true,
"strictTemplates": true
},
"files": [],
"include": [],
+10 -3
View File
@@ -3,8 +3,15 @@
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"declaration": true,
"types": ["node"]
"declarationMap": true,
"inlineSources": true,
"types": []
},
"include": ["src/**/*.ts"],
"exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"]
"exclude": [
"src/**/*.spec.ts",
"src/test-setup.ts",
"jest.config.ts",
"src/**/*.test.ts"
],
"include": ["src/**/*.ts", "../../../global.d.ts"]
}
+4 -2
View File
@@ -3,9 +3,11 @@
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"moduleResolution": "node10",
"types": ["jest", "node"]
"target": "es2016",
"types": ["jest", "node"],
"moduleResolution": "node10"
},
"files": ["src/test-setup.ts"],
"include": [
"jest.config.ts",
"src/**/*.test.ts",
-2
View File
@@ -26,5 +26,3 @@ 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,5 +1,8 @@
export class IpcCommand {
constructor(public id: string, public callback: (payload) => void) {
constructor(
public id: string,
public callback: (payload: any) => void
) {
this.id = id;
this.callback = callback;
}
+1 -1
View File
@@ -5,6 +5,6 @@
"declaration": true,
"types": ["node"]
},
"include": ["src/**/*.ts"],
"include": ["src/**/*.ts", "../../../global.d.ts"],
"exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"]
}
@@ -24,13 +24,13 @@ import { MatListModule } from '@angular/material/list';
import { MatSnackBar } from '@angular/material/snack-bar';
import { MatTabsModule } from '@angular/material/tabs';
import { FilterPipe } from '@iptvnator/pipes';
import { EpgService } from '@iptvnator/services';
import { Store } from '@ngrx/store';
import { TranslatePipe, TranslateService } from '@ngx-translate/core';
import * as _ from 'lodash';
import * as PlaylistActions from 'm3u-state';
import { selectActivePlaylistId, selectFavorites } from 'm3u-state';
import { map, skipWhile } from 'rxjs';
import { EpgService } from 'services';
import { Channel } from 'shared-interfaces';
import { ChannelListItemComponent } from './channel-list-item/channel-list-item.component';
@@ -7,7 +7,6 @@ import { MatIconModule } from '@angular/material/icon';
import { MatListModule } from '@angular/material/list';
import { MatTooltipModule } from '@angular/material/tooltip';
import { MomentDatePipe } from '@iptvnator/pipes';
import { DataService, EpgService } from '@iptvnator/services';
import { Store } from '@ngrx/store';
import { TranslatePipe } from '@ngx-translate/core';
import {
@@ -19,6 +18,7 @@ import {
import moment from 'moment';
import { BehaviorSubject, combineLatest, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { DataService, EpgService } from 'services';
import {
EPG_GET_PROGRAM_DONE,
EpgChannel,
@@ -9,9 +9,9 @@ import {
SimpleChanges,
ViewChild,
} from '@angular/core';
import { DataService } from '@iptvnator/services';
import Hls from 'hls.js';
import { getExtensionFromUrl } from 'm3u-utils';
import { DataService } from 'services';
import { Channel, CHANNEL_SET_USER_AGENT } from 'shared-interfaces';
/**
@@ -33,7 +33,7 @@ export class InfoOverlayComponent implements OnChanges {
stop: any | undefined;
/** Timeout for the overlay visibility */
currentTimeout: number | undefined;
currentTimeout: any;
/**
* Calculates the necessary information for the visualization in the overview popup
@@ -14,13 +14,13 @@ import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatSnackBar } from '@angular/material/snack-bar';
import { DatabaseService, PlaylistsService } from '@iptvnator/services';
import { Store } from '@ngrx/store';
import { TranslatePipe, TranslateService } from '@ngx-translate/core';
import { save } from '@tauri-apps/plugin-dialog';
import { writeTextFile } from '@tauri-apps/plugin-fs';
import * as PlaylistActions from 'm3u-state';
import { firstValueFrom } from 'rxjs';
import { DatabaseService, PlaylistsService } from 'services';
import { Playlist, PlaylistMeta } from 'shared-interfaces';
@Component({
@@ -4,8 +4,8 @@ import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatListModule } from '@angular/material/list';
import { MatTooltipModule } from '@angular/material/tooltip';
import { PortalStatus, PortalStatusService } from '@iptvnator/services';
import { TranslatePipe } from '@ngx-translate/core';
import { PortalStatus, PortalStatusService } from 'services';
import { PlaylistMeta } from 'shared-interfaces';
@Component({
@@ -6,7 +6,6 @@ import { MatInputModule } from '@angular/material/input';
import { MatListModule } from '@angular/material/list';
import { MatSnackBar } from '@angular/material/snack-bar';
import { MatTooltipModule } from '@angular/material/tooltip';
import { DataService } from '@iptvnator/services';
import { Actions } from '@ngrx/effects';
import { provideMockActions } from '@ngrx/effects/testing';
import { MockStore, provideMockStore } from '@ngrx/store/testing';
@@ -15,6 +14,7 @@ import { initialPlaylistMetaState } from 'm3u-state';
import { MockComponent, MockModule, MockProvider } from 'ng-mocks';
import { NgxSkeletonLoaderComponent } from 'ngx-skeleton-loader';
import { Observable } from 'rxjs';
import { DataService } from 'services';
import { PLAYLIST_UPDATE, PlaylistMeta } from 'shared-interfaces';
import { ElectronServiceStub } from '../../../../../../apps/web/src/app/services/electron.service.stub';
import { DialogService } from '../confirm-dialog/dialog.service';
@@ -18,7 +18,6 @@ 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, SortService } from '@iptvnator/services';
import { Store } from '@ngrx/store';
import { TranslatePipe, TranslateService } from '@ngx-translate/core';
import * as PlaylistActions from 'm3u-state';
@@ -29,6 +28,7 @@ import {
} from 'm3u-state';
import { NgxSkeletonLoaderComponent } from 'ngx-skeleton-loader';
import { BehaviorSubject, combineLatest, map } from 'rxjs';
import { DatabaseService, DataService, SortService } from 'services';
import {
AUTO_UPDATE_PLAYLISTS_RESPONSE,
GLOBAL_FAVORITES_PLAYLIST_ID,
+1
View File
@@ -7,6 +7,7 @@
"inlineSources": true,
"types": []
},
"files": ["../../../global.d.ts"],
"exclude": [
"src/**/*.spec.ts",
"src/test-setup.ts",
+340 -1328
View File
File diff suppressed because it is too large. Load diff
+5 -11
View File
@@ -60,27 +60,24 @@
"@tauri-apps/plugin-dialog": "2.2.0",
"@tauri-apps/plugin-fs": "2.2.0",
"@tauri-apps/plugin-http": "2.3.0",
"@tauri-apps/plugin-os": "2.2.0",
"@tauri-apps/plugin-process": "2.2.0",
"@tauri-apps/plugin-shell": "2.2.0",
"@tauri-apps/plugin-sql": "2.2.0",
"@tauri-apps/plugin-updater": "2.5.1",
"@tauri-apps/plugin-window-state": "2.2.1",
"@videojs/http-streaming": "2.15.0",
"@yangkghjh/videojs-aspect-ratio-panel": "0.0.1",
"artplayer": "5.3.0",
"axios": "1.12.2",
"date-fns": "2.29.3",
"electron-store": "11.0.2",
"epg-parser": "0.1.6",
"fix-path": "5.0.0",
"hls.js": "1.6.13",
"iptv-playlist-parser": "github:4gray/iptv-playlist-parser",
"lodash": "4.17.21",
"moment": "2.30.1",
"ngx-indexed-db": "19.0.0",
"ngx-skeleton-loader": "10.0.0",
"ngx-skeleton-loader": "11.3.0",
"node-mpv": "github:4gray/Node-MPV",
"rxjs": "7.8.2",
"semver": "7.7.2",
"semver": "7.7.3",
"uuid": "9.0.0",
"video.js": "7.20.3",
"videojs-contrib-quality-levels": "2.2.0",
@@ -159,8 +156,6 @@
"jest-util": "^30.0.2",
"jsonc-eslint-parser": "^2.1.0",
"ng-mocks": "14.13.2",
"node-polyfill-webpack-plugin": "1.1.4",
"npm-run-all": "4.1.5",
"nx": "21.4.1",
"nx-electron": "^21.0.1",
"playwright": "1.46.1",
@@ -171,7 +166,6 @@
"ts-node": "10.9.1",
"tslib": "^2.3.0",
"typescript": "~5.8.2",
"typescript-eslint": "^8.29.0",
"wait-on": "6.0.0"
"typescript-eslint": "^8.29.0"
}
}
+3 -2
View File
@@ -16,14 +16,15 @@
"baseUrl": ".",
"paths": {
"@iptvnator/pipes": ["libs/ui/pipes/src/index.ts"],
"@iptvnator/services": ["libs/services/src/index.ts"],
"@package": ["./package.json"],
"components": ["libs/ui/components/src/index.ts"],
"m3u-state": ["libs/m3u-state/src/index.ts"],
"m3u-utils": ["libs/shared/m3u-utils/src/index.ts"],
"services": ["libs/services/src/index.ts"],
"shared-interfaces": ["libs/shared/interfaces/src/index.ts"],
"shared-portals": ["libs/ui/shared-portals/src/index.ts"]
}
},
"exclude": ["node_modules", "tmp"]
"exclude": ["node_modules", "tmp"],
"files": ["global.d.ts"]
}