diff --git a/apps/electron-backend/src/app/api/main.preload.ts b/apps/electron-backend/src/app/api/main.preload.ts index 37f2214d6..ab62c2f51 100644 --- a/apps/electron-backend/src/app/api/main.preload.ts +++ b/apps/electron-backend/src/app/api/main.preload.ts @@ -1,6 +1,8 @@ import { contextBridge, ipcRenderer } from 'electron'; contextBridge.exposeInMainWorld('electron', { - getAppVersion: () => ipcRenderer.invoke('get-app-version'), - platform: process.platform, + getAppVersion: () => ipcRenderer.invoke('get-app-version'), + platform: process.platform, + fetchPlaylistByUrl: (url: string) => + ipcRenderer.invoke('fetch-playlist-by-url', url), }); diff --git a/apps/electron-backend/src/app/events/playlist.events.ts b/apps/electron-backend/src/app/events/playlist.events.ts new file mode 100644 index 000000000..d0dfba480 --- /dev/null +++ b/apps/electron-backend/src/app/events/playlist.events.ts @@ -0,0 +1,47 @@ +/** + * This module is responsible on handling all the inter process communications + * between the frontend to the electron backend. + */ + +import axios from 'axios'; +import { ipcMain } from 'electron'; +import { parse } from 'iptv-playlist-parser'; +import { createPlaylistObject, getFilenameFromUrl } from 'm3u-utils'; + +export default class PlaylistEvents { + static bootstrapPlaylistEvents(): Electron.IpcMain { + return ipcMain; + } +} + +const https = require('https'); + +// Retrieve app version +ipcMain.handle('fetch-playlist-by-url', async (event, url) => { + try { + const agent = new https.Agent({ + rejectUnauthorized: false, + }); + const result = await axios.get(url, { httpsAgent: agent }); + const parsedPlaylist = parse(result.data); + + const extractedName = + url && url.length > 1 ? getFilenameFromUrl(url) : ''; + const playlistName = + !extractedName || extractedName === 'Untitled playlist' + ? 'Imported from URL' + : extractedName; + + const playlistObject = createPlaylistObject( + playlistName, + parsedPlaylist, + url, + 'URL' + ); + + return playlistObject; + } catch (error) { + console.error('Error fetching playlist:', error); + throw error; + } +}); diff --git a/apps/electron-backend/src/main.ts b/apps/electron-backend/src/main.ts index 6c871db48..40a41a7ce 100644 --- a/apps/electron-backend/src/main.ts +++ b/apps/electron-backend/src/main.ts @@ -1,29 +1,30 @@ -import SquirrelEvents from './app/events/squirrel.events'; -import ElectronEvents from './app/events/electron.events'; -import UpdateEvents from './app/events/update.events'; import { app, BrowserWindow } from 'electron'; import App from './app/app'; +import ElectronEvents from './app/events/electron.events'; +import PlaylistEvents from './app/events/playlist.events'; +import SquirrelEvents from './app/events/squirrel.events'; export default class Main { - static initialize() { - if (SquirrelEvents.handleEvents()) { - // squirrel event handled (except first run event) and app will exit in 1000ms, so don't do anything else - app.quit(); + static initialize() { + if (SquirrelEvents.handleEvents()) { + // squirrel event handled (except first run event) and app will exit in 1000ms, so don't do anything else + app.quit(); + } } - } - static bootstrapApp() { - App.main(app, BrowserWindow); - } - - static bootstrapAppEvents() { - ElectronEvents.bootstrapElectronEvents(); - - // initialize auto updater service - if (!App.isDevelopmentMode()) { - // UpdateEvents.initAutoUpdateService(); + static bootstrapApp() { + App.main(app, BrowserWindow); + } + + static bootstrapAppEvents() { + ElectronEvents.bootstrapElectronEvents(); + PlaylistEvents.bootstrapPlaylistEvents(); + + // initialize auto updater service + if (!App.isDevelopmentMode()) { + // UpdateEvents.initAutoUpdateService(); + } } - } } // handle setup events as quickly as possible diff --git a/apps/web/src/app/app.module.ts b/apps/web/src/app/app.module.ts index 1303161c3..73ee8da7b 100644 --- a/apps/web/src/app/app.module.ts +++ b/apps/web/src/app/app.module.ts @@ -38,7 +38,7 @@ export function HttpLoaderFactory(http: HttpClient): TranslateHttpLoader { * Conditionally imports the necessary service based on the current environment */ export function DataFactory() { - if (isTauri()) { + if (window.electron) { return new TauriService(); } return new PwaService(); diff --git a/apps/web/src/app/home/home.component.ts b/apps/web/src/app/home/home.component.ts index fa1596db0..0438db85a 100644 --- a/apps/web/src/app/home/home.component.ts +++ b/apps/web/src/app/home/home.component.ts @@ -1,11 +1,10 @@ - -import { Component, NgZone } from '@angular/core'; +import { Component, inject, OnDestroy } from '@angular/core'; import { MatProgressBarModule } from '@angular/material/progress-bar'; import { MatSnackBar } from '@angular/material/snack-bar'; import { Store } from '@ngrx/store'; import { TranslatePipe } from '@ngx-translate/core'; +import { Playlist } from 'shared-interfaces'; import { ERROR, PLAYLIST_PARSE_RESPONSE } from '../../shared/ipc-commands'; -import { Playlist } from '../../shared/playlist.interface'; import { DataService } from '../services/data.service'; import { HeaderComponent } from '../shared/components/header/header.component'; import { addPlaylist } from '../state/actions'; @@ -16,13 +15,17 @@ import { RecentPlaylistsComponent } from './recent-playlists/recent-playlists.co templateUrl: './home.component.html', styleUrls: ['./home.component.scss'], imports: [ - HeaderComponent, - MatProgressBarModule, - RecentPlaylistsComponent, - TranslatePipe -], + HeaderComponent, + MatProgressBarModule, + RecentPlaylistsComponent, + TranslatePipe, + ], }) -export class HomeComponent { +export class HomeComponent implements OnDestroy { + private dataService = inject(DataService); + private snackBar = inject(MatSnackBar); + private readonly store = inject(Store); + /** Loading spinner state */ isLoading = false; @@ -48,12 +51,7 @@ export class HomeComponent { listeners = []; - constructor( - private dataService: DataService, - private ngZone: NgZone, - private snackBar: MatSnackBar, - private readonly store: Store - ) { + constructor() { this.setRendererListeners(); } diff --git a/apps/web/src/app/home/recent-playlists/playlist-info/playlist-info.component.ts b/apps/web/src/app/home/recent-playlists/playlist-info/playlist-info.component.ts index be220221e..327ac4e31 100644 --- a/apps/web/src/app/home/recent-playlists/playlist-info/playlist-info.component.ts +++ b/apps/web/src/app/home/recent-playlists/playlist-info/playlist-info.component.ts @@ -20,7 +20,7 @@ import { isTauri } from '@tauri-apps/api/core'; import { save } from '@tauri-apps/plugin-dialog'; import { writeTextFile } from '@tauri-apps/plugin-fs'; import { firstValueFrom } from 'rxjs'; -import { Playlist } from '../../../../shared/playlist.interface'; +import { Playlist } from 'shared-interfaces'; import { DatabaseService } from '../../../services/database.service'; import { PlaylistsService } from '../../../services/playlists.service'; import { PlaylistMeta } from '../../../shared/playlist-meta.type'; diff --git a/apps/web/src/app/home/recent-playlists/recent-playlists.component.ts b/apps/web/src/app/home/recent-playlists/recent-playlists.component.ts index a1456de7b..5da99fc20 100644 --- a/apps/web/src/app/home/recent-playlists/recent-playlists.component.ts +++ b/apps/web/src/app/home/recent-playlists/recent-playlists.component.ts @@ -4,7 +4,6 @@ import { Component, ElementRef, EventEmitter, - HostListener, Input, OnDestroy, OnInit, @@ -23,8 +22,7 @@ import { Store } from '@ngrx/store'; import { TranslatePipe, TranslateService } from '@ngx-translate/core'; import { NgxSkeletonLoaderComponent } from 'ngx-skeleton-loader'; import { BehaviorSubject, combineLatest, map } from 'rxjs'; -import { GLOBAL_FAVORITES_PLAYLIST_ID } from '../../../shared/constants'; -import { Playlist } from '../../../shared/playlist.interface'; +import { GLOBAL_FAVORITES_PLAYLIST_ID, Playlist } from 'shared-interfaces'; import { DataService } from '../../services/data.service'; import { DatabaseService } from '../../services/database.service'; import { SortService } from '../../services/sort.service'; diff --git a/apps/web/src/app/home/stalker-portal-import/stalker-portal-import.component.ts b/apps/web/src/app/home/stalker-portal-import/stalker-portal-import.component.ts index f2c7ad3fc..40b91299a 100644 --- a/apps/web/src/app/home/stalker-portal-import/stalker-portal-import.component.ts +++ b/apps/web/src/app/home/stalker-portal-import/stalker-portal-import.component.ts @@ -11,8 +11,8 @@ import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; import { Store } from '@ngrx/store'; import { TranslatePipe } from '@ngx-translate/core'; +import { Playlist } from 'shared-interfaces'; import { v4 as uuid } from 'uuid'; -import { Playlist } from '../../../shared/playlist.interface'; import { DataService } from '../../services/data.service'; import { addPlaylist } from '../../state/actions'; diff --git a/apps/web/src/app/home/url-upload/url-upload.component.html b/apps/web/src/app/home/url-upload/url-upload.component.html index edc39bc04..0db7cbf21 100644 --- a/apps/web/src/app/home/url-upload/url-upload.component.html +++ b/apps/web/src/app/home/url-upload/url-upload.component.html @@ -7,10 +7,10 @@ formControlName="playlistUrl" /> - @if (!isTauri) { -

- {{ 'HOME.URL_UPLOAD.CORS_NOTE' | translate }} -

+ @if (!isDesktop) { +

+ {{ 'HOME.URL_UPLOAD.CORS_NOTE' | translate }} +

}