feat(player): add embedded-mpv player for macOS as experimental feature

- Introduced tooling for building and staging the macOS `libmpv` runtime for IPTVnator's embedded MPV player.
- Added `build-macos-runtime.mjs` for building an LGPL-compatible runtime from source.
- Created `stage-macos-runtime.mjs` for staging the built runtime artifacts.
- Implemented validation for the packaged embedded MPV runtime in `electron-after-pack.cjs` and `embedded-mpv-macos.cjs`.
- Updated packaging scripts to ensure the embedded MPV runtime is correctly integrated and validated during the build process.
- Added README files to document the expected layout and usage for the embedded MPV runtime artifacts.

Entire-Checkpoint: c6e522b4276c
This commit is contained in:
4gray committed 2026-04-27 00:32:14 +02:00
1 parent 10139955e7
commit 9f873e6bed
53 files changed
+6099 -49

No files matched your search

@@ -56,7 +56,7 @@ import {
PlaylistsService,
} from 'services';
import {
/* EmbeddedMpvSupport, */
EmbeddedMpvSupport,
Language,
StartupBehavior,
StreamFormat,
@@ -151,10 +151,10 @@ export class SettingsComponent implements OnInit, OnDestroy {
/** Flag that indicates whether the app runs in electron environment */
readonly isDesktop = !!window.electron;
/* readonly embeddedMpvSupport = signal<EmbeddedMpvSupport | null>(null);
readonly embeddedMpvSupport = signal<EmbeddedMpvSupport | null>(null);
readonly supportsEmbeddedMpv = computed(
() => this.isDesktop && !!this.embeddedMpvSupport()?.supported
); */
);
isPwa = this.dataService.getAppEnvironment() === 'pwa';
@@ -162,14 +162,14 @@ export class SettingsComponent implements OnInit, OnDestroy {
readonly activeSection = this.settingsCtx.activeSection;
readonly osPlayers = computed(() => [
/* ...(this.supportsEmbeddedMpv()
...(this.supportsEmbeddedMpv()
? [
{
id: VideoPlayer.EmbeddedMpv,
labelKey: 'SETTINGS.PLAYER_EMBEDDED_MPV',
},
]
: []), */
: []),
{
id: VideoPlayer.MPV,
labelKey: 'SETTINGS.PLAYER_MPV',
@@ -437,7 +437,7 @@ export class SettingsComponent implements OnInit, OnDestroy {
// Wait for settings to load before setting the form
await this.settingsStore.loadSettings();
this.setSettings();
/* void this.loadEmbeddedMpvSupport(); */
void this.loadEmbeddedMpvSupport();
this.checkAppVersion();
void this.fetchLocalIpAddresses();
@@ -448,7 +448,7 @@ export class SettingsComponent implements OnInit, OnDestroy {
requestAnimationFrame(() => this.setupSectionObserver());
}
/* private async loadEmbeddedMpvSupport(): Promise<void> {
private async loadEmbeddedMpvSupport(): Promise<void> {
if (!this.isDesktop) {
this.embeddedMpvSupport.set({
supported: false,
@@ -475,13 +475,10 @@ export class SettingsComponent implements OnInit, OnDestroy {
this.embeddedMpvSupport.set({
supported: false,
platform: window.electron.platform,
reason:
error instanceof Error
? error.message
: String(error),
reason: error instanceof Error ? error.message : String(error),
});
}
} */
}
ngOnDestroy(): void {
this.cancelPendingScrollTargetClear();