diff --git a/api.ts b/api.ts index d2c58dc46..e635dbf98 100644 --- a/api.ts +++ b/api.ts @@ -3,6 +3,7 @@ import axios from 'axios'; import { app, BrowserWindow, ipcMain, session } from 'electron'; import { parse } from 'iptv-playlist-parser'; import Nedb, { Cursor } from 'nedb-promises-ts'; +import { GLOBAL_FAVORITES_PLAYLIST_ID } from './shared/constants'; import { CHANNEL_SET_USER_AGENT, EPG_ERROR, @@ -27,6 +28,10 @@ import { PLAYLIST_UPDATE_RESPONSE, } from './shared/ipc-commands'; import { Playlist, PlaylistUpdateState } from './shared/playlist.interface'; +import { + aggregateFavoriteChannels, + createFavoritesPlaylist, +} from './shared/playlist.utils'; import { ParsedPlaylist } from './src/typings.d'; const fs = require('fs'); @@ -97,12 +102,16 @@ export class Api { ipcMain.on(PLAYLIST_GET_ALL, (event) => this.sendAllPlaylists(event)); ipcMain.on(PLAYLIST_GET_BY_ID, (event, args) => { - db.findOne({ _id: args.id }).then((playlist) => { - this.setUserAgent(playlist.userAgent); - event.sender.send(PLAYLIST_PARSE_RESPONSE, { - payload: playlist, + if (args.id === GLOBAL_FAVORITES_PLAYLIST_ID) { + this.sendPlaylistWithGlobalFavorites(event); + } else { + db.findOne({ _id: args.id }).then((playlist) => { + this.setUserAgent(playlist?.userAgent); + event.sender.send(PLAYLIST_PARSE_RESPONSE, { + payload: playlist, + }); }); - }); + } }); ipcMain.on(PLAYLIST_REMOVE_BY_ID, (event, args) => { @@ -234,6 +243,22 @@ export class Api { this.refreshPlaylists(); } + /** + * Sends a message with playlist that contains favorite channels from all available playlists + * @param event ipc main event + */ + sendPlaylistWithGlobalFavorites(event: Electron.IpcMainEvent) { + db.find({ type: { $exists: false } }).then((playlists: Playlist[]) => { + const favoriteChannels = aggregateFavoriteChannels(playlists); + const favPlaylist = createFavoritesPlaylist(favoriteChannels); + + event.sender.send(PLAYLIST_PARSE_RESPONSE, { + type: PLAYLIST_PARSE_RESPONSE, + payload: favPlaylist, + }); + }); + } + /** * Set default listeners for custom-titlebar */ diff --git a/src/app/player/components/channel-list-container/channel-list-container.component.ts b/src/app/player/components/channel-list-container/channel-list-container.component.ts index 7dee5961e..8de54395a 100644 --- a/src/app/player/components/channel-list-container/channel-list-container.component.ts +++ b/src/app/player/components/channel-list-container/channel-list-container.component.ts @@ -8,7 +8,8 @@ import { import { MatSnackBar } from '@angular/material/snack-bar'; import * as _ from 'lodash'; import { Observable } from 'rxjs'; -import { Channel, ChannelQuery, ChannelStore } from '../../../state'; +import { Channel } from '../../../../../shared/channel.interface'; +import { ChannelQuery, ChannelStore } from '../../../state'; @Component({ selector: 'app-channel-list-container', diff --git a/src/app/player/components/epg-list/epg-list.component.spec.ts b/src/app/player/components/epg-list/epg-list.component.spec.ts index 1455791c6..a9c4d6446 100644 --- a/src/app/player/components/epg-list/epg-list.component.spec.ts +++ b/src/app/player/components/epg-list/epg-list.component.spec.ts @@ -1,19 +1,20 @@ -import { MockComponent, MockProvider, MockModule, MockPipe } from 'ng-mocks'; +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; /* eslint-disable @typescript-eslint/unbound-method */ import { MatDialog, MatDialogModule } from '@angular/material/dialog'; -import { TranslatePipe } from '@ngx-translate/core'; -import { MatTooltipModule } from '@angular/material/tooltip'; -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { EpgListComponent, EpgData } from './epg-list.component'; +import { MatIconModule } from '@angular/material/icon'; import { MatListModule } from '@angular/material/list'; -import { DataService } from '../../../services/data.service'; -import { ElectronServiceStub } from '../../../services/electron.service.stub'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { TranslatePipe } from '@ngx-translate/core'; import * as moment from 'moment'; +import { MockComponent, MockModule, MockPipe, MockProvider } from 'ng-mocks'; +import { Channel } from '../../../../../shared/channel.interface'; import { EPG_GET_PROGRAM_DONE } from '../../../../../shared/ipc-commands'; -import { Channel, ChannelStore } from '../../../state'; +import { DataService } from '../../../services/data.service'; +import { ElectronServiceStub } from '../../../services/electron.service.stub'; import { MomentDatePipe } from '../../../shared/pipes/moment-date.pipe'; -import { MatIconModule } from '@angular/material/icon'; +import { ChannelStore } from '../../../state'; import { EpgListItemComponent } from './epg-list-item/epg-list-item.component'; +import { EpgData, EpgListComponent } from './epg-list.component'; describe('EpgListComponent', () => { let component: EpgListComponent; diff --git a/src/app/player/components/html-video-player/html-video-player.component.ts b/src/app/player/components/html-video-player/html-video-player.component.ts index 48f6ee572..199ca965b 100644 --- a/src/app/player/components/html-video-player/html-video-player.component.ts +++ b/src/app/player/components/html-video-player/html-video-player.component.ts @@ -7,8 +7,8 @@ import { SimpleChanges, ViewChild, } from '@angular/core'; -import { Channel } from '../../../state'; import Hls from 'hls.js'; +import { Channel } from '../../../../../shared/channel.interface'; /** * This component contains the implementation of HTML5 based video player diff --git a/src/app/player/components/info-overlay/info-overlay.component.ts b/src/app/player/components/info-overlay/info-overlay.component.ts index 5cd9d4575..83803d640 100644 --- a/src/app/player/components/info-overlay/info-overlay.component.ts +++ b/src/app/player/components/info-overlay/info-overlay.component.ts @@ -1,7 +1,7 @@ -import { Channel } from './../../../state/channel.model'; import { Component, Input, OnChanges, SimpleChanges } from '@angular/core'; -import { EpgProgram } from '../../models/epg-program.model'; import * as moment from 'moment'; +import { Channel } from '../../../../../shared/channel.interface'; +import { EpgProgram } from '../../models/epg-program.model'; @Component({ selector: 'app-info-overlay', diff --git a/src/app/player/components/video-player/video-player.component.html b/src/app/player/components/video-player/video-player.component.html index 80c2c96c6..9fce54e64 100644 --- a/src/app/player/components/video-player/video-player.component.html +++ b/src/app/player/components/video-player/video-player.component.html @@ -25,6 +25,7 @@ menu