Merge pull request #457 from KiPSOFT/xtream-favorites

feat: added favorites for xtream live streams.
This commit is contained in:
4gray authored and GitHub committed 2024-10-22 10:01:56 +02:00
commit e589e7bfd7
6 files changed
+99 -10

No files matched your search

+1 -1
View File
@@ -53,7 +53,7 @@ function createWindow(): BrowserWindow {
require('@electron/remote/main').enable(win.webContents);
if (serve) {
win.webContents.openDevTools();
win.on('ready-to-show', () => win?.webContents.openDevTools());
win.loadURL('http://localhost:4200');
} else {
win.loadURL(
+10 -1
View File
@@ -147,7 +147,16 @@ export class PlaylistsService {
DbStores.Playlists,
portalId
)
.pipe(map((item) => item.favorites ?? []));
.pipe(map((item) => item.favorites.filter(itm => itm && itm.stream_type && itm.stream_type !== 'live') ?? []));
}
getPortalLiveStreamFavorites(portalId: string) {
return this.dbService
.getByID<{ favorites: Partial<XtreamItem>[] }>(
DbStores.Playlists,
portalId
)
.pipe(map((item) => item.favorites.filter(itm => itm && itm.stream_type && itm.stream_type === 'live') ?? []));
}
addPortalFavorite(portalId: string, item: any) {
@@ -51,6 +51,22 @@
</div>
</div>
<div class="search-container">
<div class="favorite">
<button
*ngIf="favoriteVisible && activeLiveStream"
mat-icon-button
(click)="clickFavorites()"
[matTooltip]="'TOP_MENU.TOGGLE_FAVORITE_FLAG' | translate"
>
<mat-icon>
{{
isFavoriteStream
? 'star'
: 'star_outline'
}}
</mat-icon>
</button>
</div>
<div class="sort" *ngIf="sortVisible">
<button
mat-icon-button
@@ -1,5 +1,5 @@
import { NgFor, NgIf } from '@angular/common';
import { Component, EventEmitter, Input, Output, inject } from '@angular/core';
import { NgFor, NgIf, AsyncPipe } from '@angular/common';
import { Component, EventEmitter, Input, Output, inject, OnChanges, SimpleChanges } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
import { MatButtonToggleModule } from '@angular/material/button-toggle';
@@ -10,7 +10,7 @@ import { MatInputModule } from '@angular/material/input';
import { RouterLink } from '@angular/router';
import { Store } from '@ngrx/store';
import { TranslateModule } from '@ngx-translate/core';
import { Subject, debounceTime, distinctUntilChanged } from 'rxjs';
import { Observable, Subject, debounceTime, distinctUntilChanged, map } from 'rxjs';
import { PlaylistInfoComponent } from '../../home/recent-playlists/playlist-info/playlist-info.component';
import { selectCurrentPlaylist } from '../../state/selectors';
import { Breadcrumb } from '../breadcrumb.interface';
@@ -20,6 +20,7 @@ import { PortalStore } from '../portal.store';
import { MatMenuModule } from '@angular/material/menu';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatTooltipModule } from '@angular/material/tooltip';
import { XtreamLiveStream } from '../../../../shared/xtream-live-stream.interface';
@Component({
selector: 'app-navigation-bar',
@@ -39,10 +40,11 @@ import { MatTooltipModule } from '@angular/material/tooltip';
TranslateModule,
MatMenuModule,
MatCheckboxModule,
MatTooltipModule
MatTooltipModule,
AsyncPipe
],
})
export class NavigationBarComponent {
export class NavigationBarComponent implements OnChanges {
@Input({ required: true }) breadcrumbs: Breadcrumb[];
@Input({ required: true }) contentType: ContentType;
@Input() searchVisible = true;
@@ -50,12 +52,17 @@ export class NavigationBarComponent {
@Input() contentTypeNavigationItems: ContentTypeNavigationItem[];
@Input() clientSideSearch = true;
@Input() showCategories = false;
@Input() activeLiveStream!: XtreamLiveStream;
@Input() favoritesLiveStream$: Observable<any>;
@Input() favoriteVisible = false;
@Output() contentTypeChanged = new EventEmitter<ContentType>();
@Output() breadcrumbClicked = new EventEmitter<Breadcrumb>();
@Output() favoritesClicked = new EventEmitter<void>();
@Output() searchTextChanged = new EventEmitter<string>();
@Output() addToFavoritesClicked = new EventEmitter<any>();
@Output() removeFromFavoritesClicked = new EventEmitter<number>();
ContentTypeEnum = ContentType;
dialog = inject(MatDialog);
portalStore = inject(PortalStore);
@@ -64,6 +71,7 @@ export class NavigationBarComponent {
searchPhraseUpdate = new Subject<string>();
currentPlaylist = this.store.selectSignal(selectCurrentPlaylist);
sortType = this.portalStore.sortType;
isFavoriteStream = false;
constructor() {
this.searchPhraseUpdate
@@ -101,4 +109,36 @@ export class NavigationBarComponent {
trackByValue(_i: number, value: ContentTypeNavigationItem) {
return value.contentType;
}
clickFavorites(): void {
const item = this.activeLiveStream;
if (!this.isFavoriteStream) {
this.addToFavoritesClicked.emit({
name: item.name,
stream_id: item.stream_id,
cover: item.stream_icon,
stream_type: 'live'
});
this.isFavoriteStream = true;
} else {
this.removeFromFavoritesClicked.emit(item.stream_id);
this.isFavoriteStream = false;
}
}
ngOnChanges(changes: SimpleChanges) {
if (changes.activeLiveStream && this.activeLiveStream) {
this.checkFavorite();
}
}
checkFavorite() {
// if activeLiveStream.stream_id include in favorites return the true
const activeLiveStream = this.activeLiveStream;
this.favoritesLiveStream$.pipe(
map(favorites => favorites.some(fav => fav.stream_id === activeLiveStream.stream_id))
).subscribe(isFavorite => {
this.isFavoriteStream = isFavorite;
});
}
}
@@ -10,7 +10,12 @@
currentLayout === 'category' || currentLayout === 'category_content'
"
[sortVisible]="currentLayout === 'category_content'"
[favoriteVisible]="currentLayout === 'category_content' || currentLayout === 'live-stream-favorites'"
[contentTypeNavigationItems]="navigationContentTypes"
[activeLiveStream]="activeLiveStream"
[favoritesLiveStream$]="favoritesLiveStream$"
(addToFavoritesClicked)="addToFavorites($event)"
(removeFromFavoritesClicked)="removeFromFavorites($event)"
/>
@if (isLoading) {
@@ -69,5 +74,14 @@
(itemClicked)="itemClicked($event)"
/>
}
@case ('live-stream-favorites') {
<app-live-stream-layout
[channels]="favoritesLiveStream$"
[player]="player"
[streamUrl]="streamUrl"
[epgItems]="epgItems"
(itemClicked)="itemClicked($event)"
/>
}
}
}
@@ -103,7 +103,8 @@ type LayoutView =
| 'player'
| 'serie-details'
| 'favorites'
| 'error-view';
| 'error-view'
| 'live-stream-favorites';
@Component({
selector: 'app-xtream-main-container',
@@ -168,6 +169,7 @@ export class XtreamMainContainerComponent implements OnInit {
player: VideoPlayer;
favorites$: Observable<any>;
favoritesLiveStream$: Observable<any>;
breadcrumbs: Breadcrumb[] = [];
items = [];
listeners = [];
@@ -205,6 +207,9 @@ export class XtreamMainContainerComponent implements OnInit {
this.favorites$ = this.playlistService.getPortalFavorites(
this.currentPlaylist()._id
);
this.favoritesLiveStream$ = this.playlistService.getPortalLiveStreamFavorites(
this.currentPlaylist()._id
);
}
});
}
@@ -337,6 +342,7 @@ export class XtreamMainContainerComponent implements OnInit {
stream_id: item.stream_id,
limit: 10,
});
this.activeLiveStream = item;
this.playLiveStream(item);
} else if (item.series_id) {
this.items = [];
@@ -533,7 +539,11 @@ export class XtreamMainContainerComponent implements OnInit {
}
favoritesClicked() {
this.currentLayout = 'favorites';
if (this.selectedContentType === ContentType.ITV) {
this.currentLayout = 'live-stream-favorites';
} else {
this.currentLayout = 'favorites';
}
this.setInitialBreadcrumb();
}