Files
iptvnator/apps/web/src/app/settings/settings.component.html
T
4gray 7c42c1b6fc feat(settings): add mpvReuseInstance setting to store and i18n
Add MPV_REUSE_INSTANCE key to the electron backend store service and
include mpvReuseInstance in the shared settings interface so the new
boolean setting is persisted and available across renderer and main
processes.

Also update English i18n JSON formatting and expand the HOME section
translations (reformatting and adding nested playlist-related keys)
to ensure the UI strings remain consistent after changes.
2025-10-18 11:57:20 +02:00

415 lines
16 KiB
HTML

@if (!isDialog) {
<app-header
[title]="'SETTINGS.TITLE' | translate"
[subtitle]="
('SETTINGS.SUBTITLE' | translate) +
'. ' +
('SETTINGS.DESCRIPTION' | translate)
"
/>
} @else {
<h2 mat-dialog-title>{{ 'SETTINGS.TITLE' | translate }}</h2>
}
<div class="settings-container" data-test-id="settings-container">
<form [formGroup]="settingsForm" (ngSubmit)="onSubmit()" novalidate>
@if (isDesktop) {
<ng-container formArrayName="epgUrl">
<div class="row">
<div class="column">
{{ 'SETTINGS.EPG_URL_LABEL' | translate }}
<p>Add single or multiple URLs as EPG sources</p>
</div>
<div class="column">
@for (_ of epgUrl.controls; track _; let i = $index) {
<div style="display: flex">
<mat-form-field
appearance="outline"
class="full-width"
>
<mat-label>{{
'SETTINGS.EPG_URL_PLACEHOLDER'
| translate
}}</mat-label>
<input
matInput
type="url"
[formControlName]="i"
#epgField
/>
<mat-error>{{
'SETTINGS.EPG_URL_ERROR' | translate
}}</mat-error>
</mat-form-field>
<button
matLine
mat-icon-button
color="accent"
[matTooltip]="
'SETTINGS.REFRESH_EPG' | translate
"
type="button"
[disabled]="epgField.value === ''"
(click)="refreshEpg(epgUrl.value[i])"
>
<mat-icon>refresh</mat-icon>
</button>
<button
mat-icon-button
matLine
color="accent"
[matTooltip]="
'SETTINGS.REFRESH_EPG' | translate
"
type="button"
(click)="removeEpgSource(i)"
>
<mat-icon>remove</mat-icon>
</button>
</div>
}
<button
mat-button
color="accent"
type="button"
(click)="addEpgSource()"
>
{{ 'SETTINGS.ADD_EPG_SOURCE' | translate }}
</button>
</div>
</div>
<mat-divider />
</ng-container>
}
<div class="row">
<div class="column">
{{ 'SETTINGS.VIDEO_PLAYER_LABEL' | translate }}
<p>{{ 'SETTINGS.VIDEO_PLAYER_DESCRIPTION' | translate }}</p>
</div>
<div class="column">
<mat-form-field appearance="outline">
<mat-label>{{
'SETTINGS.VIDEO_PLAYER_PLACEHOLDER' | translate
}}</mat-label>
<mat-select
formControlName="player"
data-test-id="select-video-player"
>
@for (player of players; track player) {
<mat-option
[value]="player.id"
[attr.data-test-id]="player.id"
>{{ player.label }}
</mat-option>
}
</mat-select>
</mat-form-field>
</div>
</div>
@if (settingsForm.value.player === 'mpv') {
<div class="row">
<div class="column">
{{ 'SETTINGS.MPV_PLAYER_PATH_LABEL' | translate }}
<p>
{{ 'SETTINGS.MPV_PLAYER_PATH_DESCRIPTION' | translate }}
</p>
</div>
<div class="column">
<mat-form-field appearance="outline">
<mat-label for="mpvPlayerPath">{{
'SETTINGS.MPV_PLAYER_PATH' | translate
}}</mat-label>
<input
matInput
type="text"
id="mpvPlayerPath"
formControlName="mpvPlayerPath"
/>
</mat-form-field>
</div>
</div>
<div class="row">
<div class="column">
{{ 'SETTINGS.MPV_REUSE_INSTANCE_LABEL' | translate }}
<p>
{{
'SETTINGS.MPV_REUSE_INSTANCE_DESCRIPTION'
| translate
}}
</p>
</div>
<div class="column margin-right">
<mat-checkbox
class="column"
formControlName="mpvReuseInstance"
></mat-checkbox>
</div>
</div>
}
@if (settingsForm.value.player === 'vlc') {
<div class="row">
<div class="column">
{{ 'SETTINGS.VLC_PLAYER_PATH_LABEL' | translate }}
<p>
{{ 'SETTINGS.VLC_PLAYER_PATH_DESCRIPTION' | translate }}
</p>
</div>
<div class="column">
<mat-form-field appearance="outline">
<mat-label for="vlcPlayerPath">{{
'SETTINGS.VLC_PLAYER_PATH' | translate
}}</mat-label>
<input
matInput
type="text"
id="vlcPlayerPath"
formControlName="vlcPlayerPath"
/>
</mat-form-field>
</div>
</div>
}
<mat-divider />
<div class="row">
<div class="column">
{{ 'SETTINGS.STREAM_FORMAT' | translate }}
<p>{{ 'SETTINGS.STREAM_FORMAT_DESCRIPTION' | translate }}</p>
</div>
<div class="column">
<mat-form-field appearance="outline">
<mat-label>{{
'SETTINGS.VIDEO_PLAYER_PLACEHOLDER' | translate
}}</mat-label>
<mat-select
formControlName="streamFormat"
data-test-id="select-stream-format"
>
@for (
streamFormat of streamFormatEnum | keyvalue;
track streamFormat
) {
<mat-option
[value]="streamFormat.value"
[attr.data-test-id]="streamFormat.value"
>{{ streamFormat.value }}
</mat-option>
}
</mat-select>
</mat-form-field>
</div>
</div>
<mat-divider />
<div class="row">
<div class="column">
{{ 'SETTINGS.LANGUAGE' | translate }}
<p>{{ 'SETTINGS.LANGUAGE_DESCRIPTION' | translate }}</p>
</div>
<div class="column">
<mat-form-field appearance="outline">
<mat-label>{{
'SETTINGS.VIDEO_PLAYER_PLACEHOLDER' | translate
}}</mat-label>
<mat-select
formControlName="language"
data-test-id="select-language"
>
@for (
language of languageEnum | keyvalue;
track language
) {
<mat-option
[value]="language.value"
[attr.data-test-id]="language.value"
>{{
'LANGUAGES.' + language.key | translate
}}</mat-option
>
}
</mat-select>
</mat-form-field>
</div>
</div>
<mat-divider />
<div class="row">
<div class="column">
{{ 'SETTINGS.THEME' | translate }}
<p>{{ 'SETTINGS.THEME_DESCRIPTION' | translate }}</p>
</div>
<div class="column">
<mat-form-field appearance="outline">
<mat-label>{{
'SETTINGS.VIDEO_PLAYER_PLACEHOLDER' | translate
}}</mat-label>
<mat-select
formControlName="theme"
data-test-id="select-theme"
>
@for (theme of themeEnum | keyvalue; track theme) {
<mat-option
[value]="theme.value"
[attr.data-test-id]="theme.value"
>{{
'THEMES.' + theme.value | translate
}}</mat-option
>
}
</mat-select>
</mat-form-field>
</div>
</div>
<mat-divider />
<div class="row">
<div class="column">
{{ 'SETTINGS.SHOW_CAPTIONS' | translate }}
<p>{{ 'SETTINGS.SHOW_CAPTIONS_DESCRIPTION' | translate }}</p>
</div>
<div class="column margin-right">
<mat-checkbox
class="column"
formControlName="showCaptions"
></mat-checkbox>
</div>
</div>
<!-- not ported to tauri yet
@if (isPwa || isDesktop) {
<mat-divider />
<div class="row">
<div class="column">
{{ 'SETTINGS.REMOTE_CONTROL' | translate }}
<p>
{{ 'SETTINGS.REMOTE_CONTROL_DESCRIPTION' | translate }}
</p>
</div>
<div class="column margin-right">
<mat-checkbox
class="column"
formControlName="remoteControl"
></mat-checkbox>
</div>
</div>
}
-->
@if (settingsForm.value.remoteControl === true) {
<mat-divider />
<div class="row">
<div class="column">
{{ 'SETTINGS.REMOTE_CONTROL_PORT' | translate }}
<p>
{{
'SETTINGS.REMOTE_CONTROL_PORT_DESCRIPTION'
| translate
}}
</p>
</div>
<div class="column margin-right">
<mat-form-field appearance="outline" class="full-width">
<input
matInput
type="text"
id="remoteControlPort"
formControlName="remoteControlPort"
/>
</mat-form-field>
</div>
</div>
}
<mat-divider />
<div class="row">
<div class="column">
{{ 'SETTINGS.VERSION' | translate }}
<p>{{ 'SETTINGS.VERSION_DESCRIPTION' | translate }}</p>
</div>
<div class="column">
{{ version }} <br />
{{ updateMessage }}
</div>
</div>
<mat-divider />
<div class="row">
<div class="column">
{{ 'SETTINGS.IMPORT_EXPORT_DATA' | translate }}
<p>
{{ 'SETTINGS.IMPORT_EXPORT_DATA_DESCRIPTION' | translate }}
</p>
</div>
<div class="column">
<button
mat-button
(click)="
$event.preventDefault();
$event.stopPropagation();
importData()
"
>
{{ 'SETTINGS.IMPORT_DATA' | translate }}
</button>
<button
mat-button
(click)="
$event.preventDefault();
$event.stopPropagation();
exportData()
"
>
{{ 'SETTINGS.EXPORT_DATA' | translate }}
</button>
</div>
</div>
<div class="row">
<div class="column">
{{ 'SETTINGS.REMOVE_ALL' | translate }}
<p>
{{ 'SETTINGS.REMOVE_ALL_DESCRIPTION' | translate }}
</p>
</div>
<div class="column">
<button
mat-button
(click)="
$event.preventDefault();
$event.stopPropagation();
removeAll()
"
color="warn"
>
{{ 'SETTINGS.REMOVE_ALL_BUTTON' | translate }}
</button>
</div>
</div>
@if (isPwa) {
<div class="row">
{{ 'SETTINGS.EPG_NOTE' | translate }}
&nbsp;<a href="https://github.com/4gray/iptvnator/releases">{{
'SETTINGS.EPG_NOTE_URL_TEXT' | translate
}}</a>
</div>
}
<mat-divider />
<div class="action-buttons" align="end">
<button
mat-button
color="accent"
type="reset"
(click)="backToHome()"
data-test-id="back-to-home"
>
<mat-icon>chevron_left</mat-icon>
{{ 'SETTINGS.BACK_TO_HOME' | translate }}
</button>
<button
mat-button
color="accent"
type="submit"
[disabled]="settingsForm.pristine || !settingsForm.valid"
data-test-id="save-settings"
>
<mat-icon>save</mat-icon>
{{ 'SETTINGS.SAVE_CHANGES' | translate }}
</button>
</div>
</form>
</div>