mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-11 19:46:16 -08:00
fix(settings): fix settings issues, fix ipc commands
Update channel.model to import Channel from the local interface file
instead of the package namespace. This fixes an incorrect module
resolution and keeps the codebase consistent with local typings.
Add a new SidebarView union type ('CHANNELS' | 'PLAYLISTS') to expose
possible sidebar view options for consumers of the shared interfaces.
This commit is contained in:
1 parent
2f930a6dfe
commit
51e04ab069
10 files changed
+112
-130
No files matched your search
@@ -120,15 +120,21 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||
.getValueFromLocalStorage(STORE_KEY.Settings)
|
||||
.subscribe((settings: Settings) => {
|
||||
if (settings && Object.keys(settings).length > 0) {
|
||||
this.dataService.sendIpcEvent(SETTINGS_UPDATE, settings);
|
||||
// Send settings to Electron main process
|
||||
if (window.electron) {
|
||||
window.electron.updateSettings(settings);
|
||||
}
|
||||
|
||||
this.translate.use(settings.language ?? this.DEFAULT_LANG);
|
||||
/* if (
|
||||
|
||||
// Fetch EPG if URLs are configured
|
||||
if (
|
||||
window.electron &&
|
||||
settings.epgUrl?.length > 0 &&
|
||||
settings.epgUrl?.some((u) => u !== '') &&
|
||||
isTauri()
|
||||
settings.epgUrl?.some((u) => u !== '')
|
||||
) {
|
||||
this.epgService.fetchEpg(settings.epgUrl);
|
||||
} */
|
||||
}
|
||||
|
||||
if (settings.theme) {
|
||||
this.settingsService.changeTheme(settings.theme);
|
||||
|
||||
@@ -35,7 +35,6 @@ import {
|
||||
import { Observable, combineLatestWith, filter, map, switchMap } from 'rxjs';
|
||||
import { DataService, PlaylistsService } from 'services';
|
||||
import {
|
||||
CHANNEL_SET_USER_AGENT,
|
||||
COMPONENT_OVERLAY_REF,
|
||||
Channel,
|
||||
ERROR,
|
||||
@@ -44,14 +43,12 @@ import {
|
||||
Playlist,
|
||||
STORE_KEY,
|
||||
Settings,
|
||||
SidebarView,
|
||||
VideoPlayer,
|
||||
} from 'shared-interfaces';
|
||||
import { SettingsStore } from '../../services/settings-store.service';
|
||||
import { SettingsComponent } from '../../settings/settings.component';
|
||||
|
||||
/** Possible sidebar view options */
|
||||
export type SidebarView = 'CHANNELS' | 'PLAYLISTS';
|
||||
|
||||
@Component({
|
||||
imports: [
|
||||
AsyncPipe,
|
||||
@@ -175,15 +172,13 @@ export class VideoPlayerComponent implements OnInit {
|
||||
);
|
||||
return this.playlistsService.getPlaylist(params['id']).pipe(
|
||||
map((playlist) => {
|
||||
this.dataService.sendIpcEvent(
|
||||
CHANNEL_SET_USER_AGENT,
|
||||
playlist.userAgent
|
||||
? {
|
||||
referer: 'localhost',
|
||||
userAgent: playlist.userAgent,
|
||||
}
|
||||
: {}
|
||||
);
|
||||
// Set user agent if specified on playlist level
|
||||
if (playlist.userAgent) {
|
||||
window.electron?.setUserAgent(
|
||||
playlist.userAgent,
|
||||
'localhost'
|
||||
);
|
||||
}
|
||||
|
||||
this.store.dispatch(
|
||||
PlaylistActions.setChannels({
|
||||
|
||||
@@ -5,7 +5,6 @@ import { DataService } from 'services';
|
||||
import {
|
||||
AUTO_UPDATE_PLAYLISTS,
|
||||
AUTO_UPDATE_PLAYLISTS_RESPONSE,
|
||||
EPG_GET_PROGRAM_DONE,
|
||||
ERROR,
|
||||
Playlist,
|
||||
PLAYLIST_PARSE_BY_URL,
|
||||
@@ -92,11 +91,6 @@ export class ElectronService extends DataService {
|
||||
console.error('VLC launch error:', error);
|
||||
throw error;
|
||||
}
|
||||
} else if (type === 'EPG_FETCH_DONE') {
|
||||
window.postMessage({
|
||||
type: EPG_GET_PROGRAM_DONE,
|
||||
payload,
|
||||
});
|
||||
} else if (type === AUTO_UPDATE_PLAYLISTS) {
|
||||
const data = payload as Playlist[];
|
||||
const playlists = await window.electron.autoUpdatePlaylists(data);
|
||||
|
||||
@@ -36,14 +36,19 @@ export const SettingsStore = signalStore(
|
||||
withState<Settings>(DEFAULT_SETTINGS),
|
||||
withMethods((store, storage = inject(StorageMap)) => ({
|
||||
async loadSettings() {
|
||||
const stored = await firstValueFrom(
|
||||
storage.get(STORE_KEY.Settings)
|
||||
);
|
||||
if (stored) {
|
||||
patchState(store, {
|
||||
...DEFAULT_SETTINGS,
|
||||
...(stored as Settings),
|
||||
});
|
||||
try {
|
||||
const stored = await firstValueFrom(
|
||||
storage.get(STORE_KEY.Settings)
|
||||
);
|
||||
if (stored) {
|
||||
patchState(store, {
|
||||
...DEFAULT_SETTINGS,
|
||||
...(stored as Settings),
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to load settings:', error);
|
||||
// Keep default settings if loading fails
|
||||
}
|
||||
},
|
||||
|
||||
@@ -51,9 +56,14 @@ export const SettingsStore = signalStore(
|
||||
patchState(store, settings);
|
||||
// Save the complete settings object, not just the partial update
|
||||
const completeSettings = this.getSettings();
|
||||
await firstValueFrom(
|
||||
storage.set(STORE_KEY.Settings, completeSettings)
|
||||
);
|
||||
try {
|
||||
await firstValueFrom(
|
||||
storage.set(STORE_KEY.Settings, completeSettings)
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Failed to save settings:', error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
|
||||
getSettings() {
|
||||
|
||||
@@ -41,8 +41,6 @@ import { DataService, EpgService, PlaylistsService } from 'services';
|
||||
import {
|
||||
Language,
|
||||
Playlist,
|
||||
SET_MPV_PLAYER_PATH,
|
||||
SET_VLC_PLAYER_PATH,
|
||||
StreamFormat,
|
||||
Theme,
|
||||
VideoPlayer,
|
||||
@@ -165,7 +163,9 @@ export class SettingsComponent implements OnInit {
|
||||
* Reads the config object from the browsers
|
||||
* storage (indexed db)
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
async ngOnInit(): Promise<void> {
|
||||
// Wait for settings to load before setting the form
|
||||
await this.settingsStore.loadSettings();
|
||||
this.setSettings();
|
||||
this.checkAppVersion();
|
||||
}
|
||||
@@ -252,21 +252,18 @@ export class SettingsComponent implements OnInit {
|
||||
onSubmit(): void {
|
||||
this.settingsStore.updateSettings(this.settingsForm.value).then(() => {
|
||||
this.applyChangedSettings();
|
||||
/* this.dataService.sendIpcEvent(
|
||||
SETTINGS_UPDATE,
|
||||
this.settingsForm.value
|
||||
); */
|
||||
window.electron?.updateSettings(this.settingsForm.value);
|
||||
|
||||
this.dataService.sendIpcEvent(
|
||||
SET_MPV_PLAYER_PATH,
|
||||
this.settingsForm.value.mpvPlayerPath
|
||||
);
|
||||
|
||||
this.dataService.sendIpcEvent(
|
||||
SET_VLC_PLAYER_PATH,
|
||||
this.settingsForm.value.mpvPlayerPath
|
||||
);
|
||||
|
||||
if (window.electron) {
|
||||
window.electron.updateSettings(this.settingsForm.value);
|
||||
|
||||
// Set player paths if using external players
|
||||
if (this.settingsForm.value.mpvPlayerPath) {
|
||||
window.electron.setMpvPlayerPath(this.settingsForm.value.mpvPlayerPath);
|
||||
}
|
||||
if (this.settingsForm.value.vlcPlayerPath) {
|
||||
window.electron.setVlcPlayerPath(this.settingsForm.value.vlcPlayerPath);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (this.isDialog) {
|
||||
this.matDialog.closeAll();
|
||||
|
||||
@@ -13,10 +13,8 @@ import {
|
||||
tap,
|
||||
withLatestFrom,
|
||||
} from 'rxjs';
|
||||
import { DataService, PlaylistsService } from 'services';
|
||||
import { DataService, EpgService, PlaylistsService } from 'services';
|
||||
import {
|
||||
CHANNEL_SET_USER_AGENT,
|
||||
EPG_GET_PROGRAM,
|
||||
OPEN_MPV_PLAYER,
|
||||
OPEN_VLC_PLAYER,
|
||||
Playlist,
|
||||
@@ -36,6 +34,7 @@ export class PlaylistEffects {
|
||||
private actions$ = inject(Actions);
|
||||
private playlistsService = inject(PlaylistsService);
|
||||
private dataService = inject(DataService);
|
||||
private epgService = inject(EpgService);
|
||||
private router = inject(Router);
|
||||
private snackBar = inject(MatSnackBar);
|
||||
private storage = inject(StorageMap);
|
||||
@@ -126,15 +125,19 @@ export class PlaylistEffects {
|
||||
ofType(PlaylistActions.setActiveChannel),
|
||||
map((action) => {
|
||||
const { channel } = action;
|
||||
this.dataService.sendIpcEvent(EPG_GET_PROGRAM, {
|
||||
channel,
|
||||
});
|
||||
|
||||
// Use modern EPG service to get channel programs
|
||||
const channelId = channel.tvg?.id || channel.name;
|
||||
if (channelId) {
|
||||
this.epgService.getChannelPrograms(channelId);
|
||||
}
|
||||
|
||||
// Set user agent if specified on channel
|
||||
if (channel.http['user-agent']) {
|
||||
this.dataService.sendIpcEvent(CHANNEL_SET_USER_AGENT, {
|
||||
referer: channel.http.referrer,
|
||||
userAgent: channel.http['user-agent'],
|
||||
origin: channel.http.origin,
|
||||
});
|
||||
window.electron?.setUserAgent(
|
||||
channel.http['user-agent'],
|
||||
channel.http.referrer
|
||||
);
|
||||
}
|
||||
|
||||
firstValueFrom(this.storage.get(STORE_KEY.Settings)).then(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Channel } from 'shared-interfaces';
|
||||
import { Channel } from './channel.interface';
|
||||
|
||||
/**
|
||||
* Creates new channel object based on the given fields
|
||||
@@ -15,3 +15,6 @@ export function createChannel(params: Partial<Channel>): Channel {
|
||||
http: params.http,
|
||||
} as Channel;
|
||||
}
|
||||
|
||||
/** Possible sidebar view options */
|
||||
export type SidebarView = 'CHANNELS' | 'PLAYLISTS';
|
||||
@@ -2,8 +2,6 @@
|
||||
export const EPG_FETCH = 'EPG:FETCH';
|
||||
export const EPG_FETCH_DONE = 'EPG:FETCH_DONE';
|
||||
export const EPG_ERROR = 'EPG:ERROR';
|
||||
export const EPG_GET_PROGRAM = 'EPG:GET_PROGRAM';
|
||||
export const EPG_GET_PROGRAM_DONE = 'EPG:GET_PROGRAM_DONE';
|
||||
export const EPG_GET_CHANNELS = 'EPG:GET_CHANNELS';
|
||||
export const EPG_GET_CHANNELS_DONE = 'EPG:GET_CHANNELS_DONE';
|
||||
export const EPG_GET_CHANNELS_BY_RANGE = 'EPG:EPG_GET_CHANNELS_BY_RANGE';
|
||||
@@ -21,9 +19,6 @@ export const PLAYLIST_UPDATE_RESPONSE = 'PLAYLIST:UPDATE_RESPONSE';
|
||||
export const ERROR = 'ERROR';
|
||||
export const OPEN_FILE = 'OPEN_FILE';
|
||||
|
||||
// Channels
|
||||
export const CHANNEL_SET_USER_AGENT = 'CHANNEL:SET_USER_AGENT';
|
||||
|
||||
// Views
|
||||
export const VIEW_SETTINGS = 'VIEW:SETTINGS';
|
||||
export const VIEW_ADD_PLAYLIST = 'VIEW:PLAYLISTS';
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
import Hls from 'hls.js';
|
||||
import { getExtensionFromUrl } from 'm3u-utils';
|
||||
import { DataService } from 'services';
|
||||
import { Channel, CHANNEL_SET_USER_AGENT } from 'shared-interfaces';
|
||||
import { Channel } from 'shared-interfaces';
|
||||
|
||||
/**
|
||||
* This component contains the implementation of HTML5 based video player
|
||||
@@ -74,61 +74,38 @@ export class HtmlVideoPlayerComponent implements OnInit, OnChanges, OnDestroy {
|
||||
const url = channel.url + (channel.epgParams ?? '');
|
||||
const extension = getExtensionFromUrl(channel.url);
|
||||
|
||||
// Send IPC event and handle the response
|
||||
this.dataService
|
||||
.sendIpcEvent(CHANNEL_SET_USER_AGENT, {
|
||||
userAgent: channel.http?.['user-agent'] ?? '',
|
||||
referer: channel.http?.referrer ?? '',
|
||||
origin: channel.http?.origin ?? '',
|
||||
})
|
||||
.then(() => {
|
||||
if (
|
||||
extension !== 'mp4' &&
|
||||
extension !== 'mpv' &&
|
||||
Hls &&
|
||||
Hls.isSupported()
|
||||
) {
|
||||
console.log(
|
||||
'... switching channel to ',
|
||||
channel.name,
|
||||
url
|
||||
);
|
||||
this.hls = new Hls();
|
||||
this.hls.attachMedia(this.videoPlayer.nativeElement);
|
||||
this.hls.loadSource(url);
|
||||
this.handlePlayOperation();
|
||||
} else {
|
||||
console.log('Using native video player...');
|
||||
this.addSourceToVideo(
|
||||
this.videoPlayer.nativeElement,
|
||||
url,
|
||||
'video/mp4'
|
||||
);
|
||||
this.videoPlayer.nativeElement.play();
|
||||
}
|
||||
})
|
||||
.catch((error: any) => {
|
||||
console.error('Error setting user agent:', error);
|
||||
// Continue playback even if setting user agent fails
|
||||
if (
|
||||
extension !== 'mp4' &&
|
||||
extension !== 'mpv' &&
|
||||
Hls &&
|
||||
Hls.isSupported()
|
||||
) {
|
||||
this.hls = new Hls();
|
||||
this.hls.attachMedia(this.videoPlayer.nativeElement);
|
||||
this.hls.loadSource(url);
|
||||
this.handlePlayOperation();
|
||||
} else {
|
||||
this.addSourceToVideo(
|
||||
this.videoPlayer.nativeElement,
|
||||
url,
|
||||
'video/mp4'
|
||||
);
|
||||
this.videoPlayer.nativeElement.play();
|
||||
}
|
||||
});
|
||||
// Set user agent if specified on channel
|
||||
if (channel.http?.['user-agent']) {
|
||||
window.electron?.setUserAgent(
|
||||
channel.http['user-agent'],
|
||||
channel.http.referrer
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
extension !== 'mp4' &&
|
||||
extension !== 'mpv' &&
|
||||
Hls &&
|
||||
Hls.isSupported()
|
||||
) {
|
||||
console.log(
|
||||
'... switching channel to ',
|
||||
channel.name,
|
||||
url
|
||||
);
|
||||
this.hls = new Hls();
|
||||
this.hls.attachMedia(this.videoPlayer.nativeElement);
|
||||
this.hls.loadSource(url);
|
||||
this.handlePlayOperation();
|
||||
} else {
|
||||
console.log('Using native video player...');
|
||||
this.addSourceToVideo(
|
||||
this.videoPlayer.nativeElement,
|
||||
url,
|
||||
'video/mp4'
|
||||
);
|
||||
this.videoPlayer.nativeElement.play();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
import '@yangkghjh/videojs-aspect-ratio-panel';
|
||||
import videoJs from 'video.js';
|
||||
import 'videojs-contrib-quality-levels';
|
||||
import 'videojs-hls-quality-selector';
|
||||
//import 'videojs-hls-quality-selector';
|
||||
|
||||
/**
|
||||
* This component contains the implementation of video player that is based on video.js library
|
||||
@@ -28,9 +28,9 @@ export class VjsPlayerComponent implements OnInit, OnChanges, OnDestroy {
|
||||
/** DOM-element reference */
|
||||
@ViewChild('target', { static: true }) target!: ElementRef<Element>;
|
||||
/** Options of VideoJs player */
|
||||
@Input() options!: videoJs.PlayerOptions;
|
||||
@Input() options!: any;
|
||||
/** VideoJs object */
|
||||
player!: videoJs.Player;
|
||||
player!: any;
|
||||
@Input() volume = 1;
|
||||
|
||||
/**
|
||||
@@ -56,9 +56,11 @@ export class VjsPlayerComponent implements OnInit, OnChanges, OnDestroy {
|
||||
});
|
||||
}
|
||||
);
|
||||
this.player.hlsQualitySelector({
|
||||
/* this.player.hlsQualitySelector({
|
||||
displayCurrentQuality: true,
|
||||
});
|
||||
// this one produces warning in console
|
||||
*/
|
||||
this.player['aspectRatioPanel']();
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user