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