fix: refresh local playlist functionallity

This commit is contained in:
4gray committed 2025-03-09 19:38:43 +01:00
1 parent b07bda2663
commit a3a8f96eaa
6 files changed
+90 -84

No files matched your search

+10 -11
View File
@@ -42,7 +42,6 @@ export class HomeComponent {
{
id: ERROR,
execute: (error: { message: string; status: string }) => {
//this.isLoading = false;
this.showNotification('Error: ' + error.message);
},
},
@@ -64,19 +63,19 @@ export class HomeComponent {
*/
setRendererListeners(): void {
this.commandsList.forEach((command) => {
if (this.dataService.isElectron) {
/* if (this.dataService.isElectron) {
this.dataService.listenOn(command.id, (event, response) =>
this.ngZone.run(() => command.execute(response))
);
} else {
const cb = (response) => {
if (response.data.type === command.id) {
command.execute(response.data);
}
};
this.dataService.listenOn(command.id, cb);
this.listeners.push(cb);
}
} else { */
const cb = (response) => {
if (response.data.type === command.id) {
command.execute(response.data);
}
};
this.dataService.listenOn(command.id, cb);
this.listeners.push(cb);
/* } */
});
}
@@ -6,7 +6,6 @@ import {
EventEmitter,
HostListener,
Input,
NgZone,
OnDestroy,
Output,
ViewChild,
@@ -24,7 +23,6 @@ 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 { IpcCommand } from '../../../../shared/ipc-command.class';
import { Playlist } from '../../../../shared/playlist.interface';
import { DataService } from '../../services/data.service';
import { DatabaseService } from '../../services/database.service';
@@ -118,36 +116,41 @@ export class RecentPlaylistsComponent implements OnDestroy {
/** IPC Renderer commands list with callbacks */
commandsList = [
new IpcCommand(
PLAYLIST_UPDATE_RESPONSE,
(response: { message: string; playlist: Playlist }) => {
this.snackBar.open(response.message, null, { duration: 2000 });
{
id: PLAYLIST_UPDATE_RESPONSE,
execute: (response: {
payload: { message: string; playlist: Playlist };
}) => {
this.snackBar.open(response.payload.message, null, {
duration: 2000,
});
this.store.dispatch(
PlaylistActions.updatePlaylist({
playlistId: response.playlist._id,
playlist: response.playlist,
playlistId: response.payload.playlist._id,
playlist: response.payload.playlist,
})
);
}
),
new IpcCommand(
AUTO_UPDATE_PLAYLISTS_RESPONSE,
(playlists: Playlist[]) => {
},
},
{
id: AUTO_UPDATE_PLAYLISTS_RESPONSE,
execute: (playlists: Playlist[]) => {
this.store.dispatch(
PlaylistActions.updateManyPlaylists({
playlists,
})
);
}
),
},
},
];
listeners = [];
constructor(
private readonly databaseService: DatabaseService,
private readonly dialog: MatDialog,
private readonly dialogService: DialogService,
private readonly electronService: DataService,
private readonly ngZone: NgZone,
private readonly dataService: DataService,
private readonly router: Router,
private readonly snackBar: MatSnackBar,
private readonly sortService: SortService,
@@ -159,16 +162,15 @@ export class RecentPlaylistsComponent implements OnDestroy {
this.setRendererListeners();
}
/**
* Set electrons main process listeners
*/
setRendererListeners(): void {
this.commandsList.forEach((command) => {
if (this.electronService.isElectron) {
this.electronService.listenOn(command.id, (event, response) =>
this.ngZone.run(() => command.callback(response))
);
}
const cb = (response) => {
if (response.data.type === command.id) {
command.execute(response.data);
}
};
this.dataService.listenOn(command.id, cb);
this.listeners.push(cb);
});
}
@@ -241,8 +243,8 @@ export class RecentPlaylistsComponent implements OnDestroy {
* Sends an IPC event with the playlist details to the main process to trigger the refresh operation
* @param item playlist to update
*/
refreshPlaylist(item: PlaylistMeta): void {
this.electronService.sendIpcEvent(PLAYLIST_UPDATE, {
refreshPlaylist(item: PlaylistMeta) {
this.dataService.sendIpcEvent(PLAYLIST_UPDATE, {
id: item._id,
title: item.title,
...(item.url ? { url: item.url } : { filePath: item.filePath }),
@@ -250,22 +252,20 @@ export class RecentPlaylistsComponent implements OnDestroy {
}
migratePlaylists() {
this.electronService.sendIpcEvent(MIGRATE_PLAYLISTS);
this.dataService.sendIpcEvent(MIGRATE_PLAYLISTS);
}
deleteMigratedPlaylists() {
this.electronService.sendIpcEvent(DELETE_ALL_PLAYLISTS);
this.dataService.sendIpcEvent(DELETE_ALL_PLAYLISTS);
}
/**
* Removes command listeners on component destroy
*/
ngOnDestroy(): void {
if (this.electronService.isElectron) {
this.commandsList.forEach((command) =>
this.electronService.removeAllListeners(command.id)
);
}
this.listeners.forEach((listener) => {
window.removeEventListener('message', listener);
});
}
trackByFn(_index: number, item: PlaylistMeta) {
@@ -7,9 +7,11 @@
formControlName="playlistUrl"
/>
</mat-form-field>
<p *ngIf="!isElectron">
{{ 'HOME.URL_UPLOAD.CORS_NOTE' | translate }}
</p>
@if (!isTauri) {
<p>
{{ 'HOME.URL_UPLOAD.CORS_NOTE' | translate }}
</p>
}
<button
class="add-button"
mat-flat-button
@@ -1,43 +1,30 @@
import { NgIf } from '@angular/common';
import { Component, EventEmitter, OnInit, Output } from '@angular/core';
import { Component, EventEmitter, inject, OnInit, Output } from '@angular/core';
import {
FormBuilder,
FormGroup,
ReactiveFormsModule,
Validators,
} from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import { MatButton } from '@angular/material/button';
import { MatInputModule } from '@angular/material/input';
import { TranslatePipe } from '@ngx-translate/core';
import { DataService } from '../../services/data.service';
import { isTauri } from '@tauri-apps/api/core';
@Component({
selector: 'app-url-upload',
templateUrl: './url-upload.component.html',
imports: [
MatButtonModule,
MatCardModule,
MatInputModule,
NgIf,
ReactiveFormsModule,
TranslatePipe,
],
imports: [MatButton, MatInputModule, ReactiveFormsModule, TranslatePipe],
})
export class UrlUploadComponent implements OnInit {
private readonly fb = inject(FormBuilder);
/** Emits url string to the parent component on form submit */
@Output() urlAdded: EventEmitter<string> = new EventEmitter();
form: FormGroup;
isTauri = isTauri();
isElectron = this.dataService.isElectron;
constructor(
private fb: FormBuilder,
private dataService: DataService
) {}
ngOnInit(): void {
ngOnInit() {
const urlRegex = '(https?://.*?)';
this.form = this.fb.group({
playlistUrl: [
@@ -71,7 +71,7 @@ export const COMPONENT_OVERLAY_REF = new InjectionToken(
ArtPlayerComponent,
],
templateUrl: './video-player.component.html',
styleUrls: ['./video-player.component.scss']
styleUrl: './video-player.component.scss',
})
export class VideoPlayerComponent implements OnInit, OnDestroy {
/** Active selected channel */
@@ -208,6 +208,7 @@ export class VideoPlayerComponent implements OnInit, OnDestroy {
/**
* Opens a playlist provided as a url param
* e.g. iptvnat.or?url=http://...
* @pwaOnly
*/
getPlaylistUrlAsParam() {
const URL_REGEX = /^(http|https|file):\/\/[^ "]+$/;
@@ -221,9 +222,6 @@ export class VideoPlayerComponent implements OnInit, OnDestroy {
}
}
/**
* Set electrons main process listeners
*/
setRendererListeners(): void {
this.commandsList.forEach((command) => {
if (this.isTauri) {
@@ -252,20 +250,14 @@ export class VideoPlayerComponent implements OnInit, OnDestroy {
player: settings.player || VideoPlayer.VideoJs,
showCaptions: settings.showCaptions || false,
};
// Don't override volume from settings storage anymore
// as we're using localStorage for volume persistence
}
});
}
ngOnDestroy() {
if (this.isTauri) {
this.dataService.removeAllListeners(PLAYLIST_PARSE_RESPONSE);
} else {
this.listeners.forEach((listener) =>
window.removeEventListener('message', listener)
);
}
this.listeners.forEach((listener) =>
window.removeEventListener('message', listener)
);
}
/**
+28 -2
View File
@@ -1,6 +1,7 @@
import { Injectable } from '@angular/core';
import { Params } from '@angular/router';
import { invoke } from '@tauri-apps/api/core';
import { readTextFile } from '@tauri-apps/plugin-fs';
import { fetch } from '@tauri-apps/plugin-http';
import { parse } from 'iptv-playlist-parser';
import {
@@ -8,6 +9,8 @@ import {
ERROR,
PLAYLIST_PARSE_BY_URL,
PLAYLIST_PARSE_RESPONSE,
PLAYLIST_UPDATE,
PLAYLIST_UPDATE_RESPONSE,
XTREAM_RESPONSE,
} from '../../../shared/ipc-commands';
import { Playlist } from '../../../shared/playlist.interface';
@@ -31,8 +34,31 @@ export class TauriService extends DataService {
async sendIpcEvent(type: string, payload?: unknown) {
if (type === PLAYLIST_PARSE_BY_URL) {
this.fetchFromUrl(payload);
} else if (type === 'PLAYLIST_UPDATE') {
console.log('PLAYLIST_UPDATE');
} else if (type === PLAYLIST_UPDATE) {
const data = payload as {
id: string;
filePath: string;
title: string;
};
const playlist = await readTextFile(data.filePath);
const parsedPlaylist = parse(playlist);
const playlistObject = createPlaylistObject(
data.title,
parsedPlaylist,
data.filePath,
'FILE'
);
window.postMessage({
type: PLAYLIST_UPDATE_RESPONSE,
payload: {
message: 'Success! The playlist was successfully updated',
playlist: {
...playlistObject,
_id: data.id,
},
},
});
} else if (type === 'XTREAM_REQUEST') {
return await this.forwardXtreamRequest(
payload as { url: string; params: Record<string, string> }