mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-08 17:06:15 -08:00
refactor(settings): add backup and reset functionality with UI updates
Entire-Checkpoint: c6e522b4276c
This commit is contained in:
1 parent
e53a25f441
commit
58ee06bb2b
21 files changed
+371
-96
No files matched your search
@@ -476,7 +476,6 @@
|
||||
}
|
||||
<button
|
||||
mat-icon-button
|
||||
color="accent"
|
||||
[matTooltip]="
|
||||
'SETTINGS.REFRESH_EPG'
|
||||
| translate
|
||||
@@ -495,7 +494,6 @@
|
||||
</button>
|
||||
<button
|
||||
mat-icon-button
|
||||
color="accent"
|
||||
[matTooltip]="
|
||||
'SETTINGS.REMOVE_EPG_SOURCE'
|
||||
| translate
|
||||
@@ -517,10 +515,10 @@
|
||||
<div class="inline-actions">
|
||||
<button
|
||||
mat-button
|
||||
color="accent"
|
||||
type="button"
|
||||
(click)="addEpgSource()"
|
||||
>
|
||||
<mat-icon>add</mat-icon>
|
||||
{{ 'SETTINGS.ADD_EPG_SOURCE' | translate }}
|
||||
</button>
|
||||
<button
|
||||
@@ -752,20 +750,17 @@
|
||||
|
||||
<section
|
||||
class="settings-group"
|
||||
[class.settings-group--active]="activeSection() === 'data'"
|
||||
id="data"
|
||||
[class.settings-group--active]="activeSection() === 'backup'"
|
||||
id="backup"
|
||||
>
|
||||
<header class="settings-group__header">
|
||||
<div class="settings-group__header-icon">
|
||||
<mat-icon>sync_alt</mat-icon>
|
||||
<mat-icon>backup</mat-icon>
|
||||
</div>
|
||||
<div class="settings-group__header-text">
|
||||
<h3>{{ 'SETTINGS.DATA' | translate }}</h3>
|
||||
<h3>{{ 'SETTINGS.BACKUP' | translate }}</h3>
|
||||
<p>
|
||||
{{
|
||||
'SETTINGS.IMPORT_EXPORT_DATA_DESCRIPTION'
|
||||
| translate
|
||||
}}
|
||||
{{ 'SETTINGS.BACKUP_DESCRIPTION' | translate }}
|
||||
</p>
|
||||
</div>
|
||||
</header>
|
||||
@@ -829,39 +824,45 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="setting-item danger-zone">
|
||||
<div class="setting-item__meta">
|
||||
<h4>{{ 'SETTINGS.REMOVE_ALL' | translate }}</h4>
|
||||
<p>
|
||||
{{ 'SETTINGS.REMOVE_ALL_DESCRIPTION' | translate }}
|
||||
</p>
|
||||
<div class="danger-zone__summary" aria-live="polite">
|
||||
<span class="danger-zone__summary-pill">
|
||||
{{ 'HOME.PLAYLIST_TYPES.M3U' | translate }}
|
||||
<strong>{{
|
||||
playlistDeleteSummary().m3u
|
||||
}}</strong>
|
||||
</span>
|
||||
<span class="danger-zone__summary-pill">
|
||||
{{ 'HOME.PLAYLIST_TYPES.XTREAM' | translate }}
|
||||
<strong>{{
|
||||
playlistDeleteSummary().xtream
|
||||
}}</strong>
|
||||
</span>
|
||||
<span class="danger-zone__summary-pill">
|
||||
{{ 'HOME.PLAYLIST_TYPES.STALKER' | translate }}
|
||||
<strong>{{
|
||||
playlistDeleteSummary().stalker
|
||||
}}</strong>
|
||||
</span>
|
||||
</div>
|
||||
@if (removeAllProgressLabel(); as progressLabel) {
|
||||
<p class="danger-zone__progress">
|
||||
{{ progressLabel }}
|
||||
</p>
|
||||
}
|
||||
@if (isPwa) {
|
||||
<div class="settings-note">
|
||||
{{ 'SETTINGS.EPG_NOTE' | translate }}
|
||||
<a
|
||||
href="https://github.com/4gray/iptvnator/releases"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>{{ 'SETTINGS.EPG_NOTE_URL_TEXT' | translate }}</a
|
||||
>
|
||||
</div>
|
||||
<div class="setting-item__control">
|
||||
}
|
||||
</section>
|
||||
|
||||
<section
|
||||
class="settings-group"
|
||||
[class.settings-group--active]="activeSection() === 'reset'"
|
||||
id="reset"
|
||||
>
|
||||
<header class="settings-group__header">
|
||||
<div class="settings-group__header-icon">
|
||||
<mat-icon>delete_sweep</mat-icon>
|
||||
</div>
|
||||
<div class="settings-group__header-text">
|
||||
<h3>{{ 'SETTINGS.RESET' | translate }}</h3>
|
||||
<p>{{ 'SETTINGS.RESET_DESCRIPTION' | translate }}</p>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="setting-item danger-zone">
|
||||
<div class="danger-zone__header">
|
||||
<div class="setting-item__meta">
|
||||
<h4>{{ 'SETTINGS.REMOVE_ALL' | translate }}</h4>
|
||||
<p>
|
||||
{{
|
||||
'SETTINGS.REMOVE_ALL_DESCRIPTION'
|
||||
| translate
|
||||
}}
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
mat-button
|
||||
class="danger-zone__button"
|
||||
@@ -894,19 +895,47 @@
|
||||
}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (isPwa) {
|
||||
<div class="settings-note">
|
||||
{{ 'SETTINGS.EPG_NOTE' | translate }}
|
||||
<a
|
||||
href="https://github.com/4gray/iptvnator/releases"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>{{ 'SETTINGS.EPG_NOTE_URL_TEXT' | translate }}</a
|
||||
>
|
||||
<div class="danger-zone__summary" aria-live="polite">
|
||||
<span class="danger-zone__summary-pill">
|
||||
<mat-icon class="danger-zone__summary-icon"
|
||||
>folder_open</mat-icon
|
||||
>
|
||||
<span class="danger-zone__summary-label">{{
|
||||
'HOME.PLAYLIST_TYPES.M3U' | translate
|
||||
}}</span>
|
||||
<span class="danger-zone__summary-count">{{
|
||||
playlistDeleteSummary().m3u
|
||||
}}</span>
|
||||
</span>
|
||||
<span class="danger-zone__summary-pill">
|
||||
<mat-icon class="danger-zone__summary-icon"
|
||||
>cloud</mat-icon
|
||||
>
|
||||
<span class="danger-zone__summary-label">{{
|
||||
'HOME.PLAYLIST_TYPES.XTREAM' | translate
|
||||
}}</span>
|
||||
<span class="danger-zone__summary-count">{{
|
||||
playlistDeleteSummary().xtream
|
||||
}}</span>
|
||||
</span>
|
||||
<span class="danger-zone__summary-pill">
|
||||
<mat-icon class="danger-zone__summary-icon"
|
||||
>cast</mat-icon
|
||||
>
|
||||
<span class="danger-zone__summary-label">{{
|
||||
'HOME.PLAYLIST_TYPES.STALKER' | translate
|
||||
}}</span>
|
||||
<span class="danger-zone__summary-count">{{
|
||||
playlistDeleteSummary().stalker
|
||||
}}</span>
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
@if (removeAllProgressLabel(); as progressLabel) {
|
||||
<p class="danger-zone__progress">
|
||||
{{ progressLabel }}
|
||||
</p>
|
||||
}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section
|
||||
@@ -1116,7 +1145,6 @@
|
||||
<button
|
||||
mat-button
|
||||
type="button"
|
||||
color="accent"
|
||||
(click)="backToHome()"
|
||||
data-test-id="back-to-home"
|
||||
>
|
||||
@@ -1126,8 +1154,8 @@
|
||||
}
|
||||
<button
|
||||
mat-flat-button
|
||||
color="accent"
|
||||
type="submit"
|
||||
class="settings-save-button"
|
||||
[disabled]="settingsForm.pristine || !settingsForm.valid"
|
||||
data-test-id="save-settings"
|
||||
>
|
||||
|
||||
@@ -32,11 +32,10 @@
|
||||
}
|
||||
|
||||
.settings-page-header {
|
||||
padding: 14px 18px;
|
||||
border: 1px solid var(--settings-page-header-border);
|
||||
border-radius: 18px;
|
||||
background: var(--settings-page-header-bg);
|
||||
box-shadow: var(--settings-page-header-shadow);
|
||||
padding: 14px 18px 8px;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.settings-page-header__text {
|
||||
@@ -590,46 +589,91 @@
|
||||
background: var(--settings-item-danger-bg);
|
||||
border: 1px solid var(--settings-item-danger-border);
|
||||
border-radius: 16px;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.danger-zone__header {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
|
||||
.setting-item__meta {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.danger-zone__summary {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
margin-top: 10px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.danger-zone__summary-pill {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
min-height: 32px;
|
||||
padding: 6px 10px;
|
||||
border-radius: 999px;
|
||||
min-height: 34px;
|
||||
padding: 4px 6px 4px 12px;
|
||||
border-radius: 12px;
|
||||
background: color-mix(
|
||||
in srgb,
|
||||
var(--mat-sys-surface-container-high) 78%,
|
||||
transparent
|
||||
);
|
||||
border: 1px solid
|
||||
color-mix(in srgb, var(--settings-item-danger-border) 72%, transparent);
|
||||
color-mix(in srgb, var(--settings-item-danger-border) 60%, transparent);
|
||||
font-size: 0.82rem;
|
||||
line-height: 1.2;
|
||||
color: var(--mat-sys-on-surface);
|
||||
|
||||
strong {
|
||||
.danger-zone__summary-icon {
|
||||
font-size: 18px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
color: var(--mat-sys-on-surface-variant);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.danger-zone__summary-label {
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.01em;
|
||||
}
|
||||
|
||||
.danger-zone__summary-count {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 26px;
|
||||
height: 22px;
|
||||
padding: 0 8px;
|
||||
border-radius: 999px;
|
||||
background: color-mix(
|
||||
in srgb,
|
||||
var(--mat-sys-on-surface) 10%,
|
||||
transparent
|
||||
);
|
||||
color: var(--mat-sys-on-surface);
|
||||
font-size: 0.78rem;
|
||||
font-weight: 700;
|
||||
font-variant-numeric: tabular-nums;
|
||||
margin-left: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.danger-zone__progress {
|
||||
margin-top: 12px;
|
||||
margin-bottom: 0;
|
||||
margin: 0;
|
||||
color: var(--mat-sys-on-surface-variant);
|
||||
font-size: 0.84rem;
|
||||
}
|
||||
|
||||
.danger-zone__button {
|
||||
min-width: 138px;
|
||||
flex-shrink: 0;
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
.danger-zone__button--busy {
|
||||
@@ -670,6 +714,46 @@
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.settings-save-button.mat-mdc-button-base {
|
||||
background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
|
||||
color: #fff;
|
||||
font-weight: 500;
|
||||
padding: 0 20px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 4px 14px rgba(59, 130, 246, 0.28);
|
||||
transition:
|
||||
transform 0.2s ease,
|
||||
box-shadow 0.2s ease,
|
||||
opacity 0.2s ease;
|
||||
|
||||
mat-icon {
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
&:hover:not([disabled]) {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 6px 18px rgba(59, 130, 246, 0.38);
|
||||
}
|
||||
|
||||
&:active:not([disabled]) {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
&[disabled] {
|
||||
background: color-mix(
|
||||
in srgb,
|
||||
var(--mat-sys-on-surface) 12%,
|
||||
transparent
|
||||
);
|
||||
color: color-mix(
|
||||
in srgb,
|
||||
var(--mat-sys-on-surface) 38%,
|
||||
transparent
|
||||
);
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 1100px) {
|
||||
.settings-layout {
|
||||
max-width: 100%;
|
||||
|
||||
@@ -55,6 +55,7 @@ import {
|
||||
PlaylistsService,
|
||||
} from 'services';
|
||||
import {
|
||||
EmbeddedMpvSupport,
|
||||
Language,
|
||||
StartupBehavior,
|
||||
StreamFormat,
|
||||
@@ -150,13 +151,25 @@ 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 supportsEmbeddedMpv = computed(
|
||||
() => this.isDesktop && !!this.embeddedMpvSupport()?.supported
|
||||
);
|
||||
|
||||
isPwa = this.dataService.getAppEnvironment() === 'pwa';
|
||||
|
||||
private readonly settingsCtx = inject(SettingsContextService);
|
||||
readonly activeSection = this.settingsCtx.activeSection;
|
||||
|
||||
readonly osPlayers = [
|
||||
readonly osPlayers = computed(() => [
|
||||
...(this.supportsEmbeddedMpv()
|
||||
? [
|
||||
{
|
||||
id: VideoPlayer.EmbeddedMpv,
|
||||
labelKey: 'SETTINGS.PLAYER_EMBEDDED_MPV',
|
||||
},
|
||||
]
|
||||
: []),
|
||||
{
|
||||
id: VideoPlayer.MPV,
|
||||
labelKey: 'SETTINGS.PLAYER_MPV',
|
||||
@@ -165,10 +178,10 @@ export class SettingsComponent implements OnInit, OnDestroy {
|
||||
id: VideoPlayer.VLC,
|
||||
labelKey: 'SETTINGS.PLAYER_VLC',
|
||||
},
|
||||
];
|
||||
]);
|
||||
|
||||
/** Player options */
|
||||
readonly players = [
|
||||
readonly players = computed(() => [
|
||||
{
|
||||
id: VideoPlayer.Html5Player,
|
||||
labelKey: 'SETTINGS.PLAYER_HTML5',
|
||||
@@ -181,8 +194,8 @@ export class SettingsComponent implements OnInit, OnDestroy {
|
||||
id: VideoPlayer.ArtPlayer,
|
||||
labelKey: 'SETTINGS.PLAYER_ARTPLAYER',
|
||||
},
|
||||
...(this.isDesktop ? this.osPlayers : []),
|
||||
];
|
||||
...(this.isDesktop ? this.osPlayers() : []),
|
||||
]);
|
||||
|
||||
/** Current version of the app */
|
||||
version: string;
|
||||
@@ -296,9 +309,15 @@ export class SettingsComponent implements OnInit, OnDestroy {
|
||||
visible: this.isDesktop,
|
||||
},
|
||||
{
|
||||
id: 'data',
|
||||
label: 'SETTINGS.NAV_DATA',
|
||||
icon: 'swap_horiz',
|
||||
id: 'backup',
|
||||
label: 'SETTINGS.NAV_BACKUP',
|
||||
icon: 'backup',
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
id: 'reset',
|
||||
label: 'SETTINGS.NAV_RESET',
|
||||
icon: 'delete_sweep',
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
@@ -418,8 +437,9 @@ export class SettingsComponent implements OnInit, OnDestroy {
|
||||
// Wait for settings to load before setting the form
|
||||
await this.settingsStore.loadSettings();
|
||||
this.setSettings();
|
||||
void this.loadEmbeddedMpvSupport();
|
||||
this.checkAppVersion();
|
||||
this.fetchLocalIpAddresses();
|
||||
void this.fetchLocalIpAddresses();
|
||||
|
||||
if (!this.isDialog) {
|
||||
this.settingsCtx.setSections(this.sectionNav);
|
||||
@@ -428,6 +448,41 @@ export class SettingsComponent implements OnInit, OnDestroy {
|
||||
requestAnimationFrame(() => this.setupSectionObserver());
|
||||
}
|
||||
|
||||
private async loadEmbeddedMpvSupport(): Promise<void> {
|
||||
if (!this.isDesktop) {
|
||||
this.embeddedMpvSupport.set({
|
||||
supported: false,
|
||||
platform: 'web',
|
||||
reason: 'Embedded MPV requires the Electron desktop build.',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!window.electron?.getEmbeddedMpvSupport) {
|
||||
this.embeddedMpvSupport.set({
|
||||
supported: false,
|
||||
platform: window.electron.platform,
|
||||
reason: 'Embedded MPV support is not available in this build.',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.embeddedMpvSupport.set(
|
||||
await window.electron.getEmbeddedMpvSupport()
|
||||
);
|
||||
} catch (error) {
|
||||
this.embeddedMpvSupport.set({
|
||||
supported: false,
|
||||
platform: window.electron.platform,
|
||||
reason:
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: String(error),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.cancelPendingScrollTargetClear();
|
||||
this.sectionObserver?.disconnect();
|
||||
|
||||
@@ -211,7 +211,13 @@
|
||||
"REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}",
|
||||
"PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again.",
|
||||
"EPG_EMPTY_TITLE": "No EPG sources yet",
|
||||
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels."
|
||||
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels.",
|
||||
"BACKUP": "Backup",
|
||||
"BACKUP_DESCRIPTION": "Export your library as a snapshot, or restore from a previous backup.",
|
||||
"RESET": "Reset",
|
||||
"RESET_DESCRIPTION": "Permanently delete content stored in this app.",
|
||||
"NAV_BACKUP": "Backup",
|
||||
"NAV_RESET": "Reset"
|
||||
},
|
||||
"THEMES": {
|
||||
"DARK_THEME": "السمة الداكنة",
|
||||
|
||||
@@ -203,7 +203,13 @@
|
||||
"REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}",
|
||||
"PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again.",
|
||||
"EPG_EMPTY_TITLE": "No EPG sources yet",
|
||||
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels."
|
||||
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels.",
|
||||
"BACKUP": "Backup",
|
||||
"BACKUP_DESCRIPTION": "Export your library as a snapshot, or restore from a previous backup.",
|
||||
"RESET": "Reset",
|
||||
"RESET_DESCRIPTION": "Permanently delete content stored in this app.",
|
||||
"NAV_BACKUP": "Backup",
|
||||
"NAV_RESET": "Reset"
|
||||
},
|
||||
"THEMES": {
|
||||
"DARK_THEME": "المظهر الداكن",
|
||||
|
||||
@@ -205,7 +205,13 @@
|
||||
"REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}",
|
||||
"PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again.",
|
||||
"EPG_EMPTY_TITLE": "No EPG sources yet",
|
||||
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels."
|
||||
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels.",
|
||||
"BACKUP": "Backup",
|
||||
"BACKUP_DESCRIPTION": "Export your library as a snapshot, or restore from a previous backup.",
|
||||
"RESET": "Reset",
|
||||
"RESET_DESCRIPTION": "Permanently delete content stored in this app.",
|
||||
"NAV_BACKUP": "Backup",
|
||||
"NAV_RESET": "Reset"
|
||||
},
|
||||
"THEMES": {
|
||||
"DARK_THEME": "Цёмная тэма",
|
||||
|
||||
@@ -378,7 +378,13 @@
|
||||
"REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}",
|
||||
"PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again.",
|
||||
"EPG_EMPTY_TITLE": "No EPG sources yet",
|
||||
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels."
|
||||
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels.",
|
||||
"BACKUP": "Backup",
|
||||
"BACKUP_DESCRIPTION": "Export your library as a snapshot, or restore from a previous backup.",
|
||||
"RESET": "Reset",
|
||||
"RESET_DESCRIPTION": "Permanently delete content stored in this app.",
|
||||
"NAV_BACKUP": "Backup",
|
||||
"NAV_RESET": "Reset"
|
||||
},
|
||||
"THEMES": {
|
||||
"DARK_THEME": "Dunkel",
|
||||
|
||||
@@ -256,7 +256,13 @@
|
||||
"REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}",
|
||||
"PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again.",
|
||||
"EPG_EMPTY_TITLE": "No EPG sources yet",
|
||||
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels."
|
||||
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels.",
|
||||
"BACKUP": "Backup",
|
||||
"BACKUP_DESCRIPTION": "Export your library as a snapshot, or restore from a previous backup.",
|
||||
"RESET": "Reset",
|
||||
"RESET_DESCRIPTION": "Permanently delete content stored in this app.",
|
||||
"NAV_BACKUP": "Backup",
|
||||
"NAV_RESET": "Reset"
|
||||
},
|
||||
"THEMES": {
|
||||
"DARK_THEME": "Σκούρο θέμα",
|
||||
|
||||
@@ -203,12 +203,18 @@
|
||||
"EPG_EMPTY_TITLE": "No EPG sources yet",
|
||||
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels.",
|
||||
"DATA": "Data",
|
||||
"BACKUP": "Backup",
|
||||
"BACKUP_DESCRIPTION": "Export your library as a snapshot, or restore from a previous backup.",
|
||||
"RESET": "Reset",
|
||||
"RESET_DESCRIPTION": "Permanently delete content stored in this app.",
|
||||
"ABOUT": "About",
|
||||
"NAV_GENERAL": "General",
|
||||
"NAV_PLAYBACK": "Playback",
|
||||
"NAV_EPG": "EPG",
|
||||
"NAV_REMOTE": "Remote",
|
||||
"NAV_DATA": "Data",
|
||||
"NAV_BACKUP": "Backup",
|
||||
"NAV_RESET": "Reset",
|
||||
"NAV_ABOUT": "About",
|
||||
"APP_PREFERENCES": "App preferences",
|
||||
"HERO_EYEBROW": "Workspace settings",
|
||||
|
||||
@@ -233,7 +233,13 @@
|
||||
"REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}",
|
||||
"PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again.",
|
||||
"EPG_EMPTY_TITLE": "No EPG sources yet",
|
||||
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels."
|
||||
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels.",
|
||||
"BACKUP": "Backup",
|
||||
"BACKUP_DESCRIPTION": "Export your library as a snapshot, or restore from a previous backup.",
|
||||
"RESET": "Reset",
|
||||
"RESET_DESCRIPTION": "Permanently delete content stored in this app.",
|
||||
"NAV_BACKUP": "Backup",
|
||||
"NAV_RESET": "Reset"
|
||||
},
|
||||
"THEMES": {
|
||||
"DARK_THEME": "Tema oscuro",
|
||||
|
||||
@@ -224,7 +224,13 @@
|
||||
"REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}",
|
||||
"PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again.",
|
||||
"EPG_EMPTY_TITLE": "No EPG sources yet",
|
||||
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels."
|
||||
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels.",
|
||||
"BACKUP": "Backup",
|
||||
"BACKUP_DESCRIPTION": "Export your library as a snapshot, or restore from a previous backup.",
|
||||
"RESET": "Reset",
|
||||
"RESET_DESCRIPTION": "Permanently delete content stored in this app.",
|
||||
"NAV_BACKUP": "Backup",
|
||||
"NAV_RESET": "Reset"
|
||||
},
|
||||
"THEMES": {
|
||||
"DARK_THEME": "Thème foncé",
|
||||
|
||||
@@ -245,7 +245,13 @@
|
||||
"REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}",
|
||||
"PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again.",
|
||||
"EPG_EMPTY_TITLE": "No EPG sources yet",
|
||||
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels."
|
||||
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels.",
|
||||
"BACKUP": "Backup",
|
||||
"BACKUP_DESCRIPTION": "Export your library as a snapshot, or restore from a previous backup.",
|
||||
"RESET": "Reset",
|
||||
"RESET_DESCRIPTION": "Permanently delete content stored in this app.",
|
||||
"NAV_BACKUP": "Backup",
|
||||
"NAV_RESET": "Reset"
|
||||
},
|
||||
"THEMES": {
|
||||
"DARK_THEME": "Tema scuro",
|
||||
|
||||
@@ -191,7 +191,13 @@
|
||||
"REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}",
|
||||
"PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again.",
|
||||
"EPG_EMPTY_TITLE": "No EPG sources yet",
|
||||
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels."
|
||||
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels.",
|
||||
"BACKUP": "Backup",
|
||||
"BACKUP_DESCRIPTION": "Export your library as a snapshot, or restore from a previous backup.",
|
||||
"RESET": "Reset",
|
||||
"RESET_DESCRIPTION": "Permanently delete content stored in this app.",
|
||||
"NAV_BACKUP": "Backup",
|
||||
"NAV_RESET": "Reset"
|
||||
},
|
||||
"THEMES": {
|
||||
"DARK_THEME": "ダークテーマ",
|
||||
|
||||
@@ -162,7 +162,13 @@
|
||||
"REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}",
|
||||
"PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again.",
|
||||
"EPG_EMPTY_TITLE": "No EPG sources yet",
|
||||
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels."
|
||||
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels.",
|
||||
"BACKUP": "Backup",
|
||||
"BACKUP_DESCRIPTION": "Export your library as a snapshot, or restore from a previous backup.",
|
||||
"RESET": "Reset",
|
||||
"RESET_DESCRIPTION": "Permanently delete content stored in this app.",
|
||||
"NAV_BACKUP": "Backup",
|
||||
"NAV_RESET": "Reset"
|
||||
},
|
||||
"THEMES": {
|
||||
"DARK_THEME": "어두운 테마",
|
||||
|
||||
@@ -203,7 +203,13 @@
|
||||
"REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}",
|
||||
"PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again.",
|
||||
"EPG_EMPTY_TITLE": "No EPG sources yet",
|
||||
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels."
|
||||
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels.",
|
||||
"BACKUP": "Backup",
|
||||
"BACKUP_DESCRIPTION": "Export your library as a snapshot, or restore from a previous backup.",
|
||||
"RESET": "Reset",
|
||||
"RESET_DESCRIPTION": "Permanently delete content stored in this app.",
|
||||
"NAV_BACKUP": "Backup",
|
||||
"NAV_RESET": "Reset"
|
||||
},
|
||||
"THEMES": {
|
||||
"DARK_THEME": "Donker thema",
|
||||
|
||||
@@ -203,7 +203,13 @@
|
||||
"REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}",
|
||||
"PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again.",
|
||||
"EPG_EMPTY_TITLE": "No EPG sources yet",
|
||||
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels."
|
||||
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels.",
|
||||
"BACKUP": "Backup",
|
||||
"BACKUP_DESCRIPTION": "Export your library as a snapshot, or restore from a previous backup.",
|
||||
"RESET": "Reset",
|
||||
"RESET_DESCRIPTION": "Permanently delete content stored in this app.",
|
||||
"NAV_BACKUP": "Backup",
|
||||
"NAV_RESET": "Reset"
|
||||
},
|
||||
"THEMES": {
|
||||
"DARK_THEME": "Ciemny motyw",
|
||||
|
||||
@@ -222,7 +222,13 @@
|
||||
"REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}",
|
||||
"PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again.",
|
||||
"EPG_EMPTY_TITLE": "No EPG sources yet",
|
||||
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels."
|
||||
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels.",
|
||||
"BACKUP": "Backup",
|
||||
"BACKUP_DESCRIPTION": "Export your library as a snapshot, or restore from a previous backup.",
|
||||
"RESET": "Reset",
|
||||
"RESET_DESCRIPTION": "Permanently delete content stored in this app.",
|
||||
"NAV_BACKUP": "Backup",
|
||||
"NAV_RESET": "Reset"
|
||||
},
|
||||
"THEMES": {
|
||||
"DARK_THEME": "Tema escuro",
|
||||
|
||||
@@ -301,7 +301,13 @@
|
||||
"REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}",
|
||||
"PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again.",
|
||||
"EPG_EMPTY_TITLE": "No EPG sources yet",
|
||||
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels."
|
||||
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels.",
|
||||
"BACKUP": "Backup",
|
||||
"BACKUP_DESCRIPTION": "Export your library as a snapshot, or restore from a previous backup.",
|
||||
"RESET": "Reset",
|
||||
"RESET_DESCRIPTION": "Permanently delete content stored in this app.",
|
||||
"NAV_BACKUP": "Backup",
|
||||
"NAV_RESET": "Reset"
|
||||
},
|
||||
"THEMES": {
|
||||
"DARK_THEME": "Тёмная тема",
|
||||
|
||||
@@ -257,7 +257,13 @@
|
||||
"REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}",
|
||||
"PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again.",
|
||||
"EPG_EMPTY_TITLE": "No EPG sources yet",
|
||||
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels."
|
||||
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels.",
|
||||
"BACKUP": "Backup",
|
||||
"BACKUP_DESCRIPTION": "Export your library as a snapshot, or restore from a previous backup.",
|
||||
"RESET": "Reset",
|
||||
"RESET_DESCRIPTION": "Permanently delete content stored in this app.",
|
||||
"NAV_BACKUP": "Backup",
|
||||
"NAV_RESET": "Reset"
|
||||
},
|
||||
"THEMES": {
|
||||
"DARK_THEME": "Koyu tema",
|
||||
|
||||
@@ -162,7 +162,13 @@
|
||||
"REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}",
|
||||
"PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again.",
|
||||
"EPG_EMPTY_TITLE": "No EPG sources yet",
|
||||
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels."
|
||||
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels.",
|
||||
"BACKUP": "Backup",
|
||||
"BACKUP_DESCRIPTION": "Export your library as a snapshot, or restore from a previous backup.",
|
||||
"RESET": "Reset",
|
||||
"RESET_DESCRIPTION": "Permanently delete content stored in this app.",
|
||||
"NAV_BACKUP": "Backup",
|
||||
"NAV_RESET": "Reset"
|
||||
},
|
||||
"THEMES": {
|
||||
"DARK_THEME": "暗黑模式",
|
||||
|
||||
@@ -208,7 +208,13 @@
|
||||
"REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}",
|
||||
"PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again.",
|
||||
"EPG_EMPTY_TITLE": "No EPG sources yet",
|
||||
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels."
|
||||
"EPG_EMPTY_HINT": "Add a URL to fetch program data for your channels.",
|
||||
"BACKUP": "Backup",
|
||||
"BACKUP_DESCRIPTION": "Export your library as a snapshot, or restore from a previous backup.",
|
||||
"RESET": "Reset",
|
||||
"RESET_DESCRIPTION": "Permanently delete content stored in this app.",
|
||||
"NAV_BACKUP": "Backup",
|
||||
"NAV_RESET": "Reset"
|
||||
},
|
||||
"THEMES": {
|
||||
"DARK_THEME": "深色主題",
|
||||
|
||||
Reference in new issue
Block a user