Proyecto App Linux

This commit is contained in:
2026-05-03 23:43:09 +02:00
commit 7482733843
1248 changed files with 189750 additions and 0 deletions
+37
View File
@@ -0,0 +1,37 @@
import nx from '@nx/eslint-plugin';
import baseConfig from '../../eslint.config.mjs';
export default [
...baseConfig,
...nx.configs['flat/angular'],
...nx.configs['flat/angular-template'],
{
files: ['**/*.ts'],
rules: {
'@angular-eslint/directive-selector': [
'error',
{
type: 'attribute',
prefix: 'app',
style: 'camelCase',
},
],
'@angular-eslint/component-selector': [
'error',
{
type: 'element',
prefix: 'app',
style: 'kebab-case',
},
],
},
},
{
files: ['**/*.html'],
// Override or add rules here
rules: {
'@angular-eslint/template/click-events-have-key-events': 'off',
'@angular-eslint/template/interactive-supports-focus': 'off',
},
},
];
+41
View File
@@ -0,0 +1,41 @@
import { nxPreset } from '@nx/jest/preset.js';
import { createEsmPreset } from 'jest-preset-angular/presets/index.js';
const angularEsmPreset = createEsmPreset({
diagnostics: false,
tsconfig: '<rootDir>/tsconfig.spec.json',
});
export default {
...nxPreset,
...angularEsmPreset,
displayName: 'web',
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
coverageDirectory: '../../coverage/apps/web',
resolver: nxPreset.resolver,
moduleFileExtensions: Array.from(
new Set([
...(nxPreset.moduleFileExtensions ?? []),
...(angularEsmPreset.moduleFileExtensions ?? []),
])
),
testMatch: nxPreset.testMatch,
testEnvironmentOptions: {},
snapshotSerializers: angularEsmPreset.snapshotSerializers,
moduleNameMapper: {
...(angularEsmPreset.moduleNameMapper ?? {}),
'^@iptvnator/portal/xtream/feature$':
'<rootDir>/src/test-stubs/xtream-feature.stub.ts',
tslib: 'tslib/tslib.es6.js',
'^iptv-playlist-parser$':
'<rootDir>/src/test-stubs/iptv-playlist-parser.mjs',
'^rxjs': '<rootDir>/../../node_modules/rxjs/dist/bundles/rxjs.umd.js',
'^uuid$': '<rootDir>/../../node_modules/uuid/wrapper.mjs',
},
transform: angularEsmPreset.transform,
transformIgnorePatterns: [],
extensionsToTreatAsEsm: angularEsmPreset.extensionsToTreatAsEsm,
coverageReporters: [
...(nxPreset.coverageReporters ?? []),
],
};
+201
View File
@@ -0,0 +1,201 @@
{
"name": "web",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"projectType": "application",
"prefix": "app",
"sourceRoot": "apps/web/src",
"cli": {
"cache": {
"enabled": false
}
},
"tags": ["scope:app", "type:app"],
"targets": {
"build": {
"executor": "@angular/build:application",
"outputs": ["{options.outputPath}"],
"options": {
"outputPath": {
"base": "dist/apps/web",
"browser": ""
},
"polyfills": ["zone.js"],
"tsConfig": "apps/web/tsconfig.app.json",
"inlineStyleLanguage": "scss",
"assets": [
"apps/web/src/favicon.ico",
"apps/web/src/assets",
"apps/web/src/manifest.webmanifest"
],
"styles": [
"apps/web/src/styles.scss",
"apps/web/src/m3-theme.scss",
"./node_modules/video.js/dist/video-js.css"
],
"allowedCommonJsDependencies": [
"qrcode",
"iptv-playlist-parser",
"mpegts.js",
"videojs-contrib-quality-levels",
"videojs-quality-selector-hls",
"global/window",
"global/document",
"@videojs/xhr",
"videojs-vtt.js",
"mux.js/lib/tools/parse-sidx",
"mux.js/lib/utils/clock",
"keycode",
"safe-json-parse/tuple",
"@xmldom/xmldom",
"url-toolkit"
]
},
"configurations": {
"production": {
"baseHref": "./",
"budgets": [
{
"type": "initial",
"maximumWarning": "4.5mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "12.5kb",
"maximumError": "15kb"
}
],
"outputHashing": "all",
"fileReplacements": [
{
"replace": "apps/web/src/environments/environment.ts",
"with": "apps/web/src/environments/environment.prod.ts"
}
]
},
"pwa": {
"baseHref": "/",
"budgets": [
{
"type": "initial",
"maximumWarning": "4.5mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "12.5kb",
"maximumError": "15kb"
}
],
"outputHashing": "all",
"optimization": true,
"extractLicenses": true,
"sourceMap": false,
"fileReplacements": [
{
"replace": "apps/web/src/environments/environment.ts",
"with": "apps/web/src/environments/environment.prod.ts"
}
]
},
"development": {
"optimization": false,
"extractLicenses": false,
"sourceMap": true
},
"electron-e2e": {
"baseHref": "./",
"optimization": false,
"extractLicenses": false,
"sourceMap": true
},
"kiratv": {
"baseHref": "./",
"budgets": [
{
"type": "initial",
"maximumWarning": "4.5mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "12.5kb",
"maximumError": "15kb"
}
],
"outputHashing": "all",
"fileReplacements": [
{
"replace": "apps/web/src/environments/environment.ts",
"with": "apps/web/src/environments/environment.kiratv.ts"
}
]
}
},
"defaultConfiguration": "production"
},
"build-e2e": {
"executor": "nx:run-commands",
"options": {
"command": "pnpm nx run web:build:electron-e2e"
}
},
"serve": {
"continuous": true,
"executor": "@angular/build:dev-server",
"configurations": {
"production": {
"buildTarget": "web:build:production"
},
"pwa": {
"buildTarget": "web:build:pwa"
},
"development": {
"buildTarget": "web:build:development"
},
"kiratv": {
"buildTarget": "web:build:kiratv"
}
},
"defaultConfiguration": "development",
"options": {
"proxyConfig": "apps/web/proxy.conf.json"
}
},
"extract-i18n": {
"executor": "@angular/build:extract-i18n",
"options": {
"buildTarget": "web:build"
}
},
"lint": {
"executor": "@nx/eslint:lint"
},
"test": {
"executor": "nx:run-commands",
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
"options": {
"command": [
"node",
"./node_modules/jest/bin/jest.js",
"--config",
"apps/web/jest.config.ts"
],
"env": {
"NODE_OPTIONS": "--experimental-vm-modules"
},
"forwardAllArgs": true
}
},
"serve-static": {
"continuous": true,
"executor": "@nx/web:file-server",
"options": {
"buildTarget": "web:build",
"port": 4200,
"staticFilePath": "dist/apps/web/browser",
"spa": true
}
}
}
}
+6
View File
@@ -0,0 +1,6 @@
{
"/api": {
"target": "http://localhost:3000",
"secure": false
}
}
+324
View File
@@ -0,0 +1,324 @@
.settings-container {
--settings-safe-bottom: env(safe-area-inset-bottom, 0px);
--settings-action-bar-offset: 24px;
--settings-action-bar-space: 112px;
--settings-page-header-bg: color-mix(
in srgb,
var(--mat-sys-surface-container-low) 94%,
rgba(255, 255, 255, 0.98)
);
--settings-page-header-border: color-mix(
in srgb,
var(--mat-sys-outline-variant) 72%,
transparent
);
--settings-page-header-shadow:
0 10px 20px -28px rgba(15, 23, 42, 0.16),
0 1px 0 rgba(255, 255, 255, 0.68) inset;
--settings-group-bg: color-mix(
in srgb,
var(--mat-sys-surface) 96%,
rgba(255, 255, 255, 0.96)
);
--settings-group-border: color-mix(
in srgb,
var(--mat-sys-outline-variant) 78%,
transparent
);
--settings-group-shadow: 0 14px 28px -32px rgba(15, 23, 42, 0.14);
--settings-group-active-bg: color-mix(
in srgb,
var(--app-selection-color) 2%,
rgba(255, 255, 255, 0.98)
);
--settings-group-active-ring: color-mix(
in srgb,
var(--app-selection-border) 68%,
var(--settings-group-border)
);
--settings-group-active-glow: color-mix(
in srgb,
var(--app-selection-glow) 28%,
transparent
);
--settings-group-active-shadow:
inset 0 0 0 1px var(--settings-group-active-ring),
0 12px 24px -28px var(--settings-group-active-glow);
--settings-item-border: var(--app-separator);
--settings-item-danger-bg: color-mix(
in srgb,
var(--mat-sys-error) 4%,
rgba(255, 255, 255, 0.96)
);
--settings-item-danger-border: color-mix(
in srgb,
var(--mat-sys-error) 14%,
transparent
);
--settings-action-bar-bg: color-mix(
in srgb,
var(--mat-sys-surface-container-low) 94%,
rgba(255, 255, 255, 0.9)
);
--settings-action-bar-border: color-mix(
in srgb,
var(--mat-sys-outline-variant) 62%,
transparent
);
--settings-action-bar-shadow: 0 10px 26px -26px rgba(15, 23, 42, 0.22);
--settings-muted: color-mix(
in srgb,
var(--mat-sys-on-surface) 64%,
transparent
);
}
:where(.dark-theme, [data-theme='dark'], .mat-app-background.dark)
.settings-container {
--settings-page-header-bg: color-mix(
in srgb,
var(--mat-sys-surface-container) 92%,
rgba(12, 16, 24, 0.94)
);
--settings-page-header-border: color-mix(
in srgb,
var(--mat-sys-outline-variant) 38%,
transparent
);
--settings-page-header-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.05),
0 16px 26px -34px rgba(0, 0, 0, 0.4);
--settings-group-bg: color-mix(
in srgb,
var(--mat-sys-surface-container) 94%,
rgba(10, 14, 22, 0.82)
);
--settings-group-border: rgba(255, 255, 255, 0.08);
--settings-group-shadow: 0 16px 28px -32px rgba(0, 0, 0, 0.42);
--settings-group-active-bg: color-mix(
in srgb,
var(--app-selection-surface) 24%,
rgba(255, 255, 255, 0.015)
);
--settings-group-active-ring: color-mix(
in srgb,
var(--app-selection-border) 54%,
rgba(255, 255, 255, 0.08)
);
--settings-group-active-glow: color-mix(
in srgb,
var(--app-selection-glow) 22%,
transparent
);
--settings-group-active-shadow:
inset 0 0 0 1px var(--settings-group-active-ring),
0 10px 22px -28px var(--settings-group-active-glow);
--settings-item-danger-bg: color-mix(
in srgb,
var(--mat-sys-error) 8%,
rgba(24, 10, 12, 0.86)
);
--settings-item-danger-border: color-mix(
in srgb,
var(--mat-sys-error) 24%,
transparent
);
--settings-action-bar-bg: color-mix(
in srgb,
var(--mat-sys-surface-container) 92%,
transparent
);
--settings-action-bar-border: rgba(255, 255, 255, 0.08);
--settings-action-bar-shadow: 0 8px 30px rgba(0, 0, 0, 0.18);
--settings-muted: color-mix(
in srgb,
var(--mat-sys-on-surface) 68%,
transparent
);
}
.settings-container {
.support-card {
width: 100%;
box-sizing: border-box;
position: relative;
display: flex;
flex-direction: column;
gap: 14px;
padding: 18px;
border-radius: 18px;
border: 1px solid color-mix(in srgb, #ff4d6d 26%, transparent);
background:
radial-gradient(
120% 140% at 0% 0%,
color-mix(in srgb, #ff4d6d 16%, transparent) 0%,
transparent 55%
),
radial-gradient(
120% 140% at 100% 100%,
color-mix(in srgb, #ffb347 14%, transparent) 0%,
transparent 60%
),
color-mix(
in srgb,
var(--mat-sys-surface-container-low) 92%,
transparent
);
overflow: hidden;
&::after {
content: '';
position: absolute;
inset: 0;
pointer-events: none;
background: radial-gradient(
80% 100% at 50% -10%,
color-mix(in srgb, #ff4d6d 12%, transparent) 0%,
transparent 70%
);
opacity: 0.8;
}
}
.support-card__intro {
position: relative;
display: flex;
align-items: flex-start;
gap: 14px;
z-index: 1;
}
.support-card__emblem {
flex: 0 0 auto;
display: inline-flex;
align-items: center;
justify-content: center;
width: 44px;
height: 44px;
border-radius: 14px;
background: linear-gradient(135deg, #ff4d6d, #ff8b5e);
color: #fff;
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.35),
0 10px 18px -10px rgba(255, 77, 109, 0.55);
mat-icon {
font-size: 22px;
width: 22px;
height: 22px;
}
}
.support-card__copy {
min-width: 0;
flex: 1 1 auto;
h4 {
margin: 0;
font-size: 1rem;
font-weight: 700;
letter-spacing: -0.01em;
}
p {
margin: 4px 0 0;
color: var(--settings-muted);
font-size: 0.86rem;
line-height: 1.5;
max-width: 64ch;
}
}
.support-card__actions {
position: relative;
z-index: 1;
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.support-btn {
flex: 1 1 220px;
display: inline-flex;
align-items: center;
gap: 12px;
padding: 10px 14px;
border-radius: 14px;
border: 1px solid transparent;
text-decoration: none;
color: #fff;
transition:
transform 0.18s ease,
box-shadow 0.18s ease,
filter 0.18s ease;
&:hover {
transform: translateY(-1px);
filter: brightness(1.04);
}
&:focus-visible {
outline: none;
box-shadow:
0 0 0 2px var(--mat-sys-surface),
0 0 0 4px
color-mix(
in srgb,
var(--app-selection-color) 40%,
transparent
);
}
}
.support-btn__glyph {
display: inline-flex;
align-items: center;
justify-content: center;
width: 34px;
height: 34px;
border-radius: 10px;
background: rgba(255, 255, 255, 0.18);
color: #fff;
flex: 0 0 auto;
svg {
width: 18px;
height: 18px;
}
mat-icon {
font-size: 18px;
width: 18px;
height: 18px;
}
}
.support-btn__text {
min-width: 0;
display: flex;
flex-direction: column;
gap: 2px;
strong {
font-size: 0.92rem;
font-weight: 700;
letter-spacing: -0.01em;
}
small {
color: rgba(255, 255, 255, 0.82);
font-size: 0.75rem;
line-height: 1.3;
}
}
.support-btn--sponsors {
background: linear-gradient(135deg, #d4337a, #ff4d6d);
box-shadow: 0 12px 22px -18px rgba(212, 51, 122, 0.7);
}
.support-btn--kofi {
background: linear-gradient(135deg, #13c3ff, #29abe0);
box-shadow: 0 12px 22px -18px rgba(19, 195, 255, 0.7);
}
}
+46
View File
@@ -0,0 +1,46 @@
import { registerLocaleData } from '@angular/common';
import localeAr from '@angular/common/locales/ar';
import localeArMa from '@angular/common/locales/ar-MA';
import localeBe from '@angular/common/locales/be';
import localeDe from '@angular/common/locales/de';
import localeEl from '@angular/common/locales/el';
import localeEs from '@angular/common/locales/es';
import localeFr from '@angular/common/locales/fr';
import localeIt from '@angular/common/locales/it';
import localeJa from '@angular/common/locales/ja';
import localeKo from '@angular/common/locales/ko';
import localeNl from '@angular/common/locales/nl';
import localePl from '@angular/common/locales/pl';
import localePt from '@angular/common/locales/pt';
import localeRu from '@angular/common/locales/ru';
import localeTr from '@angular/common/locales/tr';
import localeZh from '@angular/common/locales/zh';
import localeZhHant from '@angular/common/locales/zh-Hant';
let localesRegistered = false;
export function registerAppDateLocales(): void {
if (localesRegistered) {
return;
}
registerLocaleData(localeAr, 'ar');
registerLocaleData(localeArMa, 'ar-MA');
registerLocaleData(localeBe, 'be');
registerLocaleData(localeDe, 'de');
registerLocaleData(localeEl, 'el');
registerLocaleData(localeEs, 'es');
registerLocaleData(localeFr, 'fr');
registerLocaleData(localeIt, 'it');
registerLocaleData(localeJa, 'ja');
registerLocaleData(localeKo, 'ko');
registerLocaleData(localeNl, 'nl');
registerLocaleData(localePl, 'pl');
registerLocaleData(localePt, 'pt');
registerLocaleData(localeRu, 'ru');
registerLocaleData(localeTr, 'tr');
registerLocaleData(localeZh, 'zh');
registerLocaleData(localeZhHant, 'zh-Hant');
localesRegistered = true;
}
+3
View File
@@ -0,0 +1,3 @@
<router-outlet />
<app-epg-progress-panel />
+210
View File
@@ -0,0 +1,210 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Router } from '@angular/router';
import { Actions } from '@ngrx/effects';
import { MockStore, provideMockStore } from '@ngrx/store/testing';
import { TranslateService } from '@ngx-translate/core';
import { EpgService } from '@iptvnator/epg/data-access';
import { WORKSPACE_SHELL_ACTIONS } from '@iptvnator/workspace/shell/util';
import { MockProvider } from 'ng-mocks';
import { EMPTY, of } from 'rxjs';
import { DataService } from 'services';
import {
Language,
Settings,
StartupBehavior,
STORE_KEY,
StreamFormat,
Theme,
VideoPlayer,
} from 'shared-interfaces';
import { PlaylistActions } from 'm3u-state';
import { AppComponent } from './app.component';
import { ElectronServiceStub } from './services/electron.service.stub';
import { SettingsService } from './services/settings.service';
jest.spyOn(global.console, 'error').mockImplementation(() => {
// suppress console.error output during tests
});
class MockSettingsService {
getValueFromLocalStorage = jest.fn().mockReturnValue(of(undefined));
changeTheme = jest.fn();
}
const DEFAULT_SETTINGS: Settings = {
player: VideoPlayer.VideoJs,
epgUrl: [],
streamFormat: StreamFormat.M3u8StreamFormat,
language: Language.ENGLISH,
showCaptions: false,
showDashboard: true,
startupBehavior: StartupBehavior.FirstView,
showExternalPlaybackBar: true,
theme: Theme.SystemTheme,
mpvPlayerPath: '',
mpvReuseInstance: false,
vlcPlayerPath: '',
remoteControl: false,
remoteControlPort: 8765,
downloadFolder: '',
};
describe('AppComponent', () => {
let component: AppComponent;
let fixture: ComponentFixture<AppComponent>;
let epgService: EpgService;
let router: Router;
let settingsService: MockSettingsService;
let snackBar: MatSnackBar;
let store: MockStore;
let translateService: TranslateService;
const originalElectron = window.electron;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
imports: [AppComponent],
providers: [
provideMockStore(),
{
provide: Actions,
useValue: new Actions(EMPTY),
},
{
provide: DataService,
useClass: ElectronServiceStub,
},
{
provide: SettingsService,
useClass: MockSettingsService,
},
MockProvider(EpgService, {
fetchEpg: jest.fn(),
}),
MockProvider(Router, {
navigateByUrl: jest.fn(),
}),
MockProvider(MatSnackBar, {
open: jest.fn(),
}),
MockProvider(TranslateService, {
instant: jest.fn((key: string) => key),
setDefaultLang: jest.fn(),
use: jest.fn(),
}),
{
provide: WORKSPACE_SHELL_ACTIONS,
useValue: {
openAddPlaylistDialog: jest.fn(),
openGlobalRecent: jest.fn(),
openGlobalSearch: jest.fn(),
openAccountInfo: jest.fn(),
},
},
],
})
.overrideComponent(AppComponent, {
set: {
template: '',
},
})
.compileComponents();
}));
beforeEach(() => {
window.electron = {
checkEpgFreshness: jest.fn().mockResolvedValue({
freshUrls: [],
staleUrls: [],
}),
} as unknown as typeof window.electron;
fixture = TestBed.createComponent(AppComponent);
epgService = TestBed.inject(EpgService);
router = TestBed.inject(Router);
settingsService = TestBed.inject(
SettingsService
) as unknown as MockSettingsService;
snackBar = TestBed.inject(MatSnackBar);
store = TestBed.inject(MockStore);
translateService = TestBed.inject(TranslateService);
component = fixture.componentInstance;
});
afterEach(() => {
window.electron = originalElectron;
});
it('should create the component', () => {
expect(component).toBeTruthy();
});
it('should init component', () => {
const storeDispatchSpy = jest.spyOn(store, 'dispatch');
jest.spyOn(translateService, 'setDefaultLang');
jest.spyOn(component, 'initSettings');
component.ngOnInit();
expect(storeDispatchSpy).toHaveBeenCalledWith(
PlaylistActions.loadPlaylists()
);
expect(translateService.setDefaultLang).toHaveBeenCalledWith(
Language.ENGLISH
);
expect(component.initSettings).toHaveBeenCalledTimes(1);
});
it('should navigate to the provided route', () => {
const route = '/add-playlists';
jest.spyOn(router, 'navigateByUrl');
component.navigateToRoute(route);
expect(router.navigateByUrl).toHaveBeenCalledWith(route);
});
it('should apply system theme when no settings are stored', () => {
jest.spyOn(settingsService, 'changeTheme');
component.initSettings();
expect(settingsService.getValueFromLocalStorage).toHaveBeenCalledWith(
STORE_KEY.Settings
);
expect(settingsService.changeTheme).toHaveBeenCalledWith(
Theme.SystemTheme
);
});
it('should apply saved settings and fetch stale epg data only', async () => {
const settings: Settings = {
...DEFAULT_SETTINGS,
epgUrl: ['https://example.com/epg.xml'],
language: Language.SPANISH,
theme: Theme.DarkTheme,
};
const checkEpgFreshness = jest.fn().mockResolvedValue({
freshUrls: [],
staleUrls: settings.epgUrl,
});
window.electron = {
...window.electron,
checkEpgFreshness,
} as unknown as typeof window.electron;
settingsService.getValueFromLocalStorage.mockReturnValue(of(settings));
jest.spyOn(settingsService, 'changeTheme');
jest.spyOn(translateService, 'use');
component.initSettings();
await fixture.whenStable();
expect(translateService.use).toHaveBeenCalledWith(Language.SPANISH);
expect(settingsService.changeTheme).toHaveBeenCalledWith(
Theme.DarkTheme
);
expect(checkEpgFreshness).toHaveBeenCalledWith(settings.epgUrl, 12);
expect(epgService.fetchEpg).toHaveBeenCalledWith(settings.epgUrl);
expect(snackBar.open).not.toHaveBeenCalled();
});
});
+227
View File
@@ -0,0 +1,227 @@
import { Component, HostBinding, inject, OnInit } from '@angular/core';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Router, RouterOutlet } from '@angular/router';
import { Actions, ofType } from '@ngrx/effects';
import { Store } from '@ngrx/store';
import { TranslateService } from '@ngx-translate/core';
import { EpgService } from '@iptvnator/epg/data-access';
import { WORKSPACE_SHELL_ACTIONS } from '@iptvnator/workspace/shell/util';
import { EpgProgressPanelComponent } from '@iptvnator/ui/epg/progress-panel';
import { PlaylistActions, selectAllPlaylistsMeta } from 'm3u-state';
import { filter, take } from 'rxjs';
import { DataService } from 'services';
import { AppConfig } from '../environments/environment';
import {
AUTO_UPDATE_PLAYLISTS,
Language,
OPEN_FILE,
Settings,
STORE_KEY,
Theme,
} from 'shared-interfaces';
import { SettingsService } from './services/settings.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
imports: [EpgProgressPanelComponent, RouterOutlet],
})
export class AppComponent implements OnInit {
@HostBinding('class.macos-platform') get isMacOS() {
return (
window.electron && navigator.platform.toLowerCase().includes('mac')
);
}
private actions$ = inject(Actions);
private dataService = inject(DataService);
private epgService = inject(EpgService);
private snackBar = inject(MatSnackBar);
private router = inject(Router);
private store = inject(Store);
private translate = inject(TranslateService);
private settingsService = inject(SettingsService);
private readonly workspaceShellActions = inject(WORKSPACE_SHELL_ACTIONS);
private readonly defaultUiLang: Language =
AppConfig.product?.defaultLanguage ??
(AppConfig.defaultTranslateLang === 'es'
? Language.SPANISH
: Language.ENGLISH);
constructor() {
if (
((this.dataService.isElectron &&
this.dataService?.remote?.process.platform === 'linux') ||
this.dataService?.remote?.process.platform === 'win32') &&
this.dataService.remote.process.argv.length > 2
) {
const filePath = this.dataService.remote.process.argv.find(
(filepath) =>
filepath.endsWith('.m3u') || filepath.endsWith('.m3u8')
);
if (filePath) {
const filePathsArray = filePath.split('/');
const fileName = filePathsArray[filePathsArray.length - 1];
this.dataService.sendIpcEvent(OPEN_FILE, {
filePath,
fileName,
});
}
}
if (window.electron) {
document.addEventListener('keydown', (event) => {
if (event.ctrlKey || event.metaKey) {
if (event.key === 'f') {
event.preventDefault();
this.workspaceShellActions.openGlobalSearch();
} else if (event.key === 'r') {
event.preventDefault();
this.workspaceShellActions.openGlobalRecent();
}
}
});
}
if (AppConfig.product?.indexHtmlLang) {
document.documentElement.lang = AppConfig.product.indexHtmlLang;
}
if (AppConfig.product?.appDisplayName) {
document.title = AppConfig.product.appDisplayName;
}
}
ngOnInit() {
this.store.dispatch(PlaylistActions.loadPlaylists());
/** English is the translation fallback (see TranslateModule defaultLanguage / useDefaultLang). */
this.translate.setDefaultLang(Language.ENGLISH);
this.initSettings();
this.triggerAutoUpdatePlaylists();
}
/**
* Reads the settings object from local storage and initializes the
* application based on them
*/
initSettings(): void {
this.settingsService
.getValueFromLocalStorage(STORE_KEY.Settings)
.subscribe((settings: Settings) => {
if (settings && Object.keys(settings).length > 0) {
// No need to send settings to Electron on init
// Settings are stored in IndexedDB and loaded by the settings store
// Only specific Electron settings (MPV/VLC paths) are sent when changed in settings component
this.translate.use(
settings.language ?? this.defaultUiLang
);
// Fetch EPG if URLs are configured (only fetch stale data)
if (
window.electron &&
settings.epgUrl?.length > 0 &&
settings.epgUrl?.some((u) => u !== '')
) {
this.fetchStaleEpgData(settings.epgUrl);
}
if (settings.theme) {
this.settingsService.changeTheme(settings.theme);
} else {
this.detectDarkMode();
}
} else {
this.translate.use(this.defaultUiLang);
this.detectDarkMode();
}
});
}
/**
* Applies the operating system color scheme when no explicit theme is set
*/
detectDarkMode(): void {
this.settingsService.changeTheme(Theme.SystemTheme);
}
/**
* Navigate to the specified route
* @param route route to navigate to
*/
navigateToRoute(route: string) {
this.router.navigateByUrl(route);
}
/**
* Fetches EPG data only for URLs that have stale or missing data.
* Data is considered fresh if updated within the last 12 hours.
*/
private async fetchStaleEpgData(urls: string[]): Promise<void> {
try {
const result = await window.electron.checkEpgFreshness(urls, 12);
if (result.freshUrls.length > 0) {
console.log(
`EPG: ${result.freshUrls.length} source(s) already fresh, skipping fetch`
);
// Show snackbar if all EPG sources are fresh (no stale URLs)
if (result.staleUrls.length === 0) {
this.snackBar.open(
this.translate.instant('EPG.UP_TO_DATE'),
this.translate.instant('CLOSE'),
{ duration: 3000 }
);
}
}
if (result.staleUrls.length > 0) {
console.log(
`EPG: Fetching ${result.staleUrls.length} stale source(s)`
);
this.epgService.fetchEpg(result.staleUrls);
}
} catch (error) {
console.error('Error checking EPG freshness, fetching all:', error);
// Fallback: fetch all URLs if freshness check fails
this.epgService.fetchEpg(urls);
}
}
/**
* Triggers auto-update for playlists that have autoRefresh enabled
*/
private triggerAutoUpdatePlaylists(): void {
// Wait for playlists to be loaded successfully
this.actions$
.pipe(
ofType(PlaylistActions.loadPlaylistsSuccess),
take(1) // Only trigger once on app startup
)
.subscribe(() => {
// Get all playlists from store
this.store
.select(selectAllPlaylistsMeta)
.pipe(
take(1),
filter((playlists) => playlists.length > 0)
)
.subscribe((playlists) => {
// Filter playlists with autoRefresh enabled
const playlistsToUpdate = playlists.filter(
(playlist) => playlist.autoRefresh === true
);
// Trigger auto-update if there are playlists to update
if (playlistsToUpdate.length > 0) {
console.log(
`Auto-updating ${playlistsToUpdate.length} playlist(s) on startup`
);
this.dataService.sendIpcEvent(
AUTO_UPDATE_PLAYLISTS,
playlistsToUpdate
);
}
});
});
}
}
+133
View File
@@ -0,0 +1,133 @@
import {
HttpClient,
provideHttpClient,
withInterceptorsFromDi,
} from '@angular/common/http';
import {
ApplicationConfig,
importProvidersFrom,
provideZoneChangeDetection,
} from '@angular/core';
import { MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material/form-field';
import { provideAnimations } from '@angular/platform-browser/animations';
import { provideRouter, withComponentInputBinding } from '@angular/router';
import { provideServiceWorker } from '@angular/service-worker';
import { provideEffects } from '@ngrx/effects';
import { provideRouterStore, routerReducer } from '@ngrx/router-store';
import { provideStore } from '@ngrx/store';
import { provideStoreDevtools } from '@ngrx/store-devtools';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { PlaylistEffects, playlistReducer } from 'm3u-state';
import { NgxIndexedDBModule, NgxIndexedDBService } from 'ngx-indexed-db';
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
import {
PORTAL_EXTERNAL_PLAYBACK,
PORTAL_PLAYER,
} from '@iptvnator/portal/shared/util';
import { PLAYLIST_PLAYER_ACTIONS } from '@iptvnator/playlist/shared/util';
import { provideXtreamDataSource } from '@iptvnator/portal/xtream/data-access';
import { DataService, WORKSPACE_PRODUCT_BRANDING } from 'services';
import { dbConfig } from 'shared-interfaces';
import { AppConfig } from '../environments/environment';
import { routes } from './app.routes';
import { ElectronService } from './services/electron.service';
import { ExternalPlaybackService } from './services/external-playback.service';
import { PlayerService } from './services/player.service';
import {
AppPortalNavigationActionsService,
providePortalNavigationActions,
} from './services/portal-navigation-actions.service';
import { providePortalPlaybackPositions } from './services/portal-playback-positions.service';
import { PwaService } from './services/pwa.service';
import { provideWorkspaceShellActions } from './services/workspace-shell-actions.service';
// AoT requires an exported function for factories
export function HttpLoaderFactory(http: HttpClient): TranslateHttpLoader {
return new TranslateHttpLoader(http, './assets/i18n/', '.json');
}
/**
* Conditionally provides the necessary service based on the current environment
*/
export function DataFactory() {
if (window.electron) {
return new ElectronService();
}
return new PwaService();
}
export const appConfig: ApplicationConfig = {
providers: [
provideZoneChangeDetection({ eventCoalescing: true }),
provideRouter(routes, withComponentInputBinding()),
provideAnimations(),
provideHttpClient(withInterceptorsFromDi()),
provideStore({
router: routerReducer,
playlistState: playlistReducer,
}),
provideEffects([PlaylistEffects]),
provideRouterStore(),
provideStoreDevtools({
maxAge: 25,
logOnly: AppConfig.production,
}),
provideServiceWorker('ngsw-worker.js', {
enabled: AppConfig.production && !!window.electron,
registrationStrategy: 'registerWhenStable:30000',
}),
importProvidersFrom(
AppConfig.environment === 'WEB'
? NgxIndexedDBModule.forRoot(dbConfig)
: [],
NgxIndexedDBModule.forRoot(dbConfig),
NgxSkeletonLoaderModule.forRoot({
animation: 'pulse',
loadingText:
AppConfig.defaultTranslateLang === 'es'
? 'Cargando…'
: 'This item is actually loading...',
}),
TranslateModule.forRoot({
/** Fallback when the active locale file is missing a key (avoids raw keys like WORKSPACE.SHELL.*). */
defaultLanguage: 'en',
useDefaultLang: true,
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [HttpClient],
},
})
),
{
provide: DataService,
useFactory: DataFactory,
deps: [NgxIndexedDBService, HttpClient],
},
{
provide: PORTAL_PLAYER,
useExisting: PlayerService,
},
{
provide: PORTAL_EXTERNAL_PLAYBACK,
useExisting: ExternalPlaybackService,
},
...providePortalPlaybackPositions(),
...providePortalNavigationActions(),
{
provide: PLAYLIST_PLAYER_ACTIONS,
useExisting: AppPortalNavigationActionsService,
},
...provideWorkspaceShellActions(),
...provideXtreamDataSource(),
{
provide: MAT_FORM_FIELD_DEFAULT_OPTIONS,
useValue: { appearance: 'outline', subscriptSizing: 'dynamic' },
},
{
provide: WORKSPACE_PRODUCT_BRANDING,
useValue: AppConfig.product,
},
],
};
+73
View File
@@ -0,0 +1,73 @@
describe('app routes', () => {
let workspaceChildren: Array<{
canActivate?: unknown[];
data?: Record<string, unknown>;
loadComponent?: unknown;
path?: string;
redirectTo?: unknown;
}> = [];
beforeAll(async () => {
jest.resetModules();
jest.unstable_mockModule('@iptvnator/playlist/m3u/feature-player', () => ({
M3uCollectionRouteComponent: class {},
VideoPlayerComponent: class {},
provideM3uWorkspaceRouteSession: () => [],
}));
const { routes } = await import('./app.routes');
const workspaceRoute = routes.find((route) => route.path === 'workspace');
workspaceChildren = workspaceRoute?.children ?? [];
});
it('routes M3U favorites and recent pages through the shared collection wrapper', async () => {
const favoritesRoute = workspaceChildren.find(
(route) => route.path === 'playlists/:id/favorites'
);
const recentRoute = workspaceChildren.find(
(route) => route.path === 'playlists/:id/recent'
);
expect(favoritesRoute?.data).toEqual({
mode: 'favorites',
portalType: 'm3u',
defaultScope: 'playlist',
});
expect(recentRoute?.data).toEqual({
mode: 'recent',
portalType: 'm3u',
defaultScope: 'playlist',
});
expect(typeof favoritesRoute?.loadComponent).toBe('function');
expect(typeof recentRoute?.loadComponent).toBe('function');
});
it('adds a shared /workspace/global-recent route', async () => {
const globalRecentRoute = workspaceChildren.find(
(route) => route.path === 'global-recent'
);
expect(globalRecentRoute?.data).toEqual({
mode: 'recent',
defaultScope: 'all',
});
expect(typeof globalRecentRoute?.loadComponent).toBe('function');
});
it('uses a dynamic redirect for the default /workspace child route', async () => {
const workspaceDefaultRoute = workspaceChildren.find(
(route) => route.path === ''
);
expect(typeof workspaceDefaultRoute?.redirectTo).toBe('function');
});
it('protects the dashboard route behind a visibility guard', async () => {
const dashboardRoute = workspaceChildren.find(
(route) => route.path === 'dashboard'
);
expect(dashboardRoute?.canActivate).toHaveLength(1);
});
});
+155
View File
@@ -0,0 +1,155 @@
import { inject } from '@angular/core';
import { Router, Routes } from '@angular/router';
import { provideM3uWorkspaceRouteSession } from '@iptvnator/playlist/m3u/feature-player';
import { WorkspaceStartupPreferencesService } from '@iptvnator/workspace/shell/util';
const workspaceEntryRedirect = async () =>
inject(WorkspaceStartupPreferencesService).resolveInitialWorkspacePath();
const dashboardAccessGuard = async () => {
const startupPreferences = inject(WorkspaceStartupPreferencesService);
const router = inject(Router);
const redirectPath = await startupPreferences.resolveDashboardPath();
return redirectPath === '/workspace/dashboard'
? true
: router.parseUrl(redirectPath);
};
export const routes: Routes = [
{
path: '',
pathMatch: 'full',
redirectTo: 'workspace',
},
{
path: 'workspace',
data: {
layout: 'workspace',
},
loadComponent: () =>
import('@iptvnator/workspace/shell/feature').then(
(c) => c.WorkspaceShellComponent
),
children: [
{
path: '',
pathMatch: 'full',
redirectTo: workspaceEntryRedirect,
},
{
path: 'dashboard',
canActivate: [dashboardAccessGuard],
loadComponent: () =>
import('workspace-dashboard-feature').then(
(c) => c.WorkspaceDashboardRailsComponent
),
},
{
path: 'sources',
loadComponent: () =>
import('@iptvnator/workspace/shell/feature').then(
(c) => c.WorkspaceSourcesComponent
),
},
{
path: 'playlists/:id',
pathMatch: 'full',
redirectTo: 'playlists/:id/all',
},
{
path: 'playlists/:id/favorites',
providers: provideM3uWorkspaceRouteSession(),
loadComponent: () =>
import('@iptvnator/playlist/m3u/feature-player').then(
(c) => c.M3uCollectionRouteComponent
),
data: {
mode: 'favorites',
portalType: 'm3u',
defaultScope: 'playlist',
},
},
{
path: 'playlists/:id/recent',
providers: provideM3uWorkspaceRouteSession(),
loadComponent: () =>
import('@iptvnator/playlist/m3u/feature-player').then(
(c) => c.M3uCollectionRouteComponent
),
data: {
mode: 'recent',
portalType: 'm3u',
defaultScope: 'playlist',
},
},
{
path: 'playlists/:id/:view',
providers: provideM3uWorkspaceRouteSession(),
loadComponent: () =>
import('@iptvnator/playlist/m3u/feature-player').then(
(c) => c.VideoPlayerComponent
),
},
{
path: 'global-favorites',
data: {
mode: 'favorites',
defaultScope: 'all',
},
loadComponent: () =>
import('./global-collection-route.component').then(
(c) => c.GlobalCollectionRouteComponent
),
},
{
path: 'global-recent',
data: {
mode: 'recent',
defaultScope: 'all',
},
loadComponent: () =>
import('./global-collection-route.component').then(
(c) => c.GlobalCollectionRouteComponent
),
},
{
path: 'downloads',
loadComponent: () =>
import('@iptvnator/portal/downloads/feature').then(
(c) => c.DownloadsComponent
),
},
{
path: '',
loadChildren: () =>
import('@iptvnator/portal/xtream/feature').then((m) =>
m.createXtreamRoutes()
),
},
{
path: '',
loadChildren: () =>
import('@iptvnator/portal/stalker/feature').then((m) =>
m.createStalkerRoutes()
),
},
{
path: 'settings',
loadComponent: () =>
import('./settings/settings.component').then(
(c) => c.SettingsComponent
),
},
],
},
{
path: 'settings',
redirectTo: '/workspace/settings',
pathMatch: 'full',
},
{
path: '**',
redirectTo: '',
},
];
@@ -0,0 +1,122 @@
import {
ChangeDetectionStrategy,
Component,
computed,
inject,
input,
} from '@angular/core';
import { Router } from '@angular/router';
import { Store } from '@ngrx/store';
import { selectAllPlaylistsMeta } from 'm3u-state';
import { EmptyStateComponent } from '@iptvnator/playlist/shared/ui';
import { PlaylistContextFacade } from '@iptvnator/playlist/shared/util';
import {
UnifiedCollectionDetailDirective,
UnifiedCollectionPageComponent,
} from '@iptvnator/portal/shared/ui';
import { CollectionScope, PortalProvider } from '@iptvnator/portal/shared/util';
import { StalkerCollectionDetailComponent } from '@iptvnator/portal/stalker/feature';
import { XtreamCollectionDetailComponent } from '@iptvnator/portal/xtream/feature';
import { WORKSPACE_SHELL_ACTIONS } from '@iptvnator/workspace/shell/util';
type UnifiedPortalType = 'm3u' | 'xtream' | 'stalker';
type CollectionMode = 'favorites' | 'recent';
const EMPTY_STATE_BY_MODE: Record<
CollectionMode,
{ icon: string; titleKey: string; descriptionKey: string }
> = {
favorites: {
icon: 'favorite_border',
titleKey: 'WORKSPACE.GLOBAL_FAVORITES.NO_PLAYLISTS_TITLE',
descriptionKey: 'WORKSPACE.GLOBAL_FAVORITES.NO_PLAYLISTS_BODY',
},
recent: {
icon: 'history_toggle_off',
titleKey: 'WORKSPACE.GLOBAL_RECENT.NO_PLAYLISTS_TITLE',
descriptionKey: 'WORKSPACE.GLOBAL_RECENT.NO_PLAYLISTS_BODY',
},
};
function providerToPortalType(provider: PortalProvider): UnifiedPortalType {
if (provider === 'playlists') return 'm3u';
if (provider === 'xtreams') return 'xtream';
return 'stalker';
}
@Component({
selector: 'app-global-collection-route',
imports: [
EmptyStateComponent,
StalkerCollectionDetailComponent,
UnifiedCollectionDetailDirective,
UnifiedCollectionPageComponent,
XtreamCollectionDetailComponent,
],
template: `
@if (hasNoPlaylists()) {
<app-empty-state
type="no-data"
[icon]="emptyState().icon"
[titleKey]="emptyState().titleKey"
[descriptionKey]="emptyState().descriptionKey"
primaryActionLabelKey="HOME.PLAYLISTS.ADD_YOUR_FIRST"
secondaryActionLabelKey="WORKSPACE.SHELL.GO_TO_DASHBOARD"
(primaryActionClicked)="addPlaylist()"
(secondaryActionClicked)="goToDashboard()"
/>
} @else {
<app-unified-collection-page
[mode]="mode()"
[playlistId]="activePlaylistId() ?? undefined"
[portalType]="activePortalType() ?? undefined"
[defaultScope]="effectiveDefaultScope()"
>
<ng-template unifiedCollectionDetail let-item let-close="close">
@if (item.sourceType === 'xtream') {
<app-xtream-collection-detail [item]="item" />
} @else if (item.sourceType === 'stalker') {
<app-stalker-collection-detail
[item]="item"
(closeRequested)="close()"
/>
}
</ng-template>
</app-unified-collection-page>
}
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class GlobalCollectionRouteComponent {
private readonly playlistContext = inject(PlaylistContextFacade);
private readonly store = inject(Store);
private readonly shellActions = inject(WORKSPACE_SHELL_ACTIONS);
private readonly router = inject(Router);
readonly mode = input<CollectionMode>('favorites');
readonly defaultScope = input<CollectionScope | undefined>(undefined);
private readonly playlists = this.store.selectSignal(selectAllPlaylistsMeta);
readonly hasNoPlaylists = computed(() => this.playlists().length === 0);
readonly emptyState = computed(() => EMPTY_STATE_BY_MODE[this.mode()]);
readonly activePlaylistId = computed(
() => this.playlistContext.activePlaylist()?._id ?? null
);
readonly activePortalType = computed<UnifiedPortalType | null>(() => {
const provider = this.playlistContext.activeProvider();
return provider ? providerToPortalType(provider) : null;
});
readonly effectiveDefaultScope = computed<CollectionScope | undefined>(() =>
this.activePlaylistId() ? 'playlist' : (this.defaultScope() ?? 'all')
);
addPlaylist(): void {
this.shellActions.openAddPlaylistDialog();
}
goToDashboard(): void {
void this.router.navigate(['/workspace', 'dashboard']);
}
}
@@ -0,0 +1,5 @@
export {
DownloadsService,
type DownloadItem,
type DownloadStatus,
} from 'services';
@@ -0,0 +1,46 @@
export class ElectronServiceStub {
ipcRenderer = {
send: jest.fn(),
on: jest.fn(),
removeAllListeners: jest.fn(),
};
remote = {
process: {
platform: 'linux',
argv: [0, 1],
},
app: {
getVersion: jest.fn(() => '1.0.0'),
},
};
isElectron = true;
removeAllListeners(_type: string): void {
void _type;
return undefined;
}
getAppVersion() {
return this.remote.app.getVersion();
}
sendIpcEvent<T = unknown>(_type: string, _payload?: unknown): T {
void _type;
void _payload;
return undefined as T;
}
listenOn(
_command: string,
_callback: (...args: unknown[]) => void
): void {
void _command;
void _callback;
return undefined;
}
getAppEnvironment() {
return 'electron';
}
}
@@ -0,0 +1,585 @@
import { inject, Injectable } from '@angular/core';
import { MatSnackBar } from '@angular/material/snack-bar';
import { Store } from '@ngrx/store';
import { TranslateService } from '@ngx-translate/core';
import { PlaylistActions } from 'm3u-state';
import { DataService } from 'services';
import {
AUTO_UPDATE_PLAYLISTS,
ERROR,
Playlist,
PLAYLIST_PARSE_BY_URL,
PLAYLIST_UPDATE,
XTREAM_REQUEST,
XTREAM_RESPONSE,
XtreamCodeActions,
} from 'shared-interfaces';
import { AppConfig } from '../../environments/environment';
import {
createPortalDebugRequestContext,
logPortalDebugEvent,
} from '@iptvnator/portal/shared/util';
interface PlayerLaunchPayload {
readonly headers?: Record<string, string>;
readonly origin?: string;
readonly referer?: string;
readonly startTime?: number;
readonly thumbnail?: string;
readonly title?: string;
readonly url: string;
readonly ['user-agent']?: string;
readonly contentInfo?: unknown;
}
interface ErrorStatus {
readonly message?: string;
readonly status?: number;
}
@Injectable({
providedIn: 'root',
})
export class ElectronService extends DataService {
private eventListeners: { [key: string]: () => void } = {};
private readonly snackBar = inject(MatSnackBar);
private readonly store = inject(Store);
private readonly translateService = inject(TranslateService);
private readonly silentXtreamActions = new Set<string>([
XtreamCodeActions.GetAccountInfo,
XtreamCodeActions.GetLiveCategories,
XtreamCodeActions.GetVodCategories,
XtreamCodeActions.GetSeriesCategories,
XtreamCodeActions.GetShortEpg,
XtreamCodeActions.GetSimpleDataTable,
XtreamCodeActions.GetSimpleDateTable,
]);
constructor() {
super();
console.log('Electron service initialized...');
this.setupPlayerErrorListener();
this.setupPortalDebugListener();
}
private setupPlayerErrorListener() {
// Listen for player errors from the backend
if (window.electron?.onPlayerError) {
window.electron.onPlayerError(
(data: {
player: string;
error: string;
originalError: string;
}) => {
console.error(`${data.player} Error:`, data.originalError);
this.snackBar.open(
`${data.player} Error: ${data.error}`,
'Close',
{
duration: 7000,
panelClass: ['error-snackbar'],
}
);
}
);
}
}
private setupPortalDebugListener() {
const onPortalDebugEvent = (
window.electron as {
onPortalDebugEvent?: (
callback: (
event: Parameters<typeof logPortalDebugEvent>[0]
) => void
) => void;
}
).onPortalDebugEvent;
if (AppConfig.production || !onPortalDebugEvent) {
return;
}
onPortalDebugEvent((event) => {
logPortalDebugEvent(
event as Parameters<typeof logPortalDebugEvent>[0]
);
});
}
getAppVersion(): string {
return AppConfig.version;
}
async sendIpcEvent<T = unknown>(
type: string,
payload?: unknown
): Promise<T> {
if (type === PLAYLIST_PARSE_BY_URL) {
this.fetchM3uPlaylistFromUrl(payload);
return undefined as T;
}
if (type === PLAYLIST_UPDATE) {
this.updateM3uPlaylistFromFile(
payload as {
id: string;
filePath?: string;
url?: string;
title: string;
}
);
return undefined as T;
}
if (type === XTREAM_REQUEST) {
return (await this.forwardXtreamRequest(
payload as { url: string; params: Record<string, string> }
)) as T;
}
if (type === 'STALKER_REQUEST') {
return (await this.fetchStalkerData(
payload as {
url: string;
macAddress: string;
params: Record<string, string>;
}
)) as T;
}
if (type === 'OPEN_MPV_PLAYER') {
const data = payload as PlayerLaunchPayload;
try {
return (await window.electron.openInMpv(
data.url,
data.title ?? '',
data.thumbnail ?? '',
data['user-agent'] ?? undefined,
data.referer ?? undefined,
data.origin ?? undefined,
data.contentInfo,
data.startTime,
data.headers ?? undefined
)) as T;
} catch (error: unknown) {
const errorMessage =
this.getErrorDetails(error)?.message ?? String(error);
this.snackBar.open(
`Error launching MPV: ${errorMessage}`,
'Close',
{
duration: 5000,
}
);
console.error('MPV launch error:', error);
throw error;
}
}
if (type === 'OPEN_VLC_PLAYER') {
const data = payload as PlayerLaunchPayload;
try {
return (await window.electron.openInVlc(
data.url,
data.title ?? '',
data.thumbnail ?? '',
data['user-agent'] ?? undefined,
data.referer ?? undefined,
data.origin ?? undefined,
data.contentInfo,
data.startTime,
data.headers ?? undefined
)) as T;
} catch (error: unknown) {
const errorMessage =
this.getErrorDetails(error)?.message ?? String(error);
this.snackBar.open(
`Error launching VLC: ${errorMessage}`,
'Close',
{
duration: 5000,
}
);
console.error('VLC launch error:', error);
throw error;
}
}
if (type === AUTO_UPDATE_PLAYLISTS) {
const data = payload as Playlist[];
const playlists = await window.electron.autoUpdatePlaylists(data);
this.store.dispatch(
PlaylistActions.updateManyPlaylists({
playlists,
})
);
this.snackBar.open(
this.translateService.instant(
'HOME.PLAYLISTS.AUTO_REFRESH_UPDATE_SUCCESS'
),
null,
{ duration: 2000 }
);
return playlists as T;
}
console.log('Unknown type', type);
return undefined as T;
}
private async fetchStalkerData(payload: {
url: string;
macAddress: string;
params: Record<string, string>;
requestId?: string;
token?: string;
serialNumber?: string;
}) {
const context = createPortalDebugRequestContext({
provider: 'stalker',
operation: payload.params?.action ?? 'unknown',
transport: 'electron-renderer',
request: payload,
});
try {
// Use Electron IPC to make the Stalker request
const response = await window.electron.stalkerRequest({
...payload,
requestId: context.requestId,
});
return response;
} catch (err: unknown) {
const errorInfo = this.getErrorDetails(err);
console.error('Stalker request error:', err);
this.snackBar.open(
`Error: ${errorInfo?.message ?? ' Not found'}, status: ${errorInfo?.status ?? 404}`,
'Close',
{
duration: 5000,
}
);
throw err;
}
}
private async fetchM3uPlaylistFromUrl(payload: Partial<Playlist>) {
const title = payload.title?.trim() || undefined;
window.electron
.fetchPlaylistByUrl(payload.url, title)
.then((result) => {
this.store.dispatch(
PlaylistActions.handleAddingPlaylistByUrl({
isTemporary: !!payload?.isTemporary,
playlist: result,
})
);
})
.catch((error: unknown) => {
const statusCode = this.extractHttpStatusCode(error);
let messageKey = 'HOME.URL_UPLOAD.ERROR_FETCH_FAILED';
if (statusCode === 403) {
messageKey = 'HOME.URL_UPLOAD.ERROR_403';
} else if (statusCode === 404) {
messageKey = 'HOME.URL_UPLOAD.ERROR_404';
} else if (statusCode === 401) {
messageKey = 'HOME.URL_UPLOAD.ERROR_401';
}
this.snackBar.open(
this.translateService.instant(messageKey),
this.translateService.instant('CLOSE'),
{ duration: 5000 }
);
});
}
private extractHttpStatusCode(error: unknown): number | null {
if (
error &&
typeof error === 'object' &&
'response' in error &&
error.response &&
typeof error.response === 'object' &&
'status' in error.response
) {
return error.response.status as number;
}
// Parse status from error message string (IPC serialization)
const msg = String((error as { message?: string })?.message ?? error);
const match = msg.match(/status code (\d{3})/);
return match ? parseInt(match[1], 10) : null;
}
private async updateM3uPlaylistFromFile(data: {
id: string;
url?: string;
filePath?: string;
title: string;
}) {
try {
let playlistObject: Playlist;
if (data.url && !data.filePath) {
playlistObject = await window.electron.fetchPlaylistByUrl(
data.url,
data.title
);
} else if (data.filePath && !data.url) {
playlistObject =
await window.electron.updatePlaylistFromFilePath(
data.filePath,
data.title
);
} else {
console.error(
'Either url or filePath must be provided, but not both.'
);
return;
}
this.store.dispatch(
PlaylistActions.updatePlaylist({
playlist: {
...playlistObject,
_id: data.id,
},
playlistId: data.id,
})
);
this.snackBar.open(
this.translateService.instant(
'HOME.PLAYLISTS.PLAYLIST_UPDATE_SUCCESS'
),
null,
{ duration: 2000 }
);
} catch (error: unknown) {
console.error('Playlist refresh error:', error);
this.snackBar.open(
this.getPlaylistRefreshErrorMessage(error, data),
this.translateService.instant('CLOSE'),
{ duration: 5000 }
);
}
}
private getPlaylistRefreshErrorMessage(
error: unknown,
data: { url?: string; filePath?: string }
): string {
if (data.filePath) {
const errorMessage = String(
this.getErrorDetails(error)?.message ?? error ?? ''
);
if (
/(ENOENT|no such file or directory|not found)/i.test(
errorMessage
)
) {
return this.translateWithFallback(
'HOME.PLAYLISTS.PLAYLIST_UPDATE_FILE_NOT_FOUND',
'Playlist refresh failed. The local file is no longer available. Check the file path or re-import the playlist.'
);
}
if (/(EACCES|EPERM|permission denied)/i.test(errorMessage)) {
return this.translateWithFallback(
'HOME.PLAYLISTS.PLAYLIST_UPDATE_FILE_ACCESS_ERROR',
'Playlist refresh failed. The app can no longer access the local file.'
);
}
return this.translateService.instant(
'HOME.PLAYLISTS.PLAYLIST_UPDATE_ERROR'
);
}
const statusCode = this.extractHttpStatusCode(error);
if (statusCode === 404) {
return this.translateService.instant('HOME.URL_UPLOAD.ERROR_404');
}
if (statusCode === 403) {
return this.translateService.instant('HOME.URL_UPLOAD.ERROR_403');
}
if (statusCode === 401) {
return this.translateService.instant('HOME.URL_UPLOAD.ERROR_401');
}
return this.translateService.instant(
'HOME.URL_UPLOAD.ERROR_FETCH_FAILED'
);
}
private translateWithFallback(key: string, fallback: string): string {
const translated = this.translateService.instant(key);
return translated === key ? fallback : translated;
}
/* private getErrorMessageByStatusCode(status: number) {
let message = 'Something went wrong';
switch (status) {
case 0:
message = 'The backend is not reachable';
break;
case 413:
message =
'This file is too big. Use standalone or self-hosted version of the app.';
break;
default:
break;
}
return message;
} */
private async forwardXtreamRequest(payload: {
url: string;
params: Record<string, string>;
requestId?: string;
sessionId?: string;
suppressErrorLog?: boolean;
}) {
const context = createPortalDebugRequestContext({
provider: 'xtream',
operation: payload.params?.action ?? 'unknown',
transport: 'electron-renderer',
request: payload,
});
try {
// Use Electron IPC to make the Xtream request
const response = await window.electron.xtreamRequest({
...payload,
requestId: context.requestId,
});
const result = {
type: XTREAM_RESPONSE,
payload: response.payload,
action: response.action,
};
window.postMessage(result);
return result;
} catch (error: unknown) {
const action = payload.params?.action;
const isSilentAction =
payload.suppressErrorLog === true ||
(action ? this.silentXtreamActions.has(action) : false);
const normalizedMessage = this.getReadableXtreamErrorMessage(error);
const errorInfo = this.getErrorDetails(error);
// Log error to console
if (isSilentAction) {
console.log(
`Background Xtream action failed (${action ?? 'unknown'}):`,
normalizedMessage
);
} else {
console.error('Xtream request error:', normalizedMessage);
}
// Only show snackbar for user-triggered Xtream requests
if (!isSilentAction) {
this.snackBar.open(
`Xtream request failed: ${normalizedMessage}`,
'Close',
{
duration: 5000,
}
);
}
return {
type: ERROR,
status: errorInfo?.status ?? 500,
message: normalizedMessage,
};
}
}
private getReadableXtreamErrorMessage(error: unknown): string {
const fallback = 'Failed to connect to Xtream server';
if (!error) {
return fallback;
}
const maybeError = error as {
message?: unknown;
statusText?: unknown;
status?: unknown;
error?: unknown;
};
if (typeof maybeError.message === 'string') {
if (maybeError.message.includes('[object Object]')) {
if (typeof maybeError.error === 'string') {
return maybeError.error;
}
if (
maybeError.error &&
typeof maybeError.error === 'object' &&
'message' in
(maybeError.error as Record<string, unknown>) &&
typeof (maybeError.error as Record<string, unknown>)
.message === 'string'
) {
return (maybeError.error as Record<string, string>).message;
}
return fallback;
}
return maybeError.message;
}
if (typeof maybeError.statusText === 'string') {
return maybeError.statusText;
}
if (typeof error === 'string') {
return error;
}
return fallback;
}
private getErrorDetails(error: unknown): ErrorStatus | null {
if (error && typeof error === 'object') {
return error as ErrorStatus;
}
return null;
}
removeAllListeners(type: string): void {
if (type === 'all') {
// Unsubscribe from all event listeners
Object.values(this.eventListeners).forEach((unsubscribe) =>
unsubscribe()
);
this.eventListeners = {};
} else if (this.eventListeners[type]) {
// Unsubscribe from a specific event
this.eventListeners[type]();
delete this.eventListeners[type];
}
// Also remove any window message listeners
window.removeEventListener('message', this.getListenerForCommand(type));
}
private getListenerForCommand(_command: string): EventListener {
void _command;
// This is a placeholder. In a real implementation, you would need to
// store the actual listener functions to be able to remove them
return () => undefined;
}
listenOn(command: string, callback: (...args: unknown[]) => void): void {
// For Electron, use window message events
void command;
window.addEventListener('message', callback);
}
getAppEnvironment(): string {
return 'electron';
}
}
@@ -0,0 +1,150 @@
import { ExternalPlayerSession } from 'shared-interfaces';
import { ExternalPlaybackService } from './external-playback.service';
describe('ExternalPlaybackService', () => {
let listener:
| ((session: ExternalPlayerSession) => void)
| undefined;
let closeExternalPlayerSession: jest.Mock;
let service: ExternalPlaybackService;
const createSession = (
overrides: Partial<ExternalPlayerSession> = {}
): ExternalPlayerSession => ({
id: 'session-1',
player: 'mpv',
status: 'launching',
title: 'Example',
streamUrl: 'https://example.com/video.m3u8',
contentInfo: {
playlistId: 'playlist-1',
contentXtreamId: 42,
contentType: 'vod',
},
startedAt: '2026-03-07T10:00:00.000Z',
updatedAt: '2026-03-07T10:00:00.000Z',
canClose: true,
...overrides,
});
beforeEach(() => {
listener = undefined;
closeExternalPlayerSession = jest.fn().mockResolvedValue(null);
Object.defineProperty(window, 'electron', {
configurable: true,
value: {
onExternalPlayerSessionUpdate: jest.fn((callback) => {
listener = callback;
return () => undefined;
}),
closeExternalPlayerSession,
},
});
service = new ExternalPlaybackService();
});
it('tracks the latest launch and hides dismissed sessions until the next launch', () => {
const first = createSession();
listener?.(first);
expect(service.activeSession()).toEqual(first);
expect(service.visibleSession()).toEqual(first);
service.dismissActiveSession();
expect(service.visibleSession()).toBeNull();
const next = createSession({
id: 'session-2',
title: 'Another Example',
});
listener?.(next);
expect(service.visibleSession()).toEqual(next);
});
it('matches only active non-error sessions to content info', () => {
const playing = createSession({
status: 'playing',
updatedAt: '2026-03-07T10:00:05.000Z',
});
listener?.(playing);
expect(
service.findMatchingSession({
playlistId: 'playlist-1',
contentXtreamId: 42,
contentType: 'vod',
})
).toEqual(playing);
listener?.(
createSession({
status: 'error',
error: 'Launch failed',
updatedAt: '2026-03-07T10:00:06.000Z',
})
);
expect(
service.findMatchingSession({
playlistId: 'playlist-1',
contentXtreamId: 42,
contentType: 'vod',
})
).toBeNull();
expect(service.visibleSession()).toBeNull();
});
it('delegates close requests for closable sessions', async () => {
const session = createSession({ status: 'opened' });
listener?.(session);
closeExternalPlayerSession.mockResolvedValue(
createSession({
...session,
status: 'closed',
canClose: false,
updatedAt: '2026-03-07T10:00:10.000Z',
})
);
await service.closeActiveSession();
expect(closeExternalPlayerSession).toHaveBeenCalledWith(session.id);
expect(service.visibleSession()).toBeNull();
});
it('can close a specific session directly', async () => {
const session = createSession({ id: 'session-2', status: 'playing' });
closeExternalPlayerSession.mockResolvedValue(
createSession({
...session,
status: 'closed',
canClose: false,
updatedAt: '2026-03-07T10:00:12.000Z',
})
);
await service.closeSession(session);
expect(closeExternalPlayerSession).toHaveBeenCalledWith('session-2');
});
it('hides terminal sessions from the dock', () => {
listener?.(createSession({ status: 'closed', canClose: false }));
expect(service.visibleSession()).toBeNull();
listener?.(
createSession({
id: 'session-3',
status: 'error',
error: 'Launch failed',
canClose: false,
})
);
expect(service.visibleSession()).toBeNull();
});
});
@@ -0,0 +1,128 @@
import { computed, Injectable, signal } from '@angular/core';
import { ExternalPlayerSession, PlayerContentInfo } from 'shared-interfaces';
@Injectable({
providedIn: 'root',
})
export class ExternalPlaybackService {
readonly activeSession = signal<ExternalPlayerSession | null>(null);
private readonly dismissedSessionId = signal<string | null>(null);
readonly visibleSession = computed(() => {
const session = this.activeSession();
if (
!session ||
session.status === 'closed' ||
session.status === 'error'
) {
return null;
}
if (this.dismissedSessionId() === session.id) {
return null;
}
return session;
});
constructor() {
window.electron?.onExternalPlayerSessionUpdate?.((session) => {
this.handleSessionUpdate(session);
});
}
dismissActiveSession(): void {
const session = this.activeSession();
if (!session) {
return;
}
this.dismissedSessionId.set(session.id);
}
async closeActiveSession(): Promise<void> {
await this.closeSession(this.activeSession());
}
async closeSession(
session: ExternalPlayerSession | null | undefined
): Promise<void> {
if (!session) {
return;
}
if (!session.canClose || !window.electron?.closeExternalPlayerSession) {
this.dismissedSessionId.set(session.id);
return;
}
const previousDismissedSessionId = this.dismissedSessionId();
this.dismissedSessionId.set(session.id);
try {
const updatedSession = await window.electron.closeExternalPlayerSession(
session.id
);
if (updatedSession) {
this.handleSessionUpdate(updatedSession);
return;
}
this.activeSession.update((current) =>
current?.id === session.id
? {
...current,
status: 'closed',
canClose: false,
updatedAt: new Date().toISOString(),
}
: current
);
} catch (error) {
if (this.dismissedSessionId() === session.id) {
this.dismissedSessionId.set(previousDismissedSessionId);
}
throw error;
}
}
findMatchingSession(
contentInfo: PlayerContentInfo | null | undefined
): ExternalPlayerSession | null {
const session = this.activeSession();
if (!contentInfo || !session?.contentInfo) {
return null;
}
if (session.status === 'error' || session.status === 'closed') {
return null;
}
return this.matchesContent(contentInfo, session.contentInfo)
? session
: null;
}
private handleSessionUpdate(session: ExternalPlayerSession): void {
const current = this.activeSession();
if (!current || current.id === session.id || session.status === 'launching') {
this.activeSession.set(session);
}
if (session.status === 'launching') {
this.dismissedSessionId.set(null);
}
}
private matchesContent(
left: PlayerContentInfo,
right: PlayerContentInfo
): boolean {
return (
left.playlistId === right.playlistId &&
left.contentType === right.contentType &&
left.contentXtreamId === right.contentXtreamId
);
}
}
@@ -0,0 +1,92 @@
import { TestBed } from '@angular/core/testing';
import { MatDialog } from '@angular/material/dialog';
import { DataService } from 'services';
import { ExternalPlayerSession, VideoPlayer } from 'shared-interfaces';
import { SettingsStore } from './settings-store.service';
import { PlayerService } from './player.service';
describe('PlayerService', () => {
let service: PlayerService;
const dialog = {
open: jest.fn(),
};
const dataService = {
sendIpcEvent: jest.fn(),
};
const settingsStore = {
player: jest.fn(() => VideoPlayer.VideoJs),
};
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
PlayerService,
{
provide: MatDialog,
useValue: dialog,
},
{
provide: DataService,
useValue: dataService,
},
{
provide: SettingsStore,
useValue: settingsStore,
},
],
});
service = TestBed.inject(PlayerService);
dialog.open.mockReset();
dataService.sendIpcEvent.mockReset();
settingsStore.player.mockReset();
settingsStore.player.mockReturnValue(VideoPlayer.VideoJs);
});
it('identifies embedded players', () => {
expect(service.isEmbeddedPlayer(VideoPlayer.VideoJs)).toBe(true);
expect(service.isEmbeddedPlayer(VideoPlayer.Html5Player)).toBe(true);
expect(service.isEmbeddedPlayer(VideoPlayer.ArtPlayer)).toBe(true);
expect(service.isEmbeddedPlayer(VideoPlayer.MPV)).toBe(false);
expect(service.isEmbeddedPlayer(VideoPlayer.VLC)).toBe(false);
});
it('uses the dialog fallback for embedded players', async () => {
await service.openResolvedPlayback({
streamUrl: 'https://example.com/video.mp4',
title: 'Example Video',
});
expect(dialog.open).toHaveBeenCalled();
expect(dataService.sendIpcEvent).not.toHaveBeenCalled();
});
it('forwards external playback launches through IPC', async () => {
const session: ExternalPlayerSession = {
id: 'session-1',
player: 'mpv',
status: 'opened',
title: 'Example Video',
streamUrl: 'https://example.com/video.mp4',
startedAt: '2026-03-07T10:00:00.000Z',
updatedAt: '2026-03-07T10:00:00.000Z',
canClose: true,
};
settingsStore.player.mockReturnValue(VideoPlayer.MPV);
dataService.sendIpcEvent.mockResolvedValue(session);
const result = await service.openResolvedPlayback({
streamUrl: 'https://example.com/video.mp4',
title: 'Example Video',
});
expect(dataService.sendIpcEvent).toHaveBeenCalledWith(
'OPEN_MPV_PLAYER',
expect.objectContaining({
url: 'https://example.com/video.mp4',
title: 'Example Video',
})
);
expect(result).toEqual(session);
});
});
+129
View File
@@ -0,0 +1,129 @@
import { Injectable, inject } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { ExternalPlayerInfoDialogComponent } from '@iptvnator/ui/playback/external-player-info-dialog';
import { DataService } from 'services';
import {
ExternalPlayerSession,
OPEN_MPV_PLAYER,
OPEN_VLC_PLAYER,
PlayerContentInfo,
ResolvedPortalPlayback,
VideoPlayer,
} from 'shared-interfaces';
import { SettingsStore } from './settings-store.service';
@Injectable({
providedIn: 'root',
})
export class PlayerService {
private dialog = inject(MatDialog);
private dataService = inject(DataService);
private settingsStore = inject(SettingsStore);
isEmbeddedPlayer(
player = this.settingsStore.player() ?? VideoPlayer.VideoJs
): boolean {
return (
player === VideoPlayer.VideoJs ||
player === VideoPlayer.Html5Player ||
player === VideoPlayer.ArtPlayer
);
}
openPlayer(
streamUrl: string,
title: string,
thumbnail?: string,
hideExternalInfoDialog = true,
_isLiveContent = false,
userAgent?: string,
referer?: string,
origin?: string,
contentInfo?: PlayerContentInfo,
startTime?: number,
headers?: Record<string, string>
): Promise<ExternalPlayerSession | void> {
void _isLiveContent;
return this.openResolvedPlayback(
{
streamUrl,
title,
thumbnail,
startTime,
contentInfo,
headers,
userAgent,
referer,
origin,
},
hideExternalInfoDialog
);
}
async openResolvedPlayback(
playback: ResolvedPortalPlayback,
hideExternalInfoDialog = true
): Promise<ExternalPlayerSession | void> {
const player = this.settingsStore.player() ?? VideoPlayer.VideoJs;
const {
streamUrl,
title,
thumbnail,
userAgent,
referer,
origin,
headers,
contentInfo,
startTime,
} = playback;
if (player === VideoPlayer.MPV) {
if (!hideExternalInfoDialog) {
this.dialog.open(ExternalPlayerInfoDialogComponent);
}
return await this.dataService.sendIpcEvent<ExternalPlayerSession>(
OPEN_MPV_PLAYER,
{
url: streamUrl,
title,
thumbnail,
'user-agent': userAgent,
referer: referer,
origin: origin,
headers,
contentInfo,
startTime,
}
);
} else if (player === VideoPlayer.VLC) {
if (!hideExternalInfoDialog) {
this.dialog.open(ExternalPlayerInfoDialogComponent);
}
return await this.dataService.sendIpcEvent<ExternalPlayerSession>(
OPEN_VLC_PLAYER,
{
url: streamUrl,
title,
thumbnail,
'user-agent': userAgent,
referer: referer,
origin: origin,
headers,
contentInfo,
startTime,
}
);
}
return import('@iptvnator/portal/xtream/feature').then(
({ PlayerDialogComponent }) => {
this.dialog.open(PlayerDialogComponent, {
data: { streamUrl, title, contentInfo, startTime },
width: '80%',
maxWidth: '1200px',
maxHeight: '90vh',
});
}
);
}
}
@@ -0,0 +1,64 @@
import { inject, Injectable, Provider } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { PlaylistInfoComponent } from '@iptvnator/playlist/shared/ui';
import {
PORTAL_NAVIGATION_ACTIONS,
PortalNavigationActions,
} from '@iptvnator/portal/shared/util';
import { XtreamStore } from '@iptvnator/portal/xtream/data-access';
import { Playlist } from 'shared-interfaces';
import { SettingsComponent } from '../settings/settings.component';
@Injectable({ providedIn: 'root' })
export class AppPortalNavigationActionsService
implements PortalNavigationActions
{
private readonly dialog = inject(MatDialog);
private readonly xtreamStore = inject(XtreamStore);
openAccountInfo(): void {
const data = {
vodStreamsCount: this.xtreamStore.vodStreams().length,
liveStreamsCount: this.xtreamStore.liveStreams().length,
seriesCount: this.xtreamStore.serialStreams().length,
};
void import('@iptvnator/portal/xtream/feature').then(
({ AccountInfoComponent }) => {
this.dialog.open(AccountInfoComponent, {
width: '80%',
maxWidth: '1200px',
maxHeight: '90vh',
data,
});
}
);
}
openPlaylistInfo(playlist: Playlist | null | undefined): void {
this.dialog.open(PlaylistInfoComponent, {
data: playlist ?? null,
});
}
openSettings(): void {
this.dialog.open(SettingsComponent, {
width: '1200px',
maxWidth: '96vw',
maxHeight: '92vh',
data: {
isDialog: true,
},
});
}
}
export function providePortalNavigationActions(): Provider[] {
return [
AppPortalNavigationActionsService,
{
provide: PORTAL_NAVIGATION_ACTIONS,
useExisting: AppPortalNavigationActionsService,
},
];
}
@@ -0,0 +1,72 @@
import { Injectable, inject } from '@angular/core';
import {
PORTAL_PLAYBACK_POSITIONS,
PortalPlaybackPositions,
} from '@iptvnator/portal/shared/util';
import {
PlaybackPositionData,
XTREAM_DATA_SOURCE,
} from '@iptvnator/portal/xtream/data-access';
@Injectable({
providedIn: 'root',
})
export class AppPortalPlaybackPositionsService
implements PortalPlaybackPositions
{
private readonly dataSource = inject(XTREAM_DATA_SOURCE);
async savePlaybackPosition(
playlistId: string,
data: PlaybackPositionData
): Promise<void> {
await this.dataSource.savePlaybackPosition(playlistId, data);
}
async getPlaybackPosition(
playlistId: string,
contentXtreamId: number,
contentType: 'vod' | 'episode'
): Promise<PlaybackPositionData | null> {
return this.dataSource.getPlaybackPosition(
playlistId,
contentXtreamId,
contentType
);
}
async getSeriesPlaybackPositions(
playlistId: string,
seriesXtreamId: number
): Promise<PlaybackPositionData[]> {
return this.dataSource.getSeriesPlaybackPositions(
playlistId,
seriesXtreamId
);
}
async getAllPlaybackPositions(
playlistId: string
): Promise<PlaybackPositionData[]> {
return this.dataSource.getAllPlaybackPositions(playlistId);
}
async clearPlaybackPosition(
playlistId: string,
contentXtreamId: number,
contentType: 'vod' | 'episode'
): Promise<void> {
await this.dataSource.clearPlaybackPosition(
playlistId,
contentXtreamId,
contentType
);
}
}
export const providePortalPlaybackPositions = () => [
{
provide: PORTAL_PLAYBACK_POSITIONS,
useExisting: AppPortalPlaybackPositionsService,
},
];
+514
View File
@@ -0,0 +1,514 @@
import { HttpClient } from '@angular/common/http';
import { inject, Injectable } from '@angular/core';
import { MatSnackBar } from '@angular/material/snack-bar';
import { SwUpdate } from '@angular/service-worker';
import { Store } from '@ngrx/store';
import { TranslateService } from '@ngx-translate/core';
import { PlaylistActions } from 'm3u-state';
import { catchError, firstValueFrom, throwError } from 'rxjs';
import { DataService } from 'services';
import {
ERROR,
Playlist,
PLAYLIST_PARSE_BY_URL,
PLAYLIST_UPDATE,
STALKER_REQUEST,
XtreamCodeActions,
XTREAM_REQUEST,
XTREAM_RESPONSE,
} from 'shared-interfaces';
import { AppConfig } from '../../environments/environment';
import {
createPortalDebugErrorEvent,
createPortalDebugRequestContext,
createPortalDebugSuccessEvent,
logPortalDebugEvent,
logPortalDebugRequest,
} from '@iptvnator/portal/shared/util';
interface PwaXtreamResponse {
readonly payload?: unknown;
readonly status?: number;
}
interface PwaXtreamResult {
readonly action: string;
readonly payload: unknown;
readonly type: typeof XTREAM_RESPONSE;
}
interface PwaErrorResult {
readonly message: string;
readonly status: number;
readonly type: typeof ERROR;
}
interface ErrorStatus {
readonly message?: string;
readonly status?: number;
}
@Injectable({
providedIn: 'root',
})
export class PwaService extends DataService {
private readonly http = inject(HttpClient);
private readonly snackBar = inject(MatSnackBar);
private readonly store = inject(Store);
private readonly swUpdate = inject(SwUpdate);
private readonly translateService = inject(TranslateService);
private readonly silentXtreamActions = new Set<string>([
XtreamCodeActions.GetAccountInfo,
XtreamCodeActions.GetLiveCategories,
XtreamCodeActions.GetVodCategories,
XtreamCodeActions.GetSeriesCategories,
XtreamCodeActions.GetShortEpg,
XtreamCodeActions.GetSimpleDataTable,
XtreamCodeActions.GetSimpleDateTable,
]);
/** Proxy URL to avoid CORS issues */
corsProxyUrl = AppConfig.BACKEND_URL;
constructor() {
super();
console.log('PWA service initialized...');
}
/** Uses service worker mechanism to check for available application updates */
checkUpdates() {
this.swUpdate.versionUpdates.subscribe(() => {
this.snackBar
.open(
this.translateService.instant('UPDATE_AVAILABLE'),
this.translateService.instant('REFRESH')
)
.onAction()
.subscribe(() => {
window.location.reload();
});
});
}
getAppVersion(): string {
return AppConfig.version;
}
/**
* Handles incoming IPC commands
* @param type ipc command type
* @param payload payload
*/
sendIpcEvent<T = unknown>(type: string, payload?: unknown): T {
if (type === PLAYLIST_PARSE_BY_URL) {
this.fetchFromUrl(payload);
return undefined as T;
}
if (type === PLAYLIST_UPDATE) {
this.refreshPlaylist(payload);
return undefined as T;
}
if (type === XTREAM_REQUEST) {
return this.forwardXtreamRequest(
payload as { url: string; params: Record<string, string> }
) as T;
}
if (type === STALKER_REQUEST) {
return this.forwardStalkerRequest(
payload as {
url: string;
macAddress: string;
params: Record<string, string>;
}
) as T;
}
return undefined as T;
}
refreshPlaylist(payload: Partial<Playlist & { id: string }>) {
this.getPlaylistFromUrl(payload.url)
.pipe(
catchError((error) => {
this.snackBar.open(
this.getPlaylistRefreshErrorMessage(error),
this.translateService.instant('CLOSE'),
{
duration: 5000,
}
);
return throwError(() => error);
})
)
.subscribe((playlist: Playlist) => {
this.store.dispatch(
PlaylistActions.updatePlaylist({
playlist,
playlistId: payload.id,
})
);
this.snackBar.open(
this.translateService.instant(
'HOME.PLAYLISTS.PLAYLIST_UPDATE_SUCCESS'
),
null,
{ duration: 2000 }
);
});
}
private getPlaylistRefreshErrorMessage(error: unknown): string {
const statusCode =
this.getErrorDetails(error)?.status ??
this.extractHttpStatusCode(error);
if (statusCode === 404) {
return this.translateService.instant('HOME.URL_UPLOAD.ERROR_404');
}
if (statusCode === 403) {
return this.translateService.instant('HOME.URL_UPLOAD.ERROR_403');
}
if (statusCode === 401) {
return this.translateService.instant('HOME.URL_UPLOAD.ERROR_401');
}
return this.translateService.instant(
'HOME.URL_UPLOAD.ERROR_FETCH_FAILED'
);
}
/**
* Fetches playlist from the specified url
* @param payload playlist payload
*/
fetchFromUrl(payload: Partial<Playlist>): void {
const title = payload.title?.trim() || undefined;
this.getPlaylistFromUrl(payload.url)
.pipe(
catchError((error) => {
this.snackBar.open(
this.getErrorMessageByStatusCode(error.status),
'Close',
{
duration: 5000,
}
);
return throwError(() => error);
})
)
.subscribe((response: Playlist) => {
const playlist = title
? {
...response,
filename: title,
title,
}
: response;
this.store.dispatch(
PlaylistActions.handleAddingPlaylistByUrl({
isTemporary: !!payload?.isTemporary,
playlist,
})
);
});
}
getErrorMessageByStatusCode(status: number) {
let messageKey = 'HOME.URL_UPLOAD.ERROR_FETCH_FAILED';
switch (status) {
case 413:
return 'This file is too big. Use standalone or self-hosted version of the app.';
case 403:
messageKey = 'HOME.URL_UPLOAD.ERROR_403';
break;
case 404:
messageKey = 'HOME.URL_UPLOAD.ERROR_404';
break;
case 401:
messageKey = 'HOME.URL_UPLOAD.ERROR_401';
break;
default:
break;
}
return this.translateService.instant(messageKey);
}
private extractHttpStatusCode(error: unknown): number | null {
if (
error &&
typeof error === 'object' &&
'status' in error &&
typeof error.status === 'number'
) {
return error.status;
}
const msg = String((error as { message?: string })?.message ?? error);
const match = msg.match(/status code (\d{3})/);
return match ? parseInt(match[1], 10) : null;
}
async forwardXtreamRequest(payload: {
url: string;
params: Record<string, string>;
macAddress?: string;
requestId?: string;
sessionId?: string;
suppressErrorLog?: boolean;
}) {
const headers = payload.macAddress
? {
headers: {
Cookie: `mac=${payload.macAddress}`,
},
}
: {};
const requestPayload = {
method: 'GET',
url: `${this.corsProxyUrl}/xtream`,
params: {
url: payload.url,
...payload.params,
},
...(payload.macAddress
? {
headers: {
Cookie: `mac=${payload.macAddress}`,
},
}
: {}),
};
const context = createPortalDebugRequestContext({
provider: 'xtream',
operation: payload.params?.action ?? 'unknown',
transport: 'pwa-http',
request: requestPayload,
});
logPortalDebugRequest(context);
try {
let result: PwaErrorResult | PwaXtreamResult;
const response = (await firstValueFrom(
this.http.get<PwaXtreamResponse>(
`${this.corsProxyUrl}/xtream`,
{
params: {
url: payload.url,
...payload.params,
},
...headers,
}
)
)) as PwaXtreamResponse;
if (!response.payload) {
const action = payload.params.action;
const isSilentAction =
payload.suppressErrorLog === true ||
this.silentXtreamActions.has(action);
const normalizedMessage =
this.getReadableXtreamErrorMessage(response);
logPortalDebugEvent(
createPortalDebugErrorEvent(context, response)
);
if (isSilentAction) {
console.log(
`Background Xtream action failed (${action ?? 'unknown'}):`,
normalizedMessage
);
return {
type: ERROR,
status: response.status ?? 500,
message: normalizedMessage,
};
}
result = {
type: ERROR,
status: response.status ?? 500,
message: normalizedMessage,
};
window.postMessage(result);
} else {
result = {
type: XTREAM_RESPONSE,
payload: response.payload,
action: payload.params.action,
};
logPortalDebugEvent(
createPortalDebugSuccessEvent(context, response)
);
window.postMessage(result);
}
return result;
} catch (error: unknown) {
logPortalDebugEvent(createPortalDebugErrorEvent(context, error));
const action = payload.params.action;
const isSilentAction =
payload.suppressErrorLog === true ||
this.silentXtreamActions.has(action);
const normalizedMessage = this.getReadableXtreamErrorMessage(error);
const errorInfo = this.getErrorDetails(error);
// Log error to console
if (isSilentAction) {
console.log(
`Background Xtream action failed (${action ?? 'unknown'}):`,
normalizedMessage
);
return {
type: ERROR,
status: errorInfo?.status ?? 500,
message: normalizedMessage,
};
}
console.error('Xtream request error:', normalizedMessage);
this.snackBar.open(
`Xtream request failed: ${normalizedMessage}`,
'Close',
{
duration: 5000,
}
);
return {
type: ERROR,
status: errorInfo?.status ?? 500,
message: normalizedMessage,
};
}
}
private getReadableXtreamErrorMessage(error: unknown): string {
const fallback = 'Failed to connect to Xtream server';
if (!error) {
return fallback;
}
const maybeError = error as {
message?: unknown;
statusText?: unknown;
error?: unknown;
};
if (typeof maybeError.message === 'string') {
if (maybeError.message.includes('[object Object]')) {
if (typeof maybeError.error === 'string') {
return maybeError.error;
}
if (
maybeError.error &&
typeof maybeError.error === 'object' &&
'message' in
(maybeError.error as Record<string, unknown>) &&
typeof (maybeError.error as Record<string, unknown>)
.message === 'string'
) {
return (maybeError.error as Record<string, string>).message;
}
return fallback;
}
return maybeError.message;
}
if (typeof maybeError.statusText === 'string') {
return maybeError.statusText;
}
if (typeof error === 'string') {
return error;
}
return fallback;
}
private getErrorDetails(error: unknown): ErrorStatus | null {
if (error && typeof error === 'object') {
return error as ErrorStatus;
}
return null;
}
async forwardStalkerRequest(payload: {
url: string;
params: Record<string, string>;
macAddress: string;
}) {
const params = new URLSearchParams({
url: payload.url,
...payload.params,
macAddress: payload.macAddress,
});
const requestUrl = `${this.corsProxyUrl}/stalker?${params.toString()}`;
const context = createPortalDebugRequestContext({
provider: 'stalker',
operation: payload.params?.action ?? 'unknown',
transport: 'pwa-http',
request: {
method: 'GET',
url: requestUrl,
params: {
url: payload.url,
...payload.params,
macAddress: payload.macAddress,
},
},
});
logPortalDebugRequest(context);
try {
// Make the fetch request
const response = await fetch(requestUrl);
if (!response.ok) {
throw new Error(
`Error: ${response.statusText} (Status: ${response.status})`
);
}
// Parse and return the JSON response
const responseBody = await response.json();
logPortalDebugEvent(
createPortalDebugSuccessEvent(context, responseBody)
);
return responseBody.payload;
} catch (err: unknown) {
const errorInfo = this.getErrorDetails(err);
logPortalDebugEvent(createPortalDebugErrorEvent(context, err));
console.error('Stalker request error:', err);
this.snackBar.open(
`Error: ${errorInfo?.message ?? ' Not found'}, status: ${errorInfo?.status ?? 404}`,
'Close',
{
duration: 5000,
}
);
throw err;
}
}
getPlaylistFromUrl(url: string) {
return this.http.get(`${this.corsProxyUrl}/parse`, {
params: { url },
});
}
removeAllListeners(): void {
// not implemented
}
listenOn(_command: string, callback: (...args: unknown[]) => void): void {
window.addEventListener('message', callback);
}
getAppEnvironment(): string {
return 'pwa';
}
}
@@ -0,0 +1 @@
export { SettingsStore } from 'services';
@@ -0,0 +1,124 @@
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { inject, TestBed } from '@angular/core/testing';
import { StorageMap } from '@ngx-pwa/local-storage';
import { of } from 'rxjs';
import { STORE_KEY, Theme } from 'shared-interfaces';
import { SettingsService } from './settings.service';
describe('Service: Settings', () => {
let systemThemeListeners: Array<(event: MediaQueryListEvent) => void>;
beforeEach(() => {
systemThemeListeners = [];
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: jest.fn().mockImplementation(() => ({
matches: true,
addEventListener: jest.fn(
(
_event: 'change',
listener: (event: MediaQueryListEvent) => void
) => {
systemThemeListeners.push(listener);
}
),
removeEventListener: jest.fn(
(
_event: 'change',
listener: (event: MediaQueryListEvent) => void
) => {
systemThemeListeners = systemThemeListeners.filter(
(registeredListener) =>
registeredListener !== listener
);
}
),
addListener: jest.fn(),
removeListener: jest.fn(),
})),
});
TestBed.configureTestingModule({
providers: [SettingsService],
imports: [HttpClientTestingModule],
});
});
it('should create a service instance', inject(
[SettingsService],
(service: SettingsService) => {
expect(service).toBeTruthy();
}
));
it('should set key/value pair', inject(
[SettingsService, StorageMap],
(service: SettingsService, storage: StorageMap) => {
const version = '2.1.0';
jest.spyOn(storage, 'set').mockReturnValue(of(undefined));
service.setValueToLocalStorage(STORE_KEY.Version, version);
expect(storage.set).toHaveBeenCalledWith(
STORE_KEY.Version,
version
);
}
));
it('should get value from the local storage', inject(
[SettingsService],
(service: SettingsService) => {
const version = '2.1.0';
service.setValueToLocalStorage(STORE_KEY.Version, version);
service
.getValueFromLocalStorage(STORE_KEY.Version)
.subscribe((value) => {
expect(value).toBe(version);
});
}
));
describe('Test theme switch', () => {
let spyOnAdd, spyOnRemove;
beforeEach(() => {
spyOnAdd = jest.spyOn(document.body.classList, 'add');
spyOnRemove = jest.spyOn(document.body.classList, 'remove');
});
afterEach(() => {
jest.clearAllMocks();
});
it('should switch to the dark theme', inject(
[SettingsService],
(service: SettingsService) => {
service.changeTheme(Theme.DarkTheme);
expect(spyOnRemove).toHaveBeenCalledTimes(0);
expect(spyOnAdd).toHaveBeenCalledTimes(1);
}
));
it('should switch to the light theme', inject(
[SettingsService],
(service: SettingsService) => {
service.changeTheme(Theme.LightTheme);
expect(spyOnRemove).toHaveBeenCalledTimes(1);
expect(spyOnAdd).toHaveBeenCalledTimes(0);
}
));
it('should follow the system theme', inject(
[SettingsService],
(service: SettingsService) => {
service.changeTheme(Theme.SystemTheme);
expect(spyOnAdd).toHaveBeenCalledWith('dark-theme');
systemThemeListeners[0]?.({
matches: false,
} as MediaQueryListEvent);
expect(spyOnRemove).toHaveBeenCalledWith('dark-theme');
}
));
});
});
@@ -0,0 +1,235 @@
import { HttpClient } from '@angular/common/http';
import { inject, Injectable } from '@angular/core';
import { StorageMap } from '@ngx-pwa/local-storage';
import { catchError, map, Observable } from 'rxjs';
import { STORE_KEY, Theme } from 'shared-interfaces';
const PRERELEASE_KEYWORDS = [
'beta',
'alpha',
'rc',
'preview',
'dev',
'canary',
'nightly',
] as const;
interface ParsedVersion {
major: number;
minor: number;
patch: number;
prerelease: boolean;
}
type LegacyMediaQueryList = MediaQueryList & {
addListener?: (listener: (event: MediaQueryListEvent) => void) => void;
removeListener?: (listener: (event: MediaQueryListEvent) => void) => void;
};
function parseVersion(input: string): ParsedVersion | null {
const normalized = input.trim().replace(/^v/i, '');
const match = normalized.match(
/(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:[-+]?([0-9A-Za-z.-]+))?/
);
if (!match) {
return null;
}
return {
major: Number(match[1] ?? 0),
minor: Number(match[2] ?? 0),
patch: Number(match[3] ?? 0),
prerelease: Boolean(match[4]),
};
}
function hasPrereleaseKeyword(value: string): boolean {
const normalized = value.toLowerCase();
return PRERELEASE_KEYWORDS.some((keyword) => normalized.includes(keyword));
}
function compareVersions(a: ParsedVersion, b: ParsedVersion): number {
if (a.major !== b.major) {
return a.major - b.major;
}
if (a.minor !== b.minor) {
return a.minor - b.minor;
}
return a.patch - b.patch;
}
@Injectable({
providedIn: 'root',
})
export class SettingsService {
private http = inject(HttpClient);
private storage = inject(StorageMap);
private readonly systemThemeMediaQuery =
typeof window !== 'undefined' && 'matchMedia' in window
? window.matchMedia('(prefers-color-scheme: dark)')
: null;
private readonly systemThemeChangeHandler = (
event: MediaQueryListEvent
): void => {
this.applyResolvedTheme(
event.matches ? Theme.DarkTheme : Theme.LightTheme
);
};
private isSystemThemeSyncActive = false;
/**
* Changes the visual theme of the application
* @param selectedTheme theme to set
*/
changeTheme(selectedTheme: Theme): void {
this.stopSystemThemeSync();
if (selectedTheme === Theme.SystemTheme) {
this.startSystemThemeSync();
this.applyResolvedTheme(
this.systemThemeMediaQuery?.matches
? Theme.DarkTheme
: Theme.LightTheme
);
return;
}
this.applyResolvedTheme(selectedTheme);
}
private applyResolvedTheme(selectedTheme: Theme): void {
if (selectedTheme === Theme.DarkTheme) {
document.body.classList.add('dark-theme');
return;
}
document.body.classList.remove('dark-theme');
}
private startSystemThemeSync(): void {
if (!this.systemThemeMediaQuery || this.isSystemThemeSyncActive) {
return;
}
const mediaQuery = this.systemThemeMediaQuery as LegacyMediaQueryList;
if (mediaQuery.addEventListener) {
mediaQuery.addEventListener('change', this.systemThemeChangeHandler);
} else {
mediaQuery.addListener?.(this.systemThemeChangeHandler);
}
this.isSystemThemeSyncActive = true;
}
private stopSystemThemeSync(): void {
if (!this.systemThemeMediaQuery || !this.isSystemThemeSyncActive) {
return;
}
const mediaQuery = this.systemThemeMediaQuery as LegacyMediaQueryList;
if (mediaQuery.removeEventListener) {
mediaQuery.removeEventListener(
'change',
this.systemThemeChangeHandler
);
} else {
mediaQuery.removeListener?.(this.systemThemeChangeHandler);
}
this.isSystemThemeSyncActive = false;
}
/**
* Returns the value of the given key from the local storage
* @param key key to get
* @returns returns the value of the given key
*/
getValueFromLocalStorage(key: STORE_KEY) {
return this.storage.get(key);
}
/**
* Sets the given key/value pair in the local storage
* @param key key to set
* @param value value to set
* @param withCallback if true, the callback will be called after the value is set
*/
setValueToLocalStorage(
key: STORE_KEY,
value: unknown,
withCallback = false
): Observable<unknown> | void {
if (withCallback) {
return this.storage.set(key, value);
}
this.storage.set(key, value).subscribe();
}
/**
* Returns the version of the released app
* Filters out pre-release versions (beta, alpha, rc)
*/
getAppVersion() {
return this.http
.get<{ created_at: string; name: string }[]>(
'https://api.github.com/repos/4gray/iptvnator/releases'
)
.pipe(
map((response) => {
// Filter out pre-release versions (beta, alpha, rc, etc.)
const stableReleases = response.filter((release) => {
if (hasPrereleaseKeyword(release.name)) {
return false;
}
const version = parseVersion(release.name);
if (!version) return false;
return !version.prerelease;
});
// Sort stable releases by creation date
const sortedReleases = stableReleases.sort(
(a, b) =>
new Date(b.created_at).getTime() -
new Date(a.created_at).getTime()
);
return sortedReleases[0];
}),
map((response) => response.name),
catchError((err) => {
console.error(err);
throw new Error(err);
})
);
}
/**
* Compares current version with latest version
* @param currentVersion current version of the app
* @param latestVersion latest stable version from GitHub
* @returns true if current version is outdated
*/
isVersionOutdated(
currentVersion: string,
latestVersion: string
): boolean {
const cleanCurrent = parseVersion(currentVersion);
const cleanLatest = parseVersion(latestVersion);
if (!cleanCurrent || !cleanLatest) {
console.warn('Invalid version format:', {
currentVersion,
latestVersion,
});
return false;
}
return compareVersions(cleanCurrent, cleanLatest) < 0;
}
}
@@ -0,0 +1,71 @@
import { inject, Injectable, Provider } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { Router } from '@angular/router';
import {
WORKSPACE_SHELL_ACTIONS,
WorkspaceAccountInfoData,
WorkspacePlaylistType,
WorkspaceShellActions,
} from '@iptvnator/workspace/shell/util';
@Injectable({ providedIn: 'root' })
export class AppWorkspaceShellActionsService implements WorkspaceShellActions {
private readonly dialog = inject(MatDialog);
private readonly router = inject(Router);
openAddPlaylistDialog(type?: WorkspacePlaylistType): void {
void import('@iptvnator/playlist/import/feature').then(
({ AddPlaylistDialogComponent }) => {
this.dialog.open(AddPlaylistDialogComponent, {
width: '560px',
maxWidth: '92vw',
data: type ? { type } : {},
});
}
);
}
openGlobalSearch(initialQuery = ''): void {
void import('@iptvnator/portal/xtream/feature').then(
({ GlobalSearchResultsComponent }) => {
this.dialog.open(GlobalSearchResultsComponent, {
width: '100%',
height: '100%',
maxWidth: '100%',
panelClass: 'global-search-overlay',
data: {
isGlobalSearch: true,
initialQuery,
},
});
}
);
}
openGlobalRecent(): void {
void this.router.navigate(['/workspace/global-recent']);
}
openAccountInfo(data: WorkspaceAccountInfoData): void {
void import('@iptvnator/portal/xtream/feature').then(
({ AccountInfoComponent }) => {
this.dialog.open(AccountInfoComponent, {
width: '80%',
maxWidth: '1200px',
maxHeight: '90vh',
data,
});
}
);
}
}
export function provideWorkspaceShellActions(): Provider[] {
return [
AppWorkspaceShellActionsService,
{
provide: WORKSPACE_SHELL_ACTIONS,
useExisting: AppWorkspaceShellActionsService,
},
];
}
@@ -0,0 +1,55 @@
<h2 mat-dialog-title>
{{ 'SETTINGS.REMOVE_DIALOG.TITLE' | translate }}
</h2>
<mat-dialog-content class="mat-typography settings-delete-dialog">
<p class="settings-delete-dialog__lead">
{{
'SETTINGS.REMOVE_DIALOG.MESSAGE'
| translate: { count: dialogData.summary.total }
}}
</p>
<section class="settings-delete-dialog__section">
<h3 class="settings-delete-dialog__section-title">
{{ 'SETTINGS.REMOVE_DIALOG.SUMMARY_TITLE' | translate }}
</h3>
<div class="settings-delete-dialog__summary">
@for (item of summaryItems(); track item.id) {
<div class="settings-delete-dialog__summary-item">
<div class="settings-delete-dialog__summary-label">
<mat-icon aria-hidden="true">{{ item.icon }}</mat-icon>
<span>{{ item.labelKey | translate }}</span>
</div>
<strong>{{ item.count }}</strong>
</div>
}
</div>
</section>
<section class="settings-delete-dialog__section">
<h3 class="settings-delete-dialog__section-title">
{{ 'SETTINGS.REMOVE_DIALOG.CONSEQUENCES_TITLE' | translate }}
</h3>
<ul class="settings-delete-dialog__list">
@for (key of consequenceKeys; track key) {
<li>{{ key | translate }}</li>
}
</ul>
</section>
<p class="settings-delete-dialog__hint">
{{ 'SETTINGS.REMOVE_DIALOG.BACKUP_HINT' | translate }}
</p>
</mat-dialog-content>
<mat-dialog-actions align="end" class="settings-delete-dialog__actions">
<button mat-button mat-dialog-close cdkFocusInitial>
{{ 'CANCEL' | translate }}
</button>
<button mat-flat-button [mat-dialog-close]="true" color="warn">
{{ 'SETTINGS.REMOVE_DIALOG.CONFIRM' | translate }}
</button>
</mat-dialog-actions>
@@ -0,0 +1,94 @@
:host {
display: block;
}
.settings-delete-dialog {
display: flex;
flex-direction: column;
gap: 18px;
min-width: min(100%, 360px);
}
.settings-delete-dialog__lead,
.settings-delete-dialog__hint {
margin: 0;
line-height: 1.55;
text-wrap: pretty;
}
.settings-delete-dialog__section {
display: flex;
flex-direction: column;
gap: 10px;
}
.settings-delete-dialog__section-title {
margin: 0;
font-size: 0.8rem;
font-weight: 700;
letter-spacing: 0.04em;
text-transform: uppercase;
color: var(--mat-sys-on-surface-variant);
}
.settings-delete-dialog__summary {
display: grid;
gap: 8px;
}
.settings-delete-dialog__summary-item {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
padding: 10px 12px;
border: 1px solid
color-mix(in srgb, var(--mat-sys-outline) 46%, transparent);
border-radius: 14px;
background: color-mix(
in srgb,
var(--mat-sys-surface-container) 84%,
transparent
);
strong {
font-size: 1rem;
font-variant-numeric: tabular-nums;
}
}
.settings-delete-dialog__summary-label {
display: flex;
align-items: center;
gap: 10px;
min-width: 0;
}
.settings-delete-dialog__summary-label mat-icon {
width: 18px;
height: 18px;
font-size: 18px;
color: var(--mat-sys-primary);
}
.settings-delete-dialog__list {
margin: 0;
padding-left: 20px;
display: grid;
gap: 8px;
}
.settings-delete-dialog__hint {
padding: 12px 14px;
border-radius: 14px;
background: color-mix(
in srgb,
var(--app-selection-surface) 32%,
transparent
);
color: var(--mat-sys-on-surface-variant);
}
.settings-delete-dialog__actions {
padding-top: 2px;
}
@@ -0,0 +1,96 @@
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MAT_DIALOG_DATA } from '@angular/material/dialog';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { SettingsDeleteAllPlaylistsDialogComponent } from './settings-delete-all-playlists-dialog.component';
describe('SettingsDeleteAllPlaylistsDialogComponent', () => {
let component: SettingsDeleteAllPlaylistsDialogComponent;
let fixture: ComponentFixture<SettingsDeleteAllPlaylistsDialogComponent>;
let translate: TranslateService;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [
SettingsDeleteAllPlaylistsDialogComponent,
NoopAnimationsModule,
TranslateModule.forRoot(),
],
providers: [
{
provide: MAT_DIALOG_DATA,
useValue: {
summary: {
total: 6,
m3u: 3,
xtream: 2,
stalker: 1,
},
},
},
],
}).compileComponents();
translate = TestBed.inject(TranslateService);
translate.setTranslation(
'en',
{
CANCEL: 'Cancel',
HOME: {
PLAYLIST_TYPES: {
M3U: 'M3U',
XTREAM: 'Xtream',
STALKER: 'Stalker',
},
},
SETTINGS: {
REMOVE_DIALOG: {
TITLE: 'Delete all playlists?',
MESSAGE: 'Delete all {{count}} playlists from the app.',
SUMMARY_TITLE: 'Playlist sources',
CONSEQUENCES_TITLE: 'This also removes',
CONSEQUENCE_FAVORITES: 'Favorites',
CONSEQUENCE_RECENTLY_VIEWED: 'Recently viewed history',
CONSEQUENCE_PLAYBACK: 'Playback positions',
CONSEQUENCE_DOWNLOADS: 'Download history',
CONSEQUENCE_XTREAM_CACHE: 'Xtream cache',
BACKUP_HINT: 'Use Export first if you need a backup.',
CONFIRM: 'Delete everything',
},
},
},
true
);
translate.use('en');
fixture = TestBed.createComponent(
SettingsDeleteAllPlaylistsDialogComponent
);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('renders the playlist type summary and destructive guidance', () => {
const text = (fixture.nativeElement as HTMLElement).textContent ?? '';
expect(component.summaryItems().map((item) => item.count)).toEqual([
3, 2, 1,
]);
expect(text).toContain('Delete all playlists?');
expect(text).toContain('Delete all 6 playlists from the app.');
expect(text).toContain('Playlist sources');
expect(text).toContain('M3U');
expect(text).toContain('Xtream');
expect(text).toContain('Stalker');
expect(text).toContain('Favorites');
expect(text).toContain('Use Export first if you need a backup.');
});
it('renders cancel and confirm actions', () => {
const buttons = Array.from(
(fixture.nativeElement as HTMLElement).querySelectorAll('button')
).map((button) => button.textContent?.trim());
expect(buttons).toEqual(['Cancel', 'Delete everything']);
});
});
@@ -0,0 +1,68 @@
import { CommonModule } from '@angular/common';
import { Component, computed, inject } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatDialogModule, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { MatIconModule } from '@angular/material/icon';
import { TranslateModule } from '@ngx-translate/core';
export interface SettingsDeleteAllPlaylistsDialogData {
summary: {
total: number;
m3u: number;
xtream: number;
stalker: number;
};
}
type SettingsDeleteSummaryItem = {
count: number;
icon: string;
id: 'm3u' | 'xtream' | 'stalker';
labelKey: string;
};
@Component({
selector: 'app-settings-delete-all-playlists-dialog',
templateUrl: './settings-delete-all-playlists-dialog.component.html',
styleUrls: ['./settings-delete-all-playlists-dialog.component.scss'],
imports: [
CommonModule,
MatButtonModule,
MatDialogModule,
MatIconModule,
TranslateModule,
],
})
export class SettingsDeleteAllPlaylistsDialogComponent {
readonly dialogData =
inject<SettingsDeleteAllPlaylistsDialogData>(MAT_DIALOG_DATA);
readonly summaryItems = computed<SettingsDeleteSummaryItem[]>(() => [
{
id: 'm3u',
count: this.dialogData.summary.m3u,
icon: 'playlist_play',
labelKey: 'HOME.PLAYLIST_TYPES.M3U',
},
{
id: 'xtream',
count: this.dialogData.summary.xtream,
icon: 'cloud',
labelKey: 'HOME.PLAYLIST_TYPES.XTREAM',
},
{
id: 'stalker',
count: this.dialogData.summary.stalker,
icon: 'router',
labelKey: 'HOME.PLAYLIST_TYPES.STALKER',
},
]);
readonly consequenceKeys = [
'SETTINGS.REMOVE_DIALOG.CONSEQUENCE_FAVORITES',
'SETTINGS.REMOVE_DIALOG.CONSEQUENCE_RECENTLY_VIEWED',
'SETTINGS.REMOVE_DIALOG.CONSEQUENCE_PLAYBACK',
'SETTINGS.REMOVE_DIALOG.CONSEQUENCE_DOWNLOADS',
'SETTINGS.REMOVE_DIALOG.CONSEQUENCE_XTREAM_CACHE',
] as const;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,829 @@
:host {
display: block;
}
.settings-container {
height: auto;
overflow: visible;
padding: 18px 20px calc(36px + var(--settings-safe-bottom));
}
.settings-container.dialog-mode {
height: auto;
max-height: none;
overflow: visible;
padding: 12px 8px calc(24px + var(--settings-safe-bottom));
}
.settings-layout {
display: flex;
flex-direction: column;
gap: 16px;
align-items: stretch;
max-width: 920px;
margin: 0 auto;
padding-bottom: calc(
var(--settings-action-bar-space) + var(--settings-safe-bottom)
);
}
.settings-container.dialog-mode .settings-layout {
padding-bottom: 0;
}
.settings-page-header {
padding: 14px 18px 8px;
background: transparent;
border: 0;
box-shadow: none;
}
.settings-page-header__text {
max-width: 56ch;
h1 {
margin: 0;
font-size: clamp(1.35rem, 2vw, 1.75rem);
line-height: 1.08;
letter-spacing: -0.03em;
font-weight: 700;
}
p {
margin: 4px 0 0;
color: var(--settings-muted);
font-size: 0.86rem;
line-height: 1.45;
}
}
.settings-content {
min-width: 0;
display: flex;
flex-direction: column;
gap: 16px;
}
.settings-group {
position: relative;
background: var(--settings-group-bg);
overflow: hidden;
scroll-margin-top: 24px;
padding: 0;
border: 1px solid var(--settings-group-border);
border-radius: 22px;
box-shadow: var(--settings-group-shadow);
transition:
background 0.2s ease,
box-shadow 0.2s ease,
border-color 0.2s ease;
}
.settings-group--active {
background: var(--settings-group-active-bg);
border-color: var(--settings-group-active-ring);
box-shadow: var(--settings-group-active-shadow);
.settings-group__header-icon {
background: color-mix(
in srgb,
var(--app-selection-surface-strong) 70%,
var(--mat-sys-surface-container-high)
);
color: var(--app-selection-color);
border-color: var(--settings-group-active-ring);
}
.settings-group__header-text h3 {
color: var(--app-selection-color);
}
}
.settings-group__header {
display: flex;
align-items: center;
gap: 14px;
padding: 16px 18px 14px;
.settings-group__header-icon {
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
flex-shrink: 0;
border: 1px solid
color-mix(in srgb, var(--mat-sys-outline-variant) 74%, transparent);
border-radius: 12px;
background: color-mix(
in srgb,
var(--mat-sys-surface-container-high) 78%,
transparent
);
color: var(--mat-sys-on-surface-variant);
mat-icon {
font-size: 20px;
width: 20px;
height: 20px;
}
}
.settings-group__header-text {
h3 {
margin: 0;
font-size: 1.08rem;
font-weight: 700;
letter-spacing: -0.02em;
}
p {
margin: 2px 0 0;
color: var(--settings-muted);
font-size: 0.84rem;
line-height: 1.45;
}
}
}
.settings-group__footer {
padding: 12px 18px 16px;
border-top: 1px solid var(--settings-item-border);
}
.setting-item {
display: grid;
grid-template-columns: minmax(0, 1.15fr) minmax(220px, 340px);
gap: 14px;
margin: 0 18px;
padding: 14px 0;
border-top: 1px solid var(--settings-item-border);
background: transparent;
&:last-of-type {
margin-bottom: 0;
}
}
.settings-group .setting-item:last-child {
margin-bottom: 0;
}
.setting-item__meta {
h4 {
margin: 0;
font-size: 0.95rem;
font-weight: 650;
letter-spacing: -0.01em;
}
p {
margin: 3px 0 0;
color: var(--settings-muted);
font-size: 0.84rem;
line-height: 1.45;
}
}
.setting-item__control {
display: flex;
justify-content: flex-end;
align-items: center;
gap: 12px;
min-height: 40px;
mat-form-field,
.w-full {
width: min(100%, 340px);
}
}
.setting-item__toggle {
justify-content: flex-end;
}
.setting-item--full-control {
grid-template-columns: 1fr;
gap: 12px;
}
.setting-item--full-control .setting-item__control {
justify-content: stretch;
}
.theme-switcher {
width: min(100%, 540px);
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 8px;
}
.theme-switcher__option {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
min-height: 54px;
padding: 12px 14px;
border: 1px solid
color-mix(in srgb, var(--mat-sys-outline-variant) 70%, transparent);
border-radius: 16px;
background: color-mix(
in srgb,
var(--mat-sys-surface-container-low) 88%,
transparent
);
color: var(--mat-sys-on-surface-variant);
font: inherit;
font-size: 0.9rem;
font-weight: 600;
letter-spacing: -0.01em;
cursor: pointer;
transition:
border-color 0.18s ease,
background 0.18s ease,
box-shadow 0.18s ease,
color 0.18s ease;
mat-icon {
width: 18px;
height: 18px;
font-size: 18px;
}
&:hover {
background: color-mix(
in srgb,
var(--mat-sys-surface-container-high) 86%,
transparent
);
color: var(--mat-sys-on-surface);
}
&:focus-visible {
outline: none;
box-shadow: 0 0 0 3px
color-mix(in srgb, var(--app-selection-color) 18%, transparent);
}
}
.theme-switcher__option--selected {
border-color: var(--settings-group-active-ring);
background: linear-gradient(
135deg,
color-mix(
in srgb,
var(--app-selection-surface-strong) 72%,
var(--mat-sys-surface-container-high)
),
color-mix(
in srgb,
var(--app-selection-surface) 72%,
var(--mat-sys-surface-container)
)
);
color: var(--app-selection-color);
box-shadow:
inset 0 0 0 1px
color-mix(in srgb, var(--app-selection-border) 54%, transparent),
0 10px 18px -22px var(--settings-group-active-glow);
}
.epg-sources {
width: 100%;
display: flex;
flex-direction: column;
gap: 8px;
}
.epg-sources-empty {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
gap: 8px;
padding: 24px 16px 16px;
color: var(--mat-sys-on-surface-variant);
.epg-sources-empty__icon {
font-size: 40px;
width: 40px;
height: 40px;
opacity: 0.55;
margin-bottom: 4px;
}
.epg-sources-empty__title {
margin: 0;
font-size: 0.95rem;
font-weight: 600;
color: var(--mat-sys-on-surface);
}
.epg-sources-empty__hint {
margin: 0;
font-size: 0.825rem;
line-height: 1.5;
max-width: 360px;
opacity: 0.75;
}
}
.epg-source-row {
display: flex;
align-items: center;
gap: 6px;
.w-full {
width: 100%;
}
app-epg-source-status {
flex-shrink: 0;
}
}
.inline-actions {
display: flex;
justify-content: flex-end;
flex-wrap: wrap;
gap: 6px;
}
.button-spinner {
display: inline-block;
margin-right: 6px;
vertical-align: middle;
}
.inline-actions__button {
min-width: 118px;
}
.inline-actions__button--busy {
background: color-mix(
in srgb,
var(--app-selection-surface) 74%,
transparent
);
color: var(--app-selection-color);
box-shadow:
inset 0 0 0 1px
color-mix(in srgb, var(--app-selection-border) 48%, transparent),
0 8px 18px -18px var(--settings-group-active-glow);
}
.inline-actions__label {
display: inline-flex;
align-items: center;
}
.remote-control-urls {
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 6px;
}
.remote-control-url-item {
width: min(100%, 340px);
}
.url-row {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 4px;
}
.remote-control-url {
font-family:
'JetBrains Mono', 'SFMono-Regular', Menlo, Monaco, Consolas, monospace;
color: inherit;
text-decoration: none;
font-size: 0.84rem;
&:hover {
text-decoration: underline;
}
}
.qr-code-container {
display: flex;
justify-content: flex-end;
padding: 8px 0;
}
.version-block {
flex-direction: column;
align-items: flex-end;
span {
font-weight: 700;
}
small {
margin-top: 4px;
color: var(--mat-sys-on-surface-variant);
text-align: right;
}
}
.link-cards {
width: 100%;
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 10px;
box-sizing: border-box;
}
.link-card {
box-sizing: border-box;
display: grid;
grid-template-columns: 40px minmax(0, 1fr) 20px;
align-items: center;
gap: 12px;
padding: 12px 14px;
border: 1px solid
color-mix(in srgb, var(--mat-sys-outline-variant) 70%, transparent);
border-radius: 16px;
background: color-mix(
in srgb,
var(--mat-sys-surface-container-low) 88%,
transparent
);
color: var(--mat-sys-on-surface);
text-decoration: none;
transition:
border-color 0.18s ease,
background 0.18s ease,
transform 0.18s ease,
box-shadow 0.18s ease;
&:hover {
transform: translateY(-1px);
border-color: color-mix(
in srgb,
var(--app-selection-border) 54%,
var(--mat-sys-outline-variant)
);
background: color-mix(
in srgb,
var(--mat-sys-surface-container-high) 92%,
transparent
);
box-shadow: 0 10px 20px -22px rgba(15, 23, 42, 0.5);
.link-card__arrow {
opacity: 1;
transform: translate(2px, -2px);
}
}
&:focus-visible {
outline: none;
box-shadow:
0 0 0 2px var(--mat-sys-surface),
0 0 0 4px
color-mix(in srgb, var(--app-selection-color) 40%, transparent);
}
}
.link-card__glyph {
display: inline-flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
border-radius: 12px;
background: color-mix(
in srgb,
var(--mat-sys-surface-container-high) 82%,
transparent
);
color: var(--mat-sys-on-surface-variant);
svg {
width: 20px;
height: 20px;
}
mat-icon {
font-size: 20px;
width: 20px;
height: 20px;
}
}
.link-card--github .link-card__glyph {
background: color-mix(in srgb, var(--mat-sys-on-surface) 10%, transparent);
color: var(--mat-sys-on-surface);
}
.link-card--blog .link-card__glyph {
background: color-mix(in srgb, #ff7849 18%, transparent);
color: #ff8a5b;
}
.link-card--telegram .link-card__glyph {
background: color-mix(in srgb, #229ed9 22%, transparent);
color: #38b0e3;
}
.link-card__text {
min-width: 0;
display: flex;
flex-direction: column;
gap: 2px;
strong {
font-size: 0.92rem;
font-weight: 650;
letter-spacing: -0.01em;
}
span {
color: var(--settings-muted);
font-size: 0.78rem;
line-height: 1.35;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
}
.link-card__arrow {
font-size: 18px;
width: 18px;
height: 18px;
color: var(--settings-muted);
opacity: 0.6;
transition:
opacity 0.18s ease,
transform 0.18s ease;
}
.settings-note {
margin: 12px 18px 18px;
padding: 10px 12px;
border-radius: 14px;
font-size: 0.84rem;
background: color-mix(in srgb, var(--mat-sys-primary) 8%, transparent);
border: 1px solid
color-mix(in srgb, var(--mat-sys-primary) 30%, transparent);
line-height: 1.45;
a {
color: inherit;
font-weight: 700;
}
}
.danger-zone {
margin-top: 8px;
margin-bottom: 18px;
padding: 14px 16px;
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: 0;
}
.danger-zone__summary-pill {
display: inline-flex;
align-items: center;
gap: 8px;
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) 60%, transparent);
font-size: 0.82rem;
line-height: 1.2;
color: var(--mat-sys-on-surface);
.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: 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 {
background: color-mix(
in srgb,
var(--settings-item-danger-border) 28%,
transparent
);
}
.action-bar {
position: sticky;
bottom: calc(
var(--settings-action-bar-offset) + var(--settings-safe-bottom)
);
margin-left: auto;
z-index: 100;
display: flex;
justify-content: flex-end;
align-items: center;
gap: 12px;
flex-wrap: wrap;
padding: 10px 14px;
border: 1px solid var(--settings-action-bar-border);
border-radius: 18px;
background: var(--settings-action-bar-bg);
backdrop-filter: blur(12px);
box-shadow: var(--settings-action-bar-shadow);
}
.settings-container.dialog-mode .action-bar {
position: static;
margin-top: 12px;
margin-bottom: 2px;
box-shadow: none;
border-radius: 16px;
padding: 12px;
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%;
padding: 0;
}
}
@media (max-width: 860px) {
.settings-container {
height: auto;
padding: 12px 12px calc(18px + var(--settings-safe-bottom));
}
.settings-page-header {
padding: 12px 14px;
border-radius: 16px;
}
.setting-item {
grid-template-columns: 1fr;
gap: 12px;
margin: 0 14px;
padding: 12px 0;
}
.setting-item__control {
justify-content: flex-start;
mat-form-field,
.w-full,
.epg-sources,
.remote-control-url-item {
width: 100%;
}
}
.theme-switcher {
width: 100%;
grid-template-columns: 1fr;
}
.remote-control-urls,
.version-block {
align-items: flex-start;
}
.link-cards {
grid-template-columns: 1fr;
}
.support-btn {
flex: 1 1 100%;
}
.url-row {
justify-content: flex-start;
flex-wrap: wrap;
}
.action-bar {
position: static;
flex-direction: column-reverse;
align-items: stretch;
border-radius: 16px;
box-shadow: none;
width: 100%;
margin-left: 0;
button {
width: 100%;
}
}
}
@@ -0,0 +1,884 @@
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import {
FormsModule,
ReactiveFormsModule,
UntypedFormBuilder,
} from '@angular/forms';
import { MatCardModule } from '@angular/material/card';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatDialog } from '@angular/material/dialog';
import { MatDividerModule } from '@angular/material/divider';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIconModule } from '@angular/material/icon';
import { MatListModule } from '@angular/material/list';
import { MatSelectModule } from '@angular/material/select';
import { MatSnackBar } from '@angular/material/snack-bar';
import { MatTooltipModule } from '@angular/material/tooltip';
import { Router } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { EpgService } from '@iptvnator/epg/data-access';
import { Store } from '@ngrx/store';
import { MockStore, provideMockStore } from '@ngrx/store/testing';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { DialogService } from 'components';
import { MockModule, MockProvider } from 'ng-mocks';
import {
DatabaseService,
DataService,
PlaylistBackupService,
PlaylistsService,
} from 'services';
import {
/* EmbeddedMpvSupport, */
Language,
PlaylistMeta,
StartupBehavior,
StreamFormat,
Theme,
VideoPlayer,
} from 'shared-interfaces';
import { SettingsComponent } from './settings.component';
import { signal } from '@angular/core';
import { SettingsContextService } from '@iptvnator/workspace/shell/util';
import {
PlaylistActions,
selectAllPlaylistsMeta,
selectIsEpgAvailable,
} from 'm3u-state';
import { NgxIndexedDBService } from 'ngx-indexed-db';
import { from, of } from 'rxjs';
import { ElectronServiceStub } from '../services/electron.service.stub';
import { SettingsStore } from '../services/settings-store.service';
import { SettingsService } from '../services/settings.service';
class MatSnackBarStub {
open = jest.fn();
}
export class MockRouter {
navigateByUrl(url: string): string {
return url;
}
}
const DEFAULT_SETTINGS = {
player: VideoPlayer.VideoJs,
streamFormat: StreamFormat.M3u8StreamFormat,
language: Language.ENGLISH,
showCaptions: false,
showDashboard: true,
startupBehavior: StartupBehavior.FirstView,
showExternalPlaybackBar: true,
theme: Theme.SystemTheme,
mpvPlayerPath: '',
mpvReuseInstance: false,
vlcPlayerPath: '',
remoteControl: false,
remoteControlPort: 8765,
epgUrl: [],
};
class MockSettingsStore {
private _settings = signal(DEFAULT_SETTINGS);
getSettings = () => this._settings();
loadSettings = jest.fn().mockResolvedValue(undefined);
updateSettings = jest.fn().mockResolvedValue(undefined);
// Helper method for tests to modify settings
_setSettings(newSettings: Partial<typeof DEFAULT_SETTINGS>) {
this._settings.set({
...this._settings(),
...newSettings,
});
}
}
class MockSettingsService {
getAppVersion = jest.fn().mockReturnValue(from(Promise.resolve('1.0.0')));
changeTheme = jest.fn();
isVersionOutdated = jest.fn().mockImplementation(
(currentVersion: string, latestVersion: string) =>
currentVersion.localeCompare(latestVersion, undefined, {
numeric: true,
sensitivity: 'base',
}) < 0
);
}
describe('SettingsComponent', () => {
let component: SettingsComponent;
let fixture: ComponentFixture<SettingsComponent>;
let electronService: DataService;
let router: Router;
let settingsStore: unknown;
let translate: TranslateService;
let epgService: EpgService;
let dialogService: DialogService;
let playlistsService: PlaylistsService;
let playlistBackupService: PlaylistBackupService;
let store: Store;
let mockStore: MockStore;
let databaseService: DatabaseService;
let snackBar: MatSnackBarStub;
const originalElectron = window.electron;
const importDate = '2026-04-21T00:00:00.000Z';
const createPlaylistMeta = (
overrides: Partial<PlaylistMeta> = {}
): PlaylistMeta => ({
_id: overrides._id ?? 'playlist-id',
title: overrides.title ?? 'Playlist',
count: overrides.count ?? 10,
importDate: overrides.importDate ?? importDate,
autoRefresh: overrides.autoRefresh ?? false,
...overrides,
});
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
providers: [
UntypedFormBuilder,
{ provide: SettingsStore, useClass: MockSettingsStore },
MockProvider(EpgService, {
fetchEpg: jest.fn(),
}),
MockProvider(DialogService, {
openConfirmDialog: jest.fn(),
}),
MockProvider(MatDialog, {
open: jest.fn(),
}),
{ provide: SettingsService, useClass: MockSettingsService },
{ provide: MatSnackBar, useClass: MatSnackBarStub },
{ provide: DataService, useClass: ElectronServiceStub },
{
provide: Router,
useClass: MockRouter,
},
provideMockStore({
selectors: [
{ selector: selectAllPlaylistsMeta, value: [] },
{ selector: selectIsEpgAvailable, value: false },
],
}),
{
provide: NgxIndexedDBService,
useValue: {},
},
MockProvider(PlaylistsService, {
getAllData: jest.fn().mockReturnValue(of([])),
removeAll: jest.fn(),
}),
MockProvider(DatabaseService, {
createOperationId: jest
.fn()
.mockReturnValue('delete-all-op'),
deleteAllPlaylists: jest.fn().mockResolvedValue(true),
}),
MockProvider(PlaylistBackupService, {
exportBackup: jest.fn().mockResolvedValue({
defaultFileName:
'iptvnator-playlist-backup-2026-04-21.json',
json: '{}',
manifest: {
kind: 'iptvnator-playlist-backup',
version: 1,
exportedAt: '2026-04-21T00:00:00.000Z',
includeSecrets: true,
playlists: [],
},
}),
importBackup: jest.fn().mockResolvedValue({
imported: 0,
merged: 0,
skipped: 0,
failed: 0,
errors: [],
}),
}),
],
imports: [
SettingsComponent,
HttpClientTestingModule,
FormsModule,
MockModule(MatSelectModule),
MockModule(MatIconModule),
MockModule(MatTooltipModule),
ReactiveFormsModule,
MockModule(RouterTestingModule),
MockModule(MatCardModule),
MockModule(MatListModule),
MockModule(MatFormFieldModule),
MockModule(MatCheckboxModule),
MockModule(MatDividerModule),
TranslateModule.forRoot(),
],
}).compileComponents();
}));
beforeEach(() => {
window.electron = {
checkEpgFreshness: jest.fn().mockResolvedValue({
freshUrls: [],
staleUrls: [],
}),
clearEpgData: jest.fn().mockResolvedValue({ success: true }),
forceFetchEpg: jest.fn().mockResolvedValue({ success: true }),
getAppVersion: jest.fn().mockResolvedValue('1.0.0'),
getLocalIpAddresses: jest.fn().mockResolvedValue([]),
platform: 'linux',
saveFileDialog: jest.fn().mockResolvedValue('/tmp/backup.json'),
setMpvPlayerPath: jest.fn().mockResolvedValue(undefined),
setVlcPlayerPath: jest.fn().mockResolvedValue(undefined),
updateSettings: jest.fn().mockResolvedValue(undefined),
writeFile: jest.fn().mockResolvedValue({ success: true }),
} as unknown as typeof window.electron;
fixture = TestBed.createComponent(SettingsComponent);
electronService = TestBed.inject(DataService);
settingsStore = TestBed.inject(SettingsStore);
router = TestBed.inject(Router);
translate = TestBed.inject(TranslateService);
epgService = TestBed.inject(EpgService);
dialogService = TestBed.inject(DialogService);
playlistsService = TestBed.inject(PlaylistsService);
playlistBackupService = TestBed.inject(PlaylistBackupService);
store = TestBed.inject(Store);
mockStore = TestBed.inject(MockStore);
databaseService = TestBed.inject(DatabaseService);
snackBar = TestBed.inject(MatSnackBar) as unknown as MatSnackBarStub;
component = fixture.componentInstance;
component.checkAppVersion = jest.fn();
component.fetchLocalIpAddresses = jest
.fn()
.mockResolvedValue(undefined);
fixture.detectChanges();
});
afterEach(() => {
window.electron = originalElectron;
});
function setPlaylists(playlists: PlaylistMeta[]): void {
mockStore.overrideSelector(selectAllPlaylistsMeta, playlists);
mockStore.refreshState();
fixture.detectChanges();
}
it('should create and init component', () => {
expect(component).toBeTruthy();
});
it('should render a compact page header outside dialog mode', () => {
const nativeElement = fixture.nativeElement as HTMLElement;
expect(
nativeElement.querySelector('[data-test-id="settings-page-header"]')
).not.toBeNull();
expect(nativeElement.querySelector('.settings-intro')).toBeNull();
});
it('should not render the page header in dialog mode', () => {
fixture.destroy();
const dialogFixture = TestBed.createComponent(SettingsComponent);
const dialogComponent = dialogFixture.componentInstance;
dialogComponent.checkAppVersion = jest.fn();
dialogComponent.fetchLocalIpAddresses = jest
.fn()
.mockResolvedValue(undefined);
dialogComponent.isDialog = true;
dialogFixture.detectChanges();
const nativeElement = dialogFixture.nativeElement as HTMLElement;
expect(
nativeElement.querySelector('[data-test-id="settings-page-header"]')
).toBeNull();
expect(
nativeElement.querySelector('h2[mat-dialog-title]')
).not.toBeNull();
});
it('should scroll the selected navigation target within the workspace viewport', async () => {
fixture.destroy();
jest.useFakeTimers();
try {
const scrollFixture = TestBed.createComponent(SettingsComponent);
const scrollComponent = scrollFixture.componentInstance;
const settingsContext = TestBed.inject(SettingsContextService);
const originalGetElementById =
document.getElementById.bind(document);
const scrollTo = jest.fn();
const scrollRoot = {
scrollTop: 96,
clientHeight: 885,
scrollHeight: 2469,
getBoundingClientRect: () =>
({
top: 56,
}) as DOMRect,
scrollTo,
} as unknown as HTMLElement;
scrollComponent.checkAppVersion = jest.fn();
scrollComponent.fetchLocalIpAddresses = jest
.fn()
.mockResolvedValue(undefined);
jest.spyOn(scrollComponent as any, 'getScrollRoot').mockReturnValue(
scrollRoot
);
scrollFixture.detectChanges();
const getElementByIdSpy = jest
.spyOn(document, 'getElementById')
.mockImplementation((id: string) => {
if (id === 'about') {
return {
getBoundingClientRect: () =>
({
top: 2050,
height: 159,
}) as DOMRect,
} as HTMLElement;
}
return originalGetElementById(id);
});
await scrollFixture.whenStable();
scrollFixture.detectChanges();
settingsContext.navigateToSection('about');
scrollFixture.detectChanges();
expect(getElementByIdSpy).toHaveBeenCalledWith('about');
expect(scrollTo).toHaveBeenCalledWith({
behavior: 'smooth',
top: 1488,
});
expect(settingsContext.pendingScrollTarget()).toBe('about');
jest.advanceTimersByTime(600);
expect(settingsContext.pendingScrollTarget()).toBeNull();
} finally {
jest.useRealTimers();
}
});
describe('Get and set settings on component init', () => {
const settings = {
language: Language.GERMAN,
player: VideoPlayer.Html5Player,
theme: Theme.DarkTheme,
};
it('should init default settings if previous config was not saved', async () => {
await component.ngOnInit();
//expect(settingsStore.loadSettings).toHaveBeenCalled();
expect(component.settingsForm.value).toEqual(DEFAULT_SETTINGS);
});
it('should get and apply custom settings', async () => {
const mockStore = settingsStore as unknown as MockSettingsStore;
mockStore._setSettings({
...DEFAULT_SETTINGS,
...settings,
});
component.setSettings();
//expect(settingsStore.loadSettings).toHaveBeenCalled();
expect(component.settingsForm.value).toEqual({
...DEFAULT_SETTINGS,
...settings,
});
});
/* it('hides the embedded mpv option when the desktop support probe reports unsupported', async () => {
window.electron = {
...window.electron,
getEmbeddedMpvSupport: jest.fn().mockResolvedValue({
supported: false,
platform: 'darwin',
reason: 'hidden harness',
}),
} as unknown as typeof window.electron;
await component.ngOnInit();
await fixture.whenStable();
expect(
component.players().some(
(player) => player.id === VideoPlayer.EmbeddedMpv
)
).toBe(false);
});
it('shows the embedded mpv option when the desktop support probe reports supported', async () => {
window.electron = {
...window.electron,
getEmbeddedMpvSupport: jest.fn().mockResolvedValue({
supported: true,
platform: 'darwin',
}),
} as unknown as typeof window.electron;
await component.ngOnInit();
await fixture.whenStable();
expect(
component.players().some(
(player) => player.id === VideoPlayer.EmbeddedMpv
)
).toBe(true);
});
it('does not block settings initialization while embedded mpv support is pending', async () => {
let resolveSupport: (value: EmbeddedMpvSupport) => void;
window.electron = {
...window.electron,
getEmbeddedMpvSupport: jest.fn(
() =>
new Promise((resolve) => {
resolveSupport = resolve;
})
),
} as unknown as typeof window.electron;
await expect(component.ngOnInit()).resolves.toBeUndefined();
expect(component.settingsForm.value).toEqual(DEFAULT_SETTINGS);
expect(window.electron.getEmbeddedMpvSupport).toHaveBeenCalled();
expect(
component.players().some(
(player) => player.id === VideoPlayer.EmbeddedMpv
)
).toBe(false);
resolveSupport!({
supported: true,
platform: 'darwin',
});
await fixture.whenStable();
expect(
component.players().some(
(player) => player.id === VideoPlayer.EmbeddedMpv
)
).toBe(true);
}); */
});
describe('Version check', () => {
const latestVersion = '1.0.0';
const currentVersion = '0.1.0';
beforeEach(() => {
const settingsService = TestBed.inject(SettingsService);
(settingsService.getAppVersion as jest.Mock).mockReturnValue(
of(latestVersion)
);
// Add translation mock
jest.spyOn(translate, 'instant').mockImplementation((key) => {
if (key === 'SETTINGS.NEW_VERSION_AVAILABLE') {
return 'New version available';
}
if (key === 'SETTINGS.LATEST_VERSION') {
return 'Latest version installed';
}
return key;
});
});
it('should return true if version is outdated', () => {
jest.spyOn(electronService, 'getAppVersion').mockReturnValue(
currentVersion
);
const isOutdated =
component.isCurrentVersionOutdated(latestVersion);
expect(isOutdated).toBeTruthy();
});
it('should update notification message if version is outdated', () => {
jest.spyOn(translate, 'instant');
jest.spyOn(electronService, 'getAppVersion').mockReturnValue(
currentVersion
);
component.showVersionInformation(latestVersion);
expect(translate.instant).toHaveBeenCalledWith(
'SETTINGS.NEW_VERSION_AVAILABLE'
);
expect(component.updateMessage).toBe(
'New version available: 1.0.0'
);
});
});
it('disables the global wipe action when there are no playlists', () => {
setPlaylists([]);
const deleteButton = (
fixture.nativeElement as HTMLElement
).querySelector('.danger-zone__button') as HTMLButtonElement | null;
expect(component.canRemoveAllPlaylists()).toBe(false);
expect(deleteButton?.disabled).toBe(true);
});
it('opens the dedicated delete-all dialog with the current playlist type summary', () => {
setPlaylists([
createPlaylistMeta({ _id: 'm3u-1' }),
createPlaylistMeta({
_id: 'xtream-1',
serverUrl: 'http://xtream.example',
}),
createPlaylistMeta({
_id: 'stalker-1',
macAddress: '00:11:22:33:44:55',
}),
]);
const openSpy = jest
.spyOn((component as any).matDialog, 'open')
.mockReturnValue({
afterClosed: () => of(false),
} as any);
component.removeAll();
expect(component.playlistDeleteSummary()).toEqual({
total: 3,
m3u: 1,
xtream: 1,
stalker: 1,
});
expect(openSpy).toHaveBeenCalledWith(
expect.any(Function),
expect.objectContaining({
data: {
summary: {
total: 3,
m3u: 1,
xtream: 1,
stalker: 1,
},
},
})
);
});
it('tracks Electron delete-all progress and dispatches store cleanup after success', async () => {
setPlaylists([
createPlaylistMeta({ _id: 'm3u-1' }),
createPlaylistMeta({
_id: 'xtream-1',
serverUrl: 'http://xtream.example',
}),
]);
const dispatchSpy = jest.spyOn(store, 'dispatch');
(databaseService.deleteAllPlaylists as jest.Mock).mockClear();
jest.spyOn((component as any).matDialog, 'open').mockReturnValue({
afterClosed: () => of(true),
} as any);
jest.spyOn(translate, 'instant').mockImplementation(
(key: string, params?: Record<string, number>) => {
if (key === 'SETTINGS.REMOVE_ALL_PROGRESS') {
return `${params?.current}/${params?.total}`;
}
return key;
}
);
jest.spyOn(
component as any,
'waitForUiFeedbackFrame'
).mockResolvedValue(undefined);
let resolveDelete: (value: boolean) => void = () => undefined;
(databaseService.deleteAllPlaylists as jest.Mock).mockImplementation(
({
onEvent,
}: {
onEvent?: (event: {
operation: string;
status: string;
current?: number;
total?: number;
}) => void;
}) => {
onEvent?.({
operation: 'delete-all-playlists',
status: 'progress',
current: 3,
total: 7,
});
return new Promise<boolean>((resolve) => {
resolveDelete = resolve;
});
}
);
component.removeAll();
await Promise.resolve();
fixture.detectChanges();
expect(component.isRemovingAllPlaylists()).toBe(true);
expect(component.removeAllProgressLabel()).toBe('3/7');
expect(databaseService.deleteAllPlaylists).toHaveBeenCalledWith(
expect.objectContaining({
operationId: 'delete-all-op',
onEvent: expect.any(Function),
})
);
resolveDelete(true);
await fixture.whenStable();
expect(component.isRemovingAllPlaylists()).toBe(false);
expect(component.removeAllProgress()).toBeNull();
expect(dispatchSpy).toHaveBeenCalledWith(
PlaylistActions.removeAllPlaylists()
);
expect(snackBar.open).toHaveBeenCalledWith(
'SETTINGS.PLAYLISTS_REMOVED',
undefined,
{
duration: 2000,
horizontalPosition: 'center',
panelClass: ['settings-snackbar'],
verticalPosition: 'bottom',
}
);
});
it('falls back to PlaylistsService.removeAll outside Electron', async () => {
fixture.destroy();
window.electron = undefined as unknown as typeof window.electron;
const browserFixture = TestBed.createComponent(SettingsComponent);
const browserComponent = browserFixture.componentInstance;
browserComponent.checkAppVersion = jest.fn();
browserComponent.fetchLocalIpAddresses = jest
.fn()
.mockResolvedValue(undefined);
browserFixture.detectChanges();
mockStore.overrideSelector(selectAllPlaylistsMeta, [
createPlaylistMeta({ _id: 'browser-m3u' }),
]);
mockStore.refreshState();
browserFixture.detectChanges();
jest.spyOn((browserComponent as any).matDialog, 'open').mockReturnValue(
{
afterClosed: () => of(true),
} as any
);
jest.spyOn(
browserComponent as any,
'waitForUiFeedbackFrame'
).mockResolvedValue(undefined);
(databaseService.deleteAllPlaylists as jest.Mock).mockClear();
(playlistsService.removeAll as jest.Mock).mockClear();
(playlistsService.removeAll as jest.Mock).mockReturnValue(
of(undefined)
);
const dispatchSpy = jest.spyOn(store, 'dispatch');
browserComponent.removeAll();
await browserFixture.whenStable();
expect(playlistsService.removeAll).toHaveBeenCalled();
expect(databaseService.deleteAllPlaylists).not.toHaveBeenCalled();
expect(dispatchSpy).toHaveBeenCalledWith(
PlaylistActions.removeAllPlaylists()
);
});
it('shows the save confirmation snackbar at the bottom center with the settings offset class', () => {
jest.spyOn(translate, 'instant').mockReturnValue('Settings saved');
component.applyChangedSettings();
expect(snackBar.open).toHaveBeenCalledWith(
'Settings saved',
undefined,
{
duration: 2000,
horizontalPosition: 'center',
panelClass: ['settings-snackbar'],
verticalPosition: 'bottom',
}
);
});
it('should force-fetch EPG for a single URL (bypassing freshness cache)', () => {
const url = 'http://epg-url-here/data.xml';
component.refreshEpg(url);
expect(window.electron.forceFetchEpg).toHaveBeenCalledWith(url);
});
it('clears EPG data with a busy state and refreshes all sources on success', async () => {
let resolveClear: () => void = () => undefined;
const clearPromise = new Promise<{ success: boolean }>((resolve) => {
resolveClear = () => resolve({ success: true });
});
(window.electron.clearEpgData as jest.Mock).mockReturnValue(
clearPromise
);
(dialogService.openConfirmDialog as jest.Mock).mockImplementation(
({ onConfirm }: { onConfirm: () => Promise<void> }) => {
void onConfirm();
}
);
const refreshSpy = jest.spyOn(component, 'refreshAllEpg');
jest.spyOn(translate, 'instant').mockImplementation((key) => key);
component.clearEpgData();
expect(component.isClearingEpgData()).toBe(true);
expect(refreshSpy).not.toHaveBeenCalled();
resolveClear();
await fixture.whenStable();
expect(component.isClearingEpgData()).toBe(false);
expect(snackBar.open).toHaveBeenCalledWith(
'SETTINGS.EPG_DATA_CLEARED',
undefined,
expect.objectContaining({ panelClass: ['settings-snackbar'] })
);
expect(refreshSpy).toHaveBeenCalled();
});
it('shows an export busy state until the backup file has been written', async () => {
let resolveExport: (value: {
defaultFileName: string;
json: string;
manifest: {
kind: string;
version: number;
exportedAt: string;
includeSecrets: boolean;
playlists: never[];
};
}) => void = () => undefined;
(playlistBackupService.exportBackup as jest.Mock).mockReturnValueOnce(
new Promise((resolve) => {
resolveExport = resolve;
})
);
const exportPromise = component.exportData();
expect(component.isExportingData()).toBe(true);
resolveExport({
defaultFileName: 'iptvnator-playlist-backup-2026-04-21.json',
json: '{}',
manifest: {
kind: 'iptvnator-playlist-backup',
version: 1,
exportedAt: '2026-04-21T00:00:00.000Z',
includeSecrets: true,
playlists: [],
},
});
await exportPromise;
expect(window.electron.saveFileDialog).toHaveBeenCalledWith(
'iptvnator-playlist-backup-2026-04-21.json',
[
{
extensions: ['json'],
name: 'JSON',
},
]
);
expect(window.electron.writeFile).toHaveBeenCalledWith(
'/tmp/backup.json',
'{}'
);
expect(component.isExportingData()).toBe(false);
});
it('shows a failure snackbar and skips refresh when clearing EPG data rejects', async () => {
(window.electron.clearEpgData as jest.Mock).mockRejectedValueOnce(
new Error('boom')
);
(dialogService.openConfirmDialog as jest.Mock).mockImplementation(
({ onConfirm }: { onConfirm: () => Promise<void> }) => {
void onConfirm();
}
);
const refreshSpy = jest.spyOn(component, 'refreshAllEpg');
jest.spyOn(translate, 'instant').mockImplementation((key) => key);
jest.spyOn(console, 'error').mockImplementation();
component.clearEpgData();
await fixture.whenStable();
expect(component.isClearingEpgData()).toBe(false);
expect(snackBar.open).toHaveBeenCalledWith(
'SETTINGS.EPG_DATA_CLEAR_FAILED',
undefined,
expect.objectContaining({ panelClass: ['settings-snackbar'] })
);
expect(refreshSpy).not.toHaveBeenCalled();
});
it('should navigate back to home page', () => {
jest.spyOn(router, 'navigateByUrl');
component.backToHome();
expect(router.navigateByUrl).toHaveBeenCalledWith('/');
});
it('should update the selected theme and mark the form dirty', () => {
component.selectTheme(Theme.DarkTheme);
expect(component.settingsForm.value.theme).toBe(Theme.DarkTheme);
expect(component.settingsForm.dirty).toBeTruthy();
});
it('renders workspace startup controls with the expected defaults', () => {
const nativeElement = fixture.nativeElement as HTMLElement;
expect(
nativeElement.querySelector(
'[data-test-id="toggle-show-dashboard"]'
)
).not.toBeNull();
expect(component.settingsForm.value.showDashboard).toBe(true);
expect(component.settingsForm.value.startupBehavior).toBe(
StartupBehavior.FirstView
);
});
it('should save settings on submit', async () => {
const mockStore = settingsStore as unknown as MockSettingsStore;
mockStore.updateSettings.mockResolvedValue(undefined);
const updateSettings = jest.spyOn(window.electron, 'updateSettings');
component.onSubmit();
await fixture.whenStable();
expect(mockStore.updateSettings).toHaveBeenCalledWith(
component.settingsForm.value
);
expect(updateSettings).toHaveBeenCalledWith(
component.settingsForm.value
);
});
});
File diff suppressed because it is too large Load Diff
View File
+428
View File
@@ -0,0 +1,428 @@
{
"CLOSE": "إغلاق",
"PLAYLISTS": "قوائم التشغيل",
"HOME": {
"TITLE": "IPTVnator",
"SUBTITLE": "يرجى اختيار قائمة تشغيل من القائمة أو إضافة قائمة جديدة",
"TABS": {
"RECENTLY_ADDED": "قوائم التشغيل المضافة مؤخرًا",
"FILE_UPLOAD": "إضافة عبر تحميل ملف",
"URL_UPLOAD": "إضافة عبر رابط URL",
"TEXT_IMPORT": "استيراد من نص",
"XTREME_IMPORT": "إضافة Xtreme Code",
"STALKER_PORTAL_IMPORT": "إضافة Stalker Portal"
},
"PLAYLISTS": {
"NO_PLAYLISTS": "لم تُضف أي قوائم تشغيل",
"ADD_FIRST": "يرجى إضافة أول قائمة تشغيل",
"WELCOME_TITLE": "مرحبًا بك في IPTVnator",
"WELCOME_DESCRIPTION": "ابدأ رحلة البث بإضافة قائمة التشغيل الأولى. اتصل بخدمة IPTV المفضلة لديك واستمتع بالتلفزيون المباشر والأفلام والمسلسلات.",
"ADD_YOUR_FIRST": "أضف قائمة التشغيل الأولى",
"FEATURE_M3U": "ملفات M3U/M3U8",
"FEATURE_XTREAM": "Xtream Codes",
"FEATURE_STALKER": "بوابة Stalker",
"NO_RESULTS_TITLE": "لم يتم العثور على قوائم تشغيل",
"NO_RESULTS_DESCRIPTION": "لا توجد قوائم تشغيل تطابق بحثك. حاول تعديل مصطلحات البحث أو امسح الفلتر لرؤية جميع القوائم.",
"ADDED_VIA_URL": "تمت الإضافة عبر رابط URL. الرابط:",
"ADDED_VIA_FILE": "تمت الإضافة عبر تحميل ملف",
"XTREAM_PLAYLIST": "قائمة تشغيل Xtream",
"STALKER_PORTAL": "بوابة Stalker",
"CHANNELS": "القنوات",
"ADDED": "تمت الإضافة",
"SHOW_DETAILS": "عرض تفاصيل القائمة",
"REMOVE": "حذف القائمة",
"SEARCH_PLAYLISTS": "البحث عن قوائم التشغيل حسب العنوان",
"INFO_DIALOG": {
"PLAYLIST_DETAILS": "تفاصيل قائمة التشغيل",
"TITLE": "العنوان",
"FROM_URL": "تمت الإضافة من الرابط",
"IMPORT_DATE": "تاريخ الاستيراد",
"CHANNELS": "عدد القنوات",
"CLOSE": "إغلاق",
"SAVE": "حفظ",
"USER_AGENT": "وكيل المستخدم",
"ORIGINAL_FILENAME": "اسم الملف الأصلي",
"FILE_PATH": "مسار الملف",
"UPDATE_FAILED": "فشل تحديث القائمة الأخيرة",
"AUTO_UPDATE": "التحديث التلقائي",
"AUTO_UPDATE_DESCRIPTION": "إذا تم تفعيل التحديث التلقائي، ستُحدَّث القائمة تلقائيًا عند كل تشغيل للتطبيق.",
"CUSTOM_USER_AGENT": "قد تتطلب بعض خدمات IPTV وكيل مستخدم محدد لتشغيل قوائم التشغيل.",
"EXPORT_PLAYLIST": "تصدير القائمة كملف M3U",
"SERVER_URL": "رابط الخادم",
"USERNAME": "اسم المستخدم",
"PASSWORD": "كلمة المرور",
"MAC_ADDRESS": "عنوان MAC",
"PLAYLIST_EXPORT_SUCCESS": "تم تصدير القائمة بنجاح.",
"PLAYLIST_EXPORT_ERROR": "خطأ: فشل تصدير القائمة."
},
"REMOVE_DIALOG": {
"TITLE": "حذف القائمة",
"MESSAGE": "هل أنت متأكد من رغبتك في حذف هذه القائمة نهائيًا؟",
"SUCCESS": "تم حذف القائمة بنجاح"
},
"UPDATED": "تم التحديث",
"REFRESH": "تحديث القائمة",
"GLOBAL_FAVORITES": "المفضلة العامة",
"GLOBAL_FAVORITES_DESCRIPTION": "قائمة تلقائية تجمع القنوات المفضلة من جميع القوائم",
"MY_PLAYLISTS": "قوائم التشغيل الخاصة بي",
"MY_PLAYLISTS_SUBTITLE": "جميع القوائم المتاحة",
"PLAYLIST_UPDATE_SUCCESS": "نجاح! تم تحديث القائمة.",
"PLAYLIST_UPDATE_ERROR": "خطأ في تحديث تفاصيل القائمة.",
"FEATURE_M3U_LABEL": "Add an M3U file or URL",
"FEATURE_XTREAM_LABEL": "Connect via Xtream Codes",
"FEATURE_STALKER_LABEL": "Connect to a Stalker portal",
"VALUE_PROPS_LABEL": "What you can do",
"VALUE_PROP_LIVE": "Live TV with EPG",
"VALUE_PROP_VOD": "Movies & Series",
"VALUE_PROP_MULTISOURCE": "Multi-source library",
"VALUE_PROP_OFFLINE": "Offline downloads",
"DASHBOARD_WELCOME_TAGLINE": "Your IPTV library, in one place.",
"FEATURE_LIVE_TITLE": "Live TV",
"FEATURE_LIVE_DESC": "Stream live channels with full schedule.",
"FEATURE_VOD_TITLE": "Movies & Series",
"FEATURE_VOD_DESC": "On-demand library with covers and details.",
"FEATURE_EPG_TITLE": "EPG & Catch-up",
"FEATURE_EPG_DESC": "Program guide and time-shifted playback.",
"FEATURE_OFFLINE_TITLE": "Offline downloads",
"FEATURE_OFFLINE_DESC": "Save movies and episodes for later.",
"SOURCES_WELCOME_TITLE": "Add your first playlist",
"SOURCES_WELCOME_BODY": "Pick a source type below to get started.",
"SOURCE_M3U_NEEDS": "Local file or URL pointing to an M3U/M3U8 playlist.",
"SOURCE_M3U_ADD": "Add M3U",
"SOURCE_XTREAM_NEEDS": "Username, password and server URL from your provider.",
"SOURCE_XTREAM_ADD": "Add Xtream",
"SOURCE_STALKER_NEEDS": "Portal URL and MAC address (Ministra-compatible).",
"SOURCE_STALKER_ADD": "Add Stalker",
"CONTENT_LIVE": "Live",
"CONTENT_VOD": "Movies",
"CONTENT_SERIES": "Series",
"CONTENT_EPG": "EPG",
"DASHBOARD_WELCOME_DESCRIPTION": "Connect M3U files, Xtream Codes, or Stalker portals — then enjoy live TV, movies and series on every screen."
},
"FILE_UPLOAD": {
"DRAG_DROP": "اسحب وأفلت الملفات هنا",
"OR": "أو",
"CHOOSE_PLAYLIST": "اختر قائمة تشغيل",
"REJECTED": "تم رفض الملف، تنسيق غير مدعوم {{filename}}."
},
"URL_UPLOAD": {
"PLAYLIST_URL": "رابط قائمة التشغيل (M3U/M3U8)",
"ADD_PLAYLIST": "إضافة القائمة",
"CORS_NOTE": "ملاحظة: لتجنب مشاكل CORS، يستخدم التطبيق خدمة بروكسي عامة. يُنصح باستيراد القوائم الحساسة عبر الملفات."
},
"TEXT_IMPORT": {
"LABEL": "إدراج قائمة تشغيل M3U(8) كنص",
"BUTTON_LABEL": "استيراد"
},
"XTREAM_PLAYLIST": {
"TITLE": "عنوان القائمة",
"SERVER_URL": "رابط الخادم",
"USERNAME": "اسم المستخدم",
"PASSWORD": "كلمة المرور",
"ADD": "إضافة",
"TEST_CREDENTIALS": "اختبار بيانات الاعتماد",
"URL_VALIDATION_ERROR": "يجب أن يكون الرابط صالحًا مع بروتوكول (مثال: http://example.com)"
},
"STALKER_PORTAL": {
"TITLE": "العنوان",
"MAC_ADDRESS": "عنوان MAC",
"SERVER_URL": "رابط الخادم",
"URL_VALIDATION_ERROR": "يجب أن يكون الرابط صالحًا مع بروتوكول (مثال: http://example.com/stalker_portal)",
"ADD": "إضافة"
},
"FILTER_BY_NAME": "التصفية حسب الاسم",
"FILTER_BY_TYPE": "التصفية حسب النوع",
"SORT_PLAYLISTS": "فرز القوائم",
"SORT_BY": "ترتيب حسب",
"SORT_OPTIONS": {
"NAME_ASC": "الاسم (أ-ي)",
"NAME_DESC": "الاسم (ي-أ)",
"NEWEST": "تاريخ الإضافة (الأحدث أولاً)",
"OLDEST": "تاريخ الإضافة (الأقدم أولاً)"
},
"IMPORTED_AS_TEXT": "مستوردة كنص",
"PARSING_ERROR": "خطأ: فشل التحليل، ليست قائمة تشغيل صالحة:"
},
"SETTINGS": {
"TITLE": "الإعدادات",
"SUBTITLE": "تعديل تكوين التطبيق",
"DESCRIPTION": "يرجى ضبط الخيارات أدناه ثم النقر على حفظ التغييرات",
"EPG_URL_LABEL": "رابط EPG (XML/XML.GZ)",
"EPG_URL_PLACEHOLDER": "أدخل رابطًا",
"REFRESH_EPG": "تحديث EPG",
"REFRESH_ALL_EPG": "تحديث الكل",
"REMOVE_EPG_SOURCE": "إزالة مصدر EPG",
"EPG_STATUS_FRESH": "محدث",
"EPG_STATUS_STALE": "يحتاج تحديث",
"EPG_STATUS_ERROR": "فشل",
"VIDEO_PLAYER_LABEL": "مشغل الفيديو",
"VIDEO_PLAYER_PLACEHOLDER": "اختر خيارًا",
"VERSION": "الإصدار",
"SAVE_CHANGES": "حفظ التغييرات",
"BACK_TO_HOME": "العودة للرئيسية",
"NEW_VERSION_AVAILABLE": "إصدار جديد متاح",
"LATEST_VERSION": "أنت تستخدم الإصدار الأحدث",
"LANGUAGE": "اللغة",
"SETTINGS_SAVED": "نجاح! تم حفظ الإعدادات.",
"THEME": "السمة البصرية",
"SHOW_CAPTIONS": "عرض الترجمات",
"ADD_EPG_SOURCE": "إضافة مصدر EPG",
"EPG_URL_ERROR": "القيمة ليست رابطًا صالحًا",
"VIDEO_PLAYER_DESCRIPTION": "اختر مشغل الفيديو الافتراضي",
"LANGUAGE_DESCRIPTION": "اختر لغة التطبيق",
"THEME_DESCRIPTION": "اختر السمة البصرية للتطبيق",
"SHOW_CAPTIONS_DESCRIPTION": "عرض أو إخفاء الترجمات افتراضيًا",
"VERSION_DESCRIPTION": "الإصدار الحالي للتطبيق",
"EPG_NOTE": "الـ EPG متاح فقط في نسخة Electron من التطبيق.",
"EPG_NOTE_URL_TEXT": "تحقق من هنا",
"IMPORT_EXPORT_DATA": "استيراد/تصدير القوائم",
"IMPORT_EXPORT_DATA_DESCRIPTION": "تصدير أو استيراد القوائم بتنسيق JSON.",
"IMPORT_DATA": "استيراد",
"EXPORT_DATA": "تصدير",
"REMOVE_ALL": "Delete all playlists and playlist data",
"REMOVE_ALL_BUTTON": "Delete all",
"REMOVE_ALL_DESCRIPTION": "Delete every M3U, Xtream, and Stalker playlist stored in the app.",
"REMOVE_DIALOG": {
"TITLE": "Delete all playlists?",
"MESSAGE": "Delete all {{count}} playlists from the app. This also removes stored playlist data on this device.",
"SUMMARY_TITLE": "Playlist sources",
"CONSEQUENCES_TITLE": "This also removes",
"CONSEQUENCE_FAVORITES": "Favorites saved for these playlists",
"CONSEQUENCE_RECENTLY_VIEWED": "Recently viewed history",
"CONSEQUENCE_PLAYBACK": "Saved playback positions",
"CONSEQUENCE_DOWNLOADS": "Download history entries linked to those playlists",
"CONSEQUENCE_XTREAM_CACHE": "Imported Xtream categories and locally cached content",
"BACKUP_HINT": "Use Export first if you want a restorable backup before deleting.",
"CONFIRM": "Delete everything"
},
"IMPORT_ERROR": "خطأ في الاستيراد، يرجى تجربة ملف آخر.",
"PLAYLISTS_REMOVED": "All playlists and playlist data were removed.",
"MPV_PLAYER_PATH_LABEL": "مسار مشغل MPV",
"MPV_PLAYER_PATH_DESCRIPTION": "حدد مسار مشغل MPV في نظامك.",
"MPV_PLAYER_PATH": "مسار مشغل MPV",
"VLC_PLAYER_PATH_LABEL": "مسار VLC",
"VLC_PLAYER_PATH_DESCRIPTION": "حدد مسار مشغل VLC في نظامك.",
"VLC_PLAYER_PATH": "مسار مشغل VLC",
"REMOTE_CONTROL": "التحكم عن بعد",
"REMOTE_CONTROL_DESCRIPTION": "تمكين التحكم عن بعد للتطبيق.",
"REMOTE_CONTROL_PORT": "منفذ التحكم عن بعد",
"REMOTE_CONTROL_PORT_DESCRIPTION": "المنفذ المستخدم للتحكم عن بعد (الافتراضي: 8765).",
"REMOVE_ALL_IN_PROGRESS": "Deleting playlist data…",
"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.",
"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": "السمة الداكنة",
"LIGHT_THEME": "السمة الفاتحة",
"SYSTEM_THEME": "سمة النظام"
},
"CHANNELS": {
"SEARCH_CHANNEL": "البحث عن قناة",
"UPLOAD_OR_SELECT_OTHER_PLAYLIST": "تحميل أو اختيار قائمة أخرى",
"ALL_CHANNELS": "جميع القنوات",
"GROUPS": "المجموعات",
"UNGROUPED": "غير مصنفة",
"UNNAMED_CHANNEL": "قناة بدون اسم",
"FAVORITES": "المفضلة",
"NO_FAVORITES": "لا توجد قنوات مفضلة",
"USE_STAR_TO_FAVORITE": "استخدم أيقونة النجمة لإضافة قنوات للمفضلة.",
"REMOVE_FAVORITE": "إزالة من المفضلة",
"FAVORITES_UPDATED": "تم تحديث المفضلة!",
"SORT_BY": "ترتيب حسب",
"SORT_BY_DATE": "تاريخ الإضافة (الأحدث أولاً)",
"SORT_BY_RATING": "التقييم",
"SORT_BY_NAME": "الاسم (أ-ي)"
},
"TOP_MENU": {
"OPEN_CHANNELS_LIST": "فتح قائمة القنوات",
"TOGGLE_FAVORITE_FLAG": "تبديل حالة المفضلة",
"OPEN_EPG_LIST": "فتح قائمة EPG",
"OPEN_MULTI_EPG": "فتح عرض Multi-EPG"
},
"EPG": {
"TITLE": "الدليل الإلكتروني للبرامج",
"NEXT_DAY": "اليوم التالي",
"PREVIOUS_DAY": "اليوم السابق",
"LIVE_NOW": "يُبث الآن",
"LIVE_STREAM": "بث مباشر",
"TIMESHIFT_AVAILABLE": "التحريك الزمني متاح، انقر للتشغيل",
"EPG_NOT_AVAILABLE_DATE": "عذراً، الدليل غير متاح لهذا التاريخ",
"EPG_NOT_AVAILABLE_CHANNEL_TITLE": "عذراً، الدليل غير متاح لهذه القناة",
"EPG_NOT_AVAILABLE_CHANNEL_DESCRIPTION": "يرجى إضافة/تعديل رابط EPG في إعدادات التطبيق.",
"FETCH_EPG": "جارٍ جلب بيانات EPG...",
"ERROR": "عذراً، فشل تحميل الدليل.",
"DOWNLOAD_SUCCESS": "تم تنزيل الدليل بنجاح.",
"PROGRAM_DIALOG": {
"PROGRAM_DETAILS": "تفاصيل البرنامج",
"TITLE": "العنوان",
"CATEGORY": "الفئة",
"PARENTAL_RATING_SYSTEM": "نظام تقييم المحتوى",
"DESCRIPTION": "الوصف",
"LANGUAGE": "اللغة",
"SHOW_PROGRAM_DETAILS": "عرض تفاصيل البرنامج"
},
"FETCH_SUCCESS": "تم جلب الدليل بنجاح."
},
"LANGUAGES": {
"ARABIC": "العربية",
"MOROCCAN_ARABIC": "العربية (اللهجة المغربية)",
"ENGLISH": "English",
"KOREAN": "한국어",
"RUSSIAN": "Русский",
"GERMAN": "Deutsch",
"SPANISH": "Español",
"CHINESE": "简体中文",
"TRADITIONAL_CHINESE": "繁體中文",
"FRENCH": "Français",
"ITALIAN": "Italiano",
"TURKISH": "Türkçe",
"JAPANESE": "日本語",
"DUTCH": "Nederlands",
"BELARUSIAN": "Беларуская",
"POLISH": "Polski",
"PORTUGUESE": "Português",
"GREEK": "Ελληνικά"
},
"YES": "نعم",
"NO": "لا",
"MENU": {
"OPEN": "فتح القائمة",
"SUPPORT_ARIA": "دعم IPTVnator على GitHub",
"SETTINGS": "الإعدادات",
"SETTINGS_ARIA": "فتح الإعدادات",
"BUG_REPORT": "ابلاغ عن خلل",
"WHAT_IS_NEW": "ما الجديد",
"ABOUT": "حول",
"ABOUT_ARIA": "حول التطبيق",
"SUPPORT_PROJECT": "دعم المشروع"
},
"ABOUT": {
"TITLE": "حول IPTVnator",
"DESCRIPTION": "تطبيق مشغل IPTV متعدد المنصات مع ميزات مثل دعم قوائم M3U/M3U8، المفضلة، الدليل التلفزيوني، الأرشيف، والمزيد.",
"VERSION": "الإصدار",
"GITHUB_TOOLTIP": "مستودع IPTVnator على GitHub",
"BUY_ME_A_COFFEE_TOOLTIP": "اشتري لي قهوة",
"TWITTER_TOOLTIP": "مشاركة على تويتر"
},
"UPDATE_AVAILABLE": "تحديث متاح",
"REFRESH": "تحديث",
"XTREAM": {
"PLAY": "تشغيل",
"NAME": "الاسم",
"RELEASE_DATE": "تاريخ الإصدار",
"GENRE": "النوع",
"COUNTRY": "البلد",
"ACTORS": "الممثلون",
"DIRECTOR": "المخرج",
"DURATION": "المدة",
"CAST": "طاقم العمل",
"EPISODE_RUN_TIME": "مدة الحلقة",
"RATING": "التقييم",
"IMDB_RATING": "تقييم IMDB",
"KINOPOISK_RATING": "تقييم Kinopoisk",
"DESCRIPTION": "الوصف",
"YEAR": "السنة",
"AGE": "العمر",
"YOUTUBE_TRAILER": "تريلر يوتيوب",
"EPISODE": "الحلقة"
},
"PORTALS": {
"ALL_CATEGORIES": "جميع الفئات",
"MY_FAVORITES": "المفضلة",
"ADD_TO_FAVORITES": "إضافة للمفضلة",
"REMOVE_FROM_FAVORITES": "إزالة من المفضلة",
"REMOVED_FROM_FAVORITES": "تمت الإزالة من المفضلة",
"ADDED_TO_FAVORITES": "تمت الإضافة للمفضلة",
"ERROR_VIEW": {
"ACCOUNT_EXPIRED": {
"TITLE": "انتهاء صلاحية الحساب",
"DESCRIPTION": "انتهت صلاحية هذا الحساب. يرجى التحقق من بيانات الاعتماد في إعدادات القائمة أو حذفها."
},
"UNAUTHORIZED": {
"TITLE": "غير مصرح",
"DESCRIPTION": "يرجى التحقق من بيانات الاعتماد في إعدادات القائمة أو حذفها."
},
"NOT_FOUND": {
"TITLE": "البوابة غير موجودة",
"DESCRIPTION": "يرجى التحقق من بيانات الاعتماد ورابط البوابة في إعدادات القائمة أو حذفها."
},
"EMPTY_CATEGORY": {
"TITLE": "فئة فارغة",
"DESCRIPTION": "هذه الفئة لا تحتوي على محتوى، يرجى اختيار فئة أخرى أو تغيير نوع المحتوى."
},
"UNKNOWN_ERROR": {
"TITLE": "حدث خطأ",
"DESCRIPTION": "خطأ غير معروف، يرجى المحاولة لاحقًا."
},
"PLAYLIST_SETTINGS": "إعدادات القائمة",
"HOME": "الرئيسية",
"DELETE": "حذف"
},
"EMPTY_LIST_VIEW": {
"NO_SEARCH_RESULTS": "لم يتم العثور على نتائج، حاول تغيير طلب البحث"
},
"STREAM_URL_COPIED": "تم نسخ رابط البث إلى الحافظة",
"COPY_STREAM_URL": "نسخ رابط البث",
"SEARCH_VIEW": {
"RESULTS_FOUND": "تم العثور على {{count}} نتيجة",
"NO_RESULTS_FOR": "لم يتم العثور على نتائج لـ \"{{term}}\""
}
},
"INFORMATION": "معلومات",
"REMOTE_CONTROL": {
"TITLE": "التحكم عن بعد",
"UP_CHANNEL": "القناة السابقة",
"DOWN_CHANNEL": "القناة التالية",
"HEADER": "التحكم عن بعد في IPTVNator",
"FOOTER": "التحكم عن بعد في IPTVNator"
},
"WORKSPACE": {
"SHELL": {
"GO_TO_DASHBOARD": "Back to dashboard",
"GO_TO_SOURCES": "Go to Sources",
"DROP_OVERLAY_TITLE": "Drop to add playlist",
"DROP_OVERLAY_BODY": "Release an .m3u or .m3u8 file anywhere in the workspace to import it.",
"DROP_OVERLAY_REJECTED_BODY": "Please drop an .m3u or .m3u8 file. Press Esc to dismiss.",
"DROP_OVERLAY_REJECTED_UNSUPPORTED": "Unsupported file type",
"DROP_OVERLAY_REJECTED_EMPTY": "That file is empty",
"DROP_OVERLAY_REJECTED_READ_ERROR": "Could not read that file",
"DROP_IMPORT_SUCCESS": "Importing \"{{title}}\"…",
"COMMANDS": {
"ADD_PLAYLIST_M3U_LABEL": "Add M3U playlist",
"ADD_PLAYLIST_M3U_DESCRIPTION": "Open add dialog on the M3U file or URL tab",
"ADD_PLAYLIST_XTREAM_LABEL": "Add Xtream Codes playlist",
"ADD_PLAYLIST_XTREAM_DESCRIPTION": "Open add dialog on the Xtream Codes tab",
"ADD_PLAYLIST_STALKER_LABEL": "Add Stalker portal",
"ADD_PLAYLIST_STALKER_DESCRIPTION": "Open add dialog on the Stalker Portal tab"
},
"EXTERNAL_PLAYBACK_CLOSE": "Close player"
},
"GLOBAL_FAVORITES": {
"NO_PLAYLISTS_TITLE": "No favorites to show",
"NO_PLAYLISTS_BODY": "Add a playlist to start collecting favorites from live channels, movies, and series.",
"NO_ITEMS_TITLE": "No favorites yet",
"NO_ITEMS_BODY": "Tap the star icon on any channel, movie, or series to save it here."
},
"GLOBAL_RECENT": {
"NO_PLAYLISTS_TITLE": "Nothing watched yet",
"NO_PLAYLISTS_BODY": "Add a playlist and your watching history will appear here.",
"NO_ITEMS_TITLE": "Nothing watched yet",
"NO_ITEMS_BODY": "Start watching anything from your library and it will show up here."
}
},
"DOWNLOADS": {
"NO_PLAYLISTS_TITLE": "Add a playlist to start downloading",
"NO_PLAYLISTS_BODY": "Once you add a playlist, you can save movies and episodes here for offline playback.",
"NO_ITEMS_BODY": "Use the download button on any movie or episode to save it for offline playback.",
"NO_FILTER_MATCH": "No downloads match the current filter",
"NO_FILTER_MATCH_HINT": "Try a different search term"
}
}
+420
View File
@@ -0,0 +1,420 @@
{
"CLOSE": "سد",
"PLAYLISTS": "قوائم التشغيل",
"HOME": {
"TITLE": "IPTVnator",
"SUBTITLE": "عفاك اختار شي قائمة تشغيل من الليستا ولا زيد قائمة جديدة",
"TABS": {
"RECENTLY_ADDED": "قوائم التشغيل اللي تزادو مؤخراً",
"FILE_UPLOAD": "زيد عن طريق رفع ملف",
"URL_UPLOAD": "زيد عن طريق رابط",
"TEXT_IMPORT": "استورد من نص",
"XTREME_IMPORT": "زيد كود Xtreme",
"STALKER_PORTAL_IMPORT": "زيد بوابة Stalker"
},
"PLAYLISTS": {
"NO_PLAYLISTS": "ما تزادت حتى شي قائمة تشغيل",
"ADD_FIRST": "عفاك زيد قائمة التشغيل الأولى ديالك",
"ADDED_VIA_URL": "تزادت عن طريق رابط. رابط:",
"ADDED_VIA_FILE": "تزادت عن طريق رفع ملف",
"XTREAM_PLAYLIST": "قائمة تشغيل Xtream",
"STALKER_PORTAL": "بوابة Stalker",
"CHANNELS": "القنوات",
"ADDED": "تزادت",
"SHOW_DETAILS": "وري تفاصيل قائمة التشغيل",
"REMOVE": "حيد قائمة التشغيل",
"SEARCH_PLAYLISTS": "قلب على قوائم التشغيل بالعنوان",
"INFO_DIALOG": {
"PLAYLIST_DETAILS": "تفاصيل قائمة التشغيل",
"TITLE": "العنوان",
"FROM_URL": "تزادت من الرابط",
"IMPORT_DATE": "تاريخ الاستيراد",
"CHANNELS": "عدد القنوات",
"CLOSE": "سد",
"SAVE": "حفظ",
"USER_AGENT": "وكيل المستخدم",
"ORIGINAL_FILENAME": "اسم الملف الأصلي",
"FILE_PATH": "مسار الملف",
"UPDATE_FAILED": "التحديث الأخير ديال قائمة التشغيل فشل",
"AUTO_UPDATE": "تحديث تلقائي",
"AUTO_UPDATE_DESCRIPTION": "إلى كانت خاصية التحديث التلقائي مفعّلة، قائمة التشغيل غادي تتحدث أوتوماتيكياً كل مرة كيتحل التطبيق.",
"CUSTOM_USER_AGENT": "بعض مزودي IPTV كيحتاجو وكيل مستخدم محدد باش يخدمو قائمة التشغيل ديالهم.",
"EXPORT_PLAYLIST": "صدّر قائمة التشغيل على شكل m3u",
"SERVER_URL": "رابط الخادم",
"USERNAME": "اسم المستخدم",
"PASSWORD": "كلمة المرور",
"MAC_ADDRESS": "عنوان MAC",
"PLAYLIST_EXPORT_SUCCESS": "قائمة التشغيل تصدرات بنجاح.",
"PLAYLIST_EXPORT_ERROR": "خطأ: تصدير قائمة التشغيل فشل."
},
"REMOVE_DIALOG": {
"TITLE": "حيد قائمة التشغيل",
"MESSAGE": "واش متأكد بغيتي تحيد قائمة التشغيل هادي بالكامل؟",
"SUCCESS": "قائمة التشغيل تحيدات بنجاح"
},
"UPDATED": "تحدثات",
"REFRESH": "حدث قائمة التشغيل",
"GLOBAL_FAVORITES": "المفضلة العامة",
"GLOBAL_FAVORITES_DESCRIPTION": "قائمة تشغيل كتتولد أوتوماتيكياً فيها المفضلة المجمعة من جميع قوائم التشغيل",
"MY_PLAYLISTS": "قوائم التشغيل ديالي",
"MY_PLAYLISTS_SUBTITLE": "جميع قوائم التشغيل المتوفرة",
"PLAYLIST_UPDATE_SUCCESS": "نجاح! قائمة التشغيل تحدثات بنجاح.",
"PLAYLIST_UPDATE_ERROR": "خطأ في تحديث تفاصيل قائمة التشغيل.",
"FEATURE_M3U_LABEL": "Add an M3U file or URL",
"FEATURE_XTREAM_LABEL": "Connect via Xtream Codes",
"FEATURE_STALKER_LABEL": "Connect to a Stalker portal",
"VALUE_PROPS_LABEL": "What you can do",
"VALUE_PROP_LIVE": "Live TV with EPG",
"VALUE_PROP_VOD": "Movies & Series",
"VALUE_PROP_MULTISOURCE": "Multi-source library",
"VALUE_PROP_OFFLINE": "Offline downloads",
"DASHBOARD_WELCOME_TAGLINE": "Your IPTV library, in one place.",
"FEATURE_LIVE_TITLE": "Live TV",
"FEATURE_LIVE_DESC": "Stream live channels with full schedule.",
"FEATURE_VOD_TITLE": "Movies & Series",
"FEATURE_VOD_DESC": "On-demand library with covers and details.",
"FEATURE_EPG_TITLE": "EPG & Catch-up",
"FEATURE_EPG_DESC": "Program guide and time-shifted playback.",
"FEATURE_OFFLINE_TITLE": "Offline downloads",
"FEATURE_OFFLINE_DESC": "Save movies and episodes for later.",
"SOURCES_WELCOME_TITLE": "Add your first playlist",
"SOURCES_WELCOME_BODY": "Pick a source type below to get started.",
"SOURCE_M3U_NEEDS": "Local file or URL pointing to an M3U/M3U8 playlist.",
"SOURCE_M3U_ADD": "Add M3U",
"SOURCE_XTREAM_NEEDS": "Username, password and server URL from your provider.",
"SOURCE_XTREAM_ADD": "Add Xtream",
"SOURCE_STALKER_NEEDS": "Portal URL and MAC address (Ministra-compatible).",
"SOURCE_STALKER_ADD": "Add Stalker",
"CONTENT_LIVE": "Live",
"CONTENT_VOD": "Movies",
"CONTENT_SERIES": "Series",
"CONTENT_EPG": "EPG",
"DASHBOARD_WELCOME_DESCRIPTION": "Connect M3U files, Xtream Codes, or Stalker portals — then enjoy live TV, movies and series on every screen."
},
"FILE_UPLOAD": {
"DRAG_DROP": "جر وأفلت الملفات هنا",
"OR": "أو",
"CHOOSE_PLAYLIST": "اختار قائمة تشغيل",
"REJECTED": "الملف ترفض، صيغة الملف غير مدعومة {{filename}}."
},
"URL_UPLOAD": {
"PLAYLIST_URL": "رابط قائمة التشغيل (m3u, m3u8)",
"ADD_PLAYLIST": "زيد قائمة التشغيل",
"CORS_NOTE": "ملاحظة: باش نتفاداو مشاكل CORS فهاد المرحلة، التطبيق كيستعمل خدمة وكيل CORS عامة. إلى بغيتي ترفع قائمة تشغيل فيها بيانات حساسة، من الأحسن تستوردها من ملف."
},
"TEXT_IMPORT": {
"LABEL": "دخل قائمة تشغيل m3u(8) على شكل نص",
"BUTTON_LABEL": "استورد"
},
"XTREAM_PLAYLIST": {
"TITLE": "عنوان قائمة التشغيل",
"SERVER_URL": "رابط الخادم",
"USERNAME": "اسم المستخدم",
"PASSWORD": "كلمة المرور",
"ADD": "زيد",
"TEST_CREDENTIALS": "جرب بيانات الاعتماد",
"URL_VALIDATION_ERROR": "خاص يكون رابط صحيح مع البروتوكول (مثلا http://example.com ولا https://example.com:4324)"
},
"STALKER_PORTAL": {
"TITLE": "العنوان",
"MAC_ADDRESS": "عنوان MAC",
"SERVER_URL": "رابط الخادم",
"URL_VALIDATION_ERROR": "خاص يكون رابط صحيح مع البروتوكول (مثلا http://example.com/c ولا https://example.com/stalker_portal/c)",
"ADD": "زيد"
},
"FILTER_BY_NAME": "فلتر بالاسم",
"FILTER_BY_TYPE": "فلتر بالنوع",
"SORT_PLAYLISTS": "رتب قوائم التشغيل",
"SORT_BY": "رتب بـ",
"SORT_OPTIONS": {
"NAME_ASC": "الاسم (أ-ي)",
"NAME_DESC": "الاسم (ي-أ)",
"NEWEST": "تاريخ الإضافة (الأحدث أولاً)",
"OLDEST": "تاريخ الإضافة (الأقدم أولاً)"
},
"IMPORTED_AS_TEXT": "استورد كنص",
"PARSING_ERROR": "خطأ: التحليل فشل، ماشي قائمة تشغيل صحيحة:"
},
"SETTINGS": {
"TITLE": "الإعدادات",
"SUBTITLE": "بدل إعدادات التطبيق",
"DESCRIPTION": "عفاك بدل الخيارات من الليستا لتحت وأكد بضغط على زر حفظ التغييرات",
"EPG_URL_LABEL": "رابط EPG (*.xml ولا *.xml.gz)",
"EPG_URL_PLACEHOLDER": "دخل رابط",
"REFRESH_EPG": "حدث EPG",
"REFRESH_ALL_EPG": "حدث الكل",
"REMOVE_EPG_SOURCE": "زول مصدر EPG",
"EPG_STATUS_FRESH": "محدث",
"EPG_STATUS_STALE": "خاصو يتحدث",
"EPG_STATUS_ERROR": "فشل",
"VIDEO_PLAYER_LABEL": "مشغل الفيديو",
"VIDEO_PLAYER_PLACEHOLDER": "اختار خيار",
"VERSION": "الإصدار",
"SAVE_CHANGES": "حفظ التغييرات",
"BACK_TO_HOME": "رجوع",
"NEW_VERSION_AVAILABLE": "كاين إصدار جديد متوفر",
"LATEST_VERSION": "راك تستعمل أحدث إصدار",
"LANGUAGE": "اللغة",
"SETTINGS_SAVED": "نجاح! الإعدادات تحفضو.",
"THEME": "المظهر المرئي",
"SHOW_CAPTIONS": "وري الترجمة",
"ADD_EPG_SOURCE": "زيد مصدر EPG",
"EPG_URL_ERROR": "القيمة ماشي رابط صحيح",
"VIDEO_PLAYER_DESCRIPTION": "اختار مشغل الفيديو الافتراضي",
"LANGUAGE_DESCRIPTION": "اختار لغة التطبيق",
"THEME_DESCRIPTION": "اختار المظهر المرئي للتطبيق",
"SHOW_CAPTIONS_DESCRIPTION": "وري ولا خفي الترجمة افتراضياً",
"VERSION_DESCRIPTION": "الإصدار الحالي ديال التطبيق",
"EPG_NOTE": "EPG متوفر حالياً غير في الإصدار اللي مبني على electron ديال IPTVnator.",
"EPG_NOTE_URL_TEXT": "شوف هنا",
"IMPORT_EXPORT_DATA": "استورد/صدّر قوائم التشغيل",
"IMPORT_EXPORT_DATA_DESCRIPTION": "صدّر ولا استورد قوائم التشغيل بصيغة JSON اللي كيستعملها التطبيق.",
"IMPORT_DATA": "استورد",
"EXPORT_DATA": "صدّر",
"REMOVE_ALL": "Delete all playlists and playlist data",
"REMOVE_ALL_BUTTON": "Delete all",
"REMOVE_ALL_DESCRIPTION": "Delete every M3U, Xtream, and Stalker playlist stored in the app.",
"REMOVE_DIALOG": {
"TITLE": "Delete all playlists?",
"MESSAGE": "Delete all {{count}} playlists from the app. This also removes stored playlist data on this device.",
"SUMMARY_TITLE": "Playlist sources",
"CONSEQUENCES_TITLE": "This also removes",
"CONSEQUENCE_FAVORITES": "Favorites saved for these playlists",
"CONSEQUENCE_RECENTLY_VIEWED": "Recently viewed history",
"CONSEQUENCE_PLAYBACK": "Saved playback positions",
"CONSEQUENCE_DOWNLOADS": "Download history entries linked to those playlists",
"CONSEQUENCE_XTREAM_CACHE": "Imported Xtream categories and locally cached content",
"BACKUP_HINT": "Use Export first if you want a restorable backup before deleting.",
"CONFIRM": "Delete everything"
},
"IMPORT_ERROR": "خطأ في الاستيراد، عفاك جرب بملف آخر.",
"PLAYLISTS_REMOVED": "All playlists and playlist data were removed.",
"MPV_PLAYER_PATH_LABEL": "مسار mpv",
"MPV_PLAYER_PATH_DESCRIPTION": "حدد مسار مشغل mpv في السيستيم ديالك. غادي يستعمل المسار اللي عطيتيه لملف mpv بدل اللي كيتلقى في $PATH.",
"MPV_PLAYER_PATH": "مسار مشغل mpv",
"VLC_PLAYER_PATH_LABEL": "مسار VLC",
"VLC_PLAYER_PATH_DESCRIPTION": "حدد مسار مشغل VLC في السيستيم ديالك. غادي يستعمل المسار اللي عطيتيه لملف VLC بدل المسار الافتراضي ديال السيستيم ديالنا.",
"VLC_PLAYER_PATH": "مسار مشغل VLC",
"REMOTE_CONTROL": "التحكم عن بعد",
"REMOTE_CONTROL_DESCRIPTION": "فعل التحكم عن بعد للتطبيق.",
"REMOTE_CONTROL_PORT": "منفذ التحكم عن بعد",
"REMOTE_CONTROL_PORT_DESCRIPTION": "المنفذ اللي كيتستعمل للتحكم عن بعد للتطبيق. المنفذ 3000 كيتستعمل افتراضياً.",
"REMOVE_ALL_IN_PROGRESS": "Deleting playlist data…",
"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.",
"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": "المظهر الداكن",
"LIGHT_THEME": "المظهر الفاتح",
"SYSTEM_THEME": "مظهر النظام"
},
"CHANNELS": {
"SEARCH_CHANNEL": "قلب على قناة",
"UPLOAD_OR_SELECT_OTHER_PLAYLIST": "رفع ولا اختار قائمة تشغيل أخرى",
"ALL_CHANNELS": "جميع القنوات",
"GROUPS": "المجموعات",
"UNGROUPED": "غير مجمعة",
"UNNAMED_CHANNEL": "قناة بدون اسم",
"FAVORITES": "المفضلة",
"NO_FAVORITES": "مازال ما كاينش مفضلة",
"USE_STAR_TO_FAVORITE": "عفاك استعمل رمز 'النجمة' باش تزيد قنوات للمفضلة ديالك.",
"REMOVE_FAVORITE": "حيد من المفضلة",
"FAVORITES_UPDATED": "المفضلة تحدثات!",
"SORT_BY": "رتب بـ",
"SORT_BY_DATE": "رتب بتاريخ الإضافة (الأحدث أولاً)",
"SORT_BY_RATING": "رتب بالتقييم",
"SORT_BY_NAME": "رتب بالاسم (أ-ي)"
},
"TOP_MENU": {
"OPEN_CHANNELS_LIST": "حل قائمة القنوات",
"TOGGLE_FAVORITE_FLAG": "بدل علامة المفضلة",
"OPEN_EPG_LIST": "حل قائمة EPG",
"OPEN_MULTI_EPG": "حل عرض EPG المتعدد"
},
"EPG": {
"TITLE": "دليل البرامج الإلكتروني",
"NEXT_DAY": "اليوم التالي",
"PREVIOUS_DAY": "اليوم السابق",
"LIVE_NOW": "مباشر الآن",
"LIVE_STREAM": "بث مباشر",
"TIMESHIFT_AVAILABLE": "التأجيل الزمني متوفر، ضغط باش تلعب",
"EPG_NOT_AVAILABLE_DATE": "أوه، EPG ما متوفرش للتاريخ اللي اختاريتيه",
"EPG_NOT_AVAILABLE_CHANNEL_TITLE": "أوه، EPG ما متوفرش لهاد القناة.",
"EPG_NOT_AVAILABLE_CHANNEL_DESCRIPTION": "عفاك زيد/بدل رابط قائمة EPG في إعدادات التطبيق.",
"FETCH_EPG": "جاري جلب بيانات EPG...",
"ERROR": "أوه، EPG ما قدرش يتشارجا.",
"DOWNLOAD_SUCCESS": "EPG تشارجا بنجاح.",
"PROGRAM_DIALOG": {
"PROGRAM_DETAILS": "تفاصيل حول البرنامج التلفزيوني",
"TITLE": "العنوان",
"CATEGORY": "الفئة",
"PARENTAL_RATING_SYSTEM": "نظام تقييم المحتوى التلفزيوني",
"DESCRIPTION": "الوصف",
"LANGUAGE": "اللغة",
"SHOW_PROGRAM_DETAILS": "وري تفاصيل حول هاد البرنامج"
},
"FETCH_SUCCESS": "EPG تجلب بنجاح"
},
"LANGUAGES": {
"ARABIC": "العربية",
"MOROCCAN_ARABIC": "العربية (اللهجة المغربية)",
"ENGLISH": "English",
"KOREAN": "한국어",
"RUSSIAN": "Русский",
"GERMAN": "Deutsch",
"SPANISH": "Español",
"CHINESE": "简体中文",
"TRADITIONAL_CHINESE": "繁體中文",
"FRENCH": "Français",
"ITALIAN": "Italiano",
"TURKISH": "Türkçe",
"JAPANESE": "日本語",
"DUTCH": "Nederlands",
"BELARUSIAN": "Беларуская",
"POLISH": "Polski",
"PORTUGUESE": "Português",
"GREEK": "Ελληνικά"
},
"YES": "آه",
"NO": "لا",
"MENU": {
"OPEN": "حل القائمة",
"SUPPORT_ARIA": "دعم IPTVnator على GitHub",
"SETTINGS": "الإعدادات",
"SETTINGS_ARIA": "حل الإعدادات",
"BUG_REPORT": "بلغ على شي مشكل",
"WHAT_IS_NEW": "شنو الجديد",
"ABOUT": "حول",
"ABOUT_ARIA": "حول التطبيق",
"SUPPORT_PROJECT": "دعم المشروع"
},
"ABOUT": {
"TITLE": "حول IPTVnator",
"DESCRIPTION": "تطبيق مشغل IPTV متعدد المنصات فيه بزاف ديال الميزات، بحال دعم قوائم تشغيل m3u و m3u8، المفضلة، دليل التلفزيون، الأرشيف التلفزيوني/الإعادة والمزيد.",
"VERSION": "الإصدار",
"GITHUB_TOOLTIP": "مستودع IPTVnator على GitHub",
"BUY_ME_A_COFFEE_TOOLTIP": "شري ليا قهوة",
"TWITTER_TOOLTIP": "شارك على تويتر"
},
"UPDATE_AVAILABLE": "تحديث متوفر",
"REFRESH": "حدث",
"XTREAM": {
"PLAY": "لعب",
"NAME": "الاسم",
"RELEASE_DATE": "تاريخ الإصدار",
"GENRE": "النوع",
"COUNTRY": "البلد",
"ACTORS": "الممثلون",
"DIRECTOR": "المخرج",
"DURATION": "المدة",
"CAST": "طاقم التمثيل",
"EPISODE_RUN_TIME": "مدة تشغيل الحلقة",
"RATING": "التقييم",
"IMDB_RATING": "تقييم IMDB",
"KINOPOISK_RATING": "تقييم Kinopoisk",
"DESCRIPTION": "الوصف",
"YEAR": "السنة",
"AGE": "العمر",
"YOUTUBE_TRAILER": "مقطع دعائي على يوتيوب",
"EPISODE": "الحلقة"
},
"PORTALS": {
"ALL_CATEGORIES": "جميع الفئات",
"MY_FAVORITES": "المفضلة ديالي",
"ADD_TO_FAVORITES": "زيد للمفضلة",
"REMOVE_FROM_FAVORITES": "حيد من المفضلة",
"REMOVED_FROM_FAVORITES": "تحيد من المفضلة",
"ADDED_TO_FAVORITES": "تزاد للمفضلة",
"ERROR_VIEW": {
"ACCOUNT_EXPIRED": {
"TITLE": "الحساب انتهى",
"DESCRIPTION": "هاد الحساب انتهت صلاحيته. عفاك تحقق من بيانات الاعتماد في إعدادات قائمة التشغيل ولا حيدها."
},
"UNAUTHORIZED": {
"TITLE": "غير مصرح",
"DESCRIPTION": "عفاك تحقق من بيانات الاعتماد في إعدادات قائمة التشغيل ولا حيدها."
},
"NOT_FOUND": {
"TITLE": "البوابة ما تلقاتش",
"DESCRIPTION": "عفاك تحقق من بيانات الاعتماد ورابط البوابة في إعدادات قائمة التشغيل ولا حيدها."
},
"EMPTY_CATEGORY": {
"TITLE": "فئة فارغة",
"DESCRIPTION": "هاد الفئة ما فيهاش محتوى، عفاك اختار فئة أخرى ولا بدل نوع المحتوى."
},
"UNKNOWN_ERROR": {
"TITLE": "وقع شي خطأ",
"DESCRIPTION": "خطأ غير معروف، عفاك حاول مرة أخرى من بعد."
},
"PLAYLIST_SETTINGS": "إعدادات قائمة التشغيل",
"HOME": "الرئيسية",
"DELETE": "حذف"
},
"EMPTY_LIST_VIEW": {
"NO_SEARCH_RESULTS": "ما تلقى والو، حاول تبدل طلب البحث ديالك"
},
"STREAM_URL_COPIED": "رابط البث تنقل للحافظة",
"COPY_STREAM_URL": "نسخ رابط البث",
"SEARCH_VIEW": {
"RESULTS_FOUND": "تلقاو {{count}} ديال النتايج",
"NO_RESULTS_FOR": "ما تلقاو حتى نتيجة لـ \"{{term}}\""
}
},
"INFORMATION": "معلومات",
"REMOTE_CONTROL": {
"TITLE": "التحكم عن بعد",
"UP_CHANNEL": "القناة الفوق",
"DOWN_CHANNEL": "القناة لتحت",
"HEADER": "التحكم عن بعد IPTVNator",
"FOOTER": "التحكم عن بعد IPTVNator"
},
"WORKSPACE": {
"SHELL": {
"GO_TO_DASHBOARD": "Back to dashboard",
"GO_TO_SOURCES": "Go to Sources",
"DROP_OVERLAY_TITLE": "Drop to add playlist",
"DROP_OVERLAY_BODY": "Release an .m3u or .m3u8 file anywhere in the workspace to import it.",
"DROP_OVERLAY_REJECTED_BODY": "Please drop an .m3u or .m3u8 file. Press Esc to dismiss.",
"DROP_OVERLAY_REJECTED_UNSUPPORTED": "Unsupported file type",
"DROP_OVERLAY_REJECTED_EMPTY": "That file is empty",
"DROP_OVERLAY_REJECTED_READ_ERROR": "Could not read that file",
"DROP_IMPORT_SUCCESS": "Importing \"{{title}}\"…",
"COMMANDS": {
"ADD_PLAYLIST_M3U_LABEL": "Add M3U playlist",
"ADD_PLAYLIST_M3U_DESCRIPTION": "Open add dialog on the M3U file or URL tab",
"ADD_PLAYLIST_XTREAM_LABEL": "Add Xtream Codes playlist",
"ADD_PLAYLIST_XTREAM_DESCRIPTION": "Open add dialog on the Xtream Codes tab",
"ADD_PLAYLIST_STALKER_LABEL": "Add Stalker portal",
"ADD_PLAYLIST_STALKER_DESCRIPTION": "Open add dialog on the Stalker Portal tab"
},
"EXTERNAL_PLAYBACK_CLOSE": "Close player"
},
"GLOBAL_FAVORITES": {
"NO_PLAYLISTS_TITLE": "No favorites to show",
"NO_PLAYLISTS_BODY": "Add a playlist to start collecting favorites from live channels, movies, and series.",
"NO_ITEMS_TITLE": "No favorites yet",
"NO_ITEMS_BODY": "Tap the star icon on any channel, movie, or series to save it here."
},
"GLOBAL_RECENT": {
"NO_PLAYLISTS_TITLE": "Nothing watched yet",
"NO_PLAYLISTS_BODY": "Add a playlist and your watching history will appear here.",
"NO_ITEMS_TITLE": "Nothing watched yet",
"NO_ITEMS_BODY": "Start watching anything from your library and it will show up here."
}
},
"DOWNLOADS": {
"NO_PLAYLISTS_TITLE": "Add a playlist to start downloading",
"NO_PLAYLISTS_BODY": "Once you add a playlist, you can save movies and episodes here for offline playback.",
"NO_ITEMS_BODY": "Use the download button on any movie or episode to save it for offline playback.",
"NO_FILTER_MATCH": "No downloads match the current filter",
"NO_FILTER_MATCH_HINT": "Try a different search term"
}
}
+388
View File
@@ -0,0 +1,388 @@
{
"CLOSE": "Закрыць",
"PLAYLISTS": "Плэйлісты",
"HOME": {
"TITLE": "IPTVnator",
"SUBTITLE": "Выберыце плэйліст са спісу, дадайце новы з камп'ютара або загрузіце па спасылцы",
"TABS": {
"RECENTLY_ADDED": "Нядаўна дададзеныя плэйлісты",
"FILE_UPLOAD": "Загрузіць з камп'ютара",
"URL_UPLOAD": "Загрузіць па спасылцы",
"TEXT_IMPORT": "Імпартаваць з тэксту",
"STALKER_PORTAL_IMPORT": "Дадаць Stalker партал",
"XTREME_IMPORT": "Дадаць Xtreme Code"
},
"PLAYLISTS": {
"NO_PLAYLISTS": "Пакуль яшчэ не было дададзена ніводнага плэйліста",
"ADD_FIRST": "Вы можаце дадаць плэйлісты з суседніх укладак",
"ADDED_VIA_URL": "Быў дададзены па спасылцы:",
"ADDED_VIA_FILE": "Быў загружаны з камп'ютара",
"CHANNELS": "Каналаў",
"ADDED": "Дададзены",
"SHOW_DETAILS": "Паказаць інфармацыю аб плэйлісце",
"REMOVE": "Выдаліць плэйліст",
"SEARCH_PLAYLISTS": "Пошук па назве плэйліста",
"INFO_DIALOG": {
"PLAYLIST_DETAILS": "Падрабязная інфармацыя аб плэйлісце",
"TITLE": "Назва",
"FROM_URL": "Дададзены па спасылцы",
"IMPORT_DATE": "Дата імпарту",
"CHANNELS": "Колькасць каналаў",
"CLOSE": "Закрыць",
"SAVE": "Захаваць",
"USER_AGENT": "User agent",
"ORIGINAL_FILENAME": "Імя файла пры загрузцы",
"FILE_PATH": "Шлях да файла",
"UPDATE_FAILED": "Не ўдалося абнавіць плэйліст",
"AUTO_UPDATE": "Аўтаабнаўленне",
"AUTO_UPDATE_DESCRIPTION": "Калі актываваная функцыя аўтаабнаўлення, спіс прайгравання будзе абнаўляцца аўтаматычна пры кожным запуску праграмы.",
"CUSTOM_USER_AGENT": "Некаторыя IPTV правайдэры патрабуюць указанне пэўнага карыстальніцкага агента (User Agent) для прайгравання свайго плэйліста.",
"EXPORT_PLAYLIST": "Экспартаваць плэйліст (m3u)",
"PASSWORD": "Пароль",
"SERVER_URL": "URL-адрас сервера",
"USERNAME": "Імя карыстальніка",
"MAC_ADDRESS": "MAC-адрас"
},
"UPDATED": "Абноўлены",
"REFRESH": "Абнавіць плэйліст",
"REMOVE_DIALOG": {
"MESSAGE": "Вы ўпэўнены, што хочаце выдаліць гэты плэйліст?",
"TITLE": "Выдаліць плэйліст"
},
"GLOBAL_FAVORITES": "Усе фаварыты",
"GLOBAL_FAVORITES_DESCRIPTION": "Аўтаматычна згенераваны плэйліст, які ўключае ў сябе фаварыты з усіх плэйлістоў",
"MY_PLAYLISTS": "Мае плэйлісты",
"MY_PLAYLISTS_SUBTITLE": "Усе наяўныя плэйлісты",
"PLAYLIST_UPDATE_SUCCESS": "Плэйліст быў паспяхова абноўлены!",
"STALKER_PORTAL": "Stalker партал",
"XTREAM_PLAYLIST": "Xtream плэйліст",
"FEATURE_M3U_LABEL": "Add an M3U file or URL",
"FEATURE_XTREAM_LABEL": "Connect via Xtream Codes",
"FEATURE_STALKER_LABEL": "Connect to a Stalker portal",
"VALUE_PROPS_LABEL": "What you can do",
"VALUE_PROP_LIVE": "Live TV with EPG",
"VALUE_PROP_VOD": "Movies & Series",
"VALUE_PROP_MULTISOURCE": "Multi-source library",
"VALUE_PROP_OFFLINE": "Offline downloads",
"DASHBOARD_WELCOME_TAGLINE": "Your IPTV library, in one place.",
"FEATURE_LIVE_TITLE": "Live TV",
"FEATURE_LIVE_DESC": "Stream live channels with full schedule.",
"FEATURE_VOD_TITLE": "Movies & Series",
"FEATURE_VOD_DESC": "On-demand library with covers and details.",
"FEATURE_EPG_TITLE": "EPG & Catch-up",
"FEATURE_EPG_DESC": "Program guide and time-shifted playback.",
"FEATURE_OFFLINE_TITLE": "Offline downloads",
"FEATURE_OFFLINE_DESC": "Save movies and episodes for later.",
"SOURCES_WELCOME_TITLE": "Add your first playlist",
"SOURCES_WELCOME_BODY": "Pick a source type below to get started.",
"SOURCE_M3U_NEEDS": "Local file or URL pointing to an M3U/M3U8 playlist.",
"SOURCE_M3U_ADD": "Add M3U",
"SOURCE_XTREAM_NEEDS": "Username, password and server URL from your provider.",
"SOURCE_XTREAM_ADD": "Add Xtream",
"SOURCE_STALKER_NEEDS": "Portal URL and MAC address (Ministra-compatible).",
"SOURCE_STALKER_ADD": "Add Stalker",
"CONTENT_LIVE": "Live",
"CONTENT_VOD": "Movies",
"CONTENT_SERIES": "Series",
"CONTENT_EPG": "EPG",
"DASHBOARD_WELCOME_DESCRIPTION": "Connect M3U files, Xtream Codes, or Stalker portals — then enjoy live TV, movies and series on every screen."
},
"FILE_UPLOAD": {
"DRAG_DROP": "Перацягніце файл у гэтую вобласць",
"OR": "або",
"CHOOSE_PLAYLIST": "выберыце плэйліст",
"REJECTED": "На жаль, гэты фармат файлаў не падтрымліваецца {{filename}}."
},
"URL_UPLOAD": {
"PLAYLIST_URL": "Спасылка на плэйліст (*.m3u або *.m3u8)",
"ADD_PLAYLIST": "Дадаць плэйліст"
},
"TEXT_IMPORT": {
"LABEL": "Устаўце плэйліст фармату m3u(8) у гэта поле",
"BUTTON_LABEL": "Імпартаваць"
},
"XTREAM_PLAYLIST": {
"TITLE": "Назва плэйліста",
"SERVER_URL": "Сервер URL",
"USERNAME": "Карыстальнік",
"PASSWORD": "Пароль",
"ADD": "Дадаць",
"TEST_CREDENTIALS": "Праверыць",
"URL_VALIDATION_ERROR": "Павінен быць сапраўдны URL-адрас з пратаколам (напрыклад, http://example.com або https://example.com:4324)."
},
"STALKER_PORTAL": {
"ADD": "Дадаць",
"TITLE": "Назва",
"MAC_ADDRESS": "MAC-адрас",
"SERVER_URL": "URL сервера",
"URL_VALIDATION_ERROR": "Павінен быць сапраўдны URL-адрас з пратаколам (напрыклад, http://example.com/c або https://example.com/stalker_portal/c)."
},
"FILTER_BY_TYPE": "Фільтраваць па тыпу",
"IMPORTED_AS_TEXT": "Імпартавана як тэкст",
"FILTER_BY_NAME": "Фільтраваць па імені",
"PARSING_ERROR": "Памылка парсінгу, несапраўдны плэйліст:"
},
"LANGUAGES": {
"ARABIC": "العربية",
"MOROCCAN_ARABIC": "العربية (اللهجة المغربية)",
"ENGLISH": "English",
"KOREAN": "한국어",
"RUSSIAN": "Русский",
"GERMAN": "Deutsch",
"SPANISH": "Español",
"CHINESE": "简体中文",
"TRADITIONAL_CHINESE": "繁體中文",
"FRENCH": "Français",
"ITALIAN": "Italiano",
"TURKISH": "Türkçe",
"JAPANESE": "日本語",
"DUTCH": "Nederlands",
"BELARUSIAN": "Беларуская",
"POLISH": "Polski",
"PORTUGUESE": "Português",
"GREEK": "Ελληνικά"
},
"SETTINGS": {
"TITLE": "Налады",
"SUBTITLE": "Тут можна змяніць агульныя налады праграмы",
"DESCRIPTION": "Скончыўшы наладу, не забудзьцеся пацвердзіць новыя налады кнопкай 'Захаваць'",
"EPG_URL_LABEL": "Спасылка на праграму каналаў (EPG) (*.xml або *.xml.gz)",
"EPG_URL_PLACEHOLDER": "Увядзіце спасылку",
"REFRESH_EPG": "Абнавіць праграму каналаў (EPG)",
"REFRESH_ALL_EPG": "Абнавіць усё",
"REMOVE_EPG_SOURCE": "Выдаліць крыніцу EPG",
"EPG_STATUS_FRESH": "Актуальна",
"EPG_STATUS_STALE": "Патрабуе абнаўлення",
"EPG_STATUS_ERROR": "Памылка",
"VIDEO_PLAYER_LABEL": "Відэапрайгравальнік",
"VIDEO_PLAYER_PLACEHOLDER": "Выберыце са спісу",
"VERSION": "Версія праграмы",
"SAVE_CHANGES": "Захаваць",
"BACK_TO_HOME": "Назад",
"NEW_VERSION_AVAILABLE": "Даступная новая версія праграмы",
"LATEST_VERSION": "Вы выкарыстоўваеце апошнюю версію праграмы",
"LANGUAGE": "Мова",
"SETTINGS_SAVED": "Новыя налады былі паспяхова захаваны!",
"THEME": "Тэма афармлення",
"SHOW_CAPTIONS": "Адлюстроўваць субтытры",
"ADD_EPG_SOURCE": "Дадаць крыніцу EPG",
"EPG_URL_ERROR": "Уведзенае значэнне не з'яўляецца URL-адрасам.",
"VIDEO_PLAYER_DESCRIPTION": "Выбраць стандартны відэапрайгравальнік",
"LANGUAGE_DESCRIPTION": "Выбраць мову праграмы",
"THEME_DESCRIPTION": "Выбраць візуальную тэму афармлення",
"SHOW_CAPTIONS_DESCRIPTION": "Паказаць або схаваць субтытры па змаўчанні.",
"VERSION_DESCRIPTION": "Бягучая версія праграмы",
"EPG_NOTE": "На гэты момант EPG даступны толькі ў натыўнай версіі IPTVnator.",
"EPG_NOTE_URL_TEXT": "Падрабязней тут",
"IMPORT_EXPORT_DATA": "Імпарт/экспарт плэйлістоў",
"IMPORT_EXPORT_DATA_DESCRIPTION": "Экспарт або імпарт плэйлістоў у фармаце JSON, які выкарыстоўваецца ў праграме.",
"IMPORT_DATA": "Імпарт",
"EXPORT_DATA": "Экспарт",
"REMOVE_ALL": "Delete all playlists and playlist data",
"REMOVE_ALL_BUTTON": "Delete all",
"REMOVE_ALL_DESCRIPTION": "Delete every M3U, Xtream, and Stalker playlist stored in the app.",
"REMOVE_DIALOG": {
"TITLE": "Delete all playlists?",
"MESSAGE": "Delete all {{count}} playlists from the app. This also removes stored playlist data on this device.",
"SUMMARY_TITLE": "Playlist sources",
"CONSEQUENCES_TITLE": "This also removes",
"CONSEQUENCE_FAVORITES": "Favorites saved for these playlists",
"CONSEQUENCE_RECENTLY_VIEWED": "Recently viewed history",
"CONSEQUENCE_PLAYBACK": "Saved playback positions",
"CONSEQUENCE_DOWNLOADS": "Download history entries linked to those playlists",
"CONSEQUENCE_XTREAM_CACHE": "Imported Xtream categories and locally cached content",
"BACKUP_HINT": "Use Export first if you want a restorable backup before deleting.",
"CONFIRM": "Delete everything"
},
"IMPORT_ERROR": "Памылка імпарту, калі ласка, паспрабуйце імпартаваць іншы файл.",
"PLAYLISTS_REMOVED": "All playlists and playlist data were removed.",
"VLC_PLAYER_PATH_LABEL": "Шлях да VLC прайгравальніка",
"VLC_PLAYER_PATH": "Шлях да VLC прайгравальніка",
"MPV_PLAYER_PATH_LABEL": "Шлях да mpv прайгравальніка",
"MPV_PLAYER_PATH": "Шлях да mpv прайгравальніка",
"VLC_PLAYER_PATH_DESCRIPTION": "Усталюйце шлях да прайгравальніка VLC у вашай сістэме. \nЁн будзе выкарыстоўваць прадастаўлены шлях да бінарнага файла VLC замест шляху па змаўчанні.",
"REMOVE_ALL_IN_PROGRESS": "Deleting playlist data…",
"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.",
"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": "Цёмная тэма",
"LIGHT_THEME": "Светлая тэма",
"SYSTEM_THEME": "Сістэмная тэма"
},
"CHANNELS": {
"SEARCH_CHANNEL": "Пошук каналаў",
"UPLOAD_OR_SELECT_OTHER_PLAYLIST": "Загрузіць або выбраць іншы плэйліст",
"ALL_CHANNELS": "Усе каналы",
"GROUPS": "Групы",
"UNGROUPED": "Незагрупаваныя",
"UNNAMED_CHANNEL": "Канал без назвы",
"FAVORITES": "Выбраныя",
"NO_FAVORITES": "Выбраных каналаў пакуль няма",
"USE_STAR_TO_FAVORITE": "Выкарыстоўвайце значок зоркі, каб дадаваць каналы ў выбранае",
"REMOVE_FAVORITE": "Выдаліць са спісу фаварытаў",
"FAVORITES_UPDATED": "Спіс фаварытаў быў абноўлены!"
},
"TOP_MENU": {
"OPEN_CHANNELS_LIST": "Адкрыць спіс каналаў",
"TOGGLE_FAVORITE_FLAG": "Выбраны",
"OPEN_EPG_LIST": "Адкрыць праграму (EPG)",
"OPEN_MULTI_EPG": "Адкрыць мульты-EPG прагляд"
},
"EPG": {
"NEXT_DAY": "Наступны дзень",
"PREVIOUS_DAY": "Папярэдні дзень",
"LIVE_NOW": "Цяпер",
"LIVE_STREAM": "Прамая трансляцыя",
"TIMESHIFT_AVAILABLE": "Даступная функцыя архіва (timeshift). Націсніце на перадачу для прайгравання.",
"EPG_NOT_AVAILABLE_DATE": "Ой, праграма на гэты дзень, на жаль, адсутнічае.",
"EPG_NOT_AVAILABLE_CHANNEL_TITLE": "Праграма для гэтага канала недаступная.",
"EPG_NOT_AVAILABLE_CHANNEL_DESCRIPTION": "Паспрабуйце змяніць або абнавіць спасылку на EPG у наладах праграмы.",
"FETCH_EPG": "Загружаю праграму ТБ-перадач (EPG)...",
"ERROR": "Ой, не ўдалося загрузіць праграму каналаў (EPG)",
"DOWNLOAD_SUCCESS": "Праграма каналаў (EPG) была паспяхова загружана.",
"PROGRAM_DIALOG": {
"PROGRAM_DETAILS": "Падрабязнасці перадачы",
"TITLE": "Назва",
"CATEGORY": "Катэгорыя",
"PARENTAL_RATING_SYSTEM": "Возраснае абмежаванне",
"DESCRIPTION": "Апісанне",
"LANGUAGE": "Мова",
"SHOW_PROGRAM_DETAILS": "Паказаць падрабязнасці"
}
},
"NO": "Не",
"YES": "Так",
"MENU": {
"OPEN": "Адкрыць меню",
"SUPPORT_ARIA": "Падтрымаць IPTVnator на GitHub",
"SETTINGS": "Налады",
"SETTINGS_ARIA": "Адкрыць налады",
"BUG_REPORT": "Паведаміць аб памылцы",
"WHAT_IS_NEW": "Што новага?",
"ABOUT": "Аб праграме",
"ABOUT_ARIA": "Аб праграме",
"SUPPORT_PROJECT": "Падтрымаць праект"
},
"ABOUT": {
"TITLE": "Аб праграме",
"DESCRIPTION": "Кросплатформавая праграма для прайгравання IPTV з мноствам функцый, такіх як падтрымка плэйлістоў m3u і m3u8, фаварыты, ТБ-гід, ТБ-архіў/даганянне і іншае.",
"VERSION": "Версія",
"GITHUB_TOOLTIP": "Рэпазітар праграмы на GitHub",
"BUY_ME_A_COFFEE_TOOLTIP": "Падтрымаць распрацоўшчыка",
"TWITTER_TOOLTIP": "Падзяліцца ў Twitter"
},
"UPDATE_AVAILABLE": "Даступна абнаўленне",
"REFRESH": "Абнавіць",
"XTREAM": {
"RATING": "Рэйтынг",
"RELEASE_DATE": "Дата выпуску",
"ACTORS": "Акцёры",
"PLAY": "Прайграць",
"GENRE": "Жанр",
"DURATION": "Працягласць",
"COUNTRY": "Краіна",
"NAME": "Назва",
"DIRECTOR": "Рэжысёр",
"CAST": "Акцёрскі склад",
"EPISODE_RUN_TIME": "Працягласць эпізоду",
"AGE": "Узрост",
"EPISODE": "Эпізод",
"YEAR": "Год",
"YOUTUBE_TRAILER": "Трэйлер на YouTube",
"DESCRIPTION": "Апісанне",
"KINOPOISK_RATING": "Рэйтынг на Кінапоіск",
"IMDB_RATING": "Рэйтынг на IMDB"
},
"PORTALS": {
"ALL_CATEGORIES": "Усе катэгорыі",
"ADD_TO_FAVORITES": "Дадаць у выбранае",
"REMOVE_FROM_FAVORITES": "Выдаліць з выбранага",
"MY_FAVORITES": "Выбранае",
"COPY_STREAM_URL": "Капіраваць URL-адрас патоку",
"ERROR_VIEW": {
"DELETE": "Выдаліць",
"ACCOUNT_EXPIRED": {
"TITLE": "Тэрмін дзеяння ўліковага запісу скончыўся",
"DESCRIPTION": "Тэрмін дзеяння гэтага ўліковага запісу скончыўся. \nКалі ласка, праверце ўліковыя дадзеныя ў наладах плэйліста або выдаліце яго."
},
"HOME": "На галоўную",
"EMPTY_CATEGORY": {
"TITLE": "Пустая катэгорыя",
"DESCRIPTION": "У гэтай катэгорыі няма кантэнту. Выберыце іншую катэгорыю або зменіце тып кантэнту."
},
"UNAUTHORIZED": {
"TITLE": "Несанкцыянаваны",
"DESCRIPTION": "Калі ласка, праверце ўліковыя дадзеныя ў наладах плэйліста або выдаліце іх."
},
"NOT_FOUND": {
"TITLE": "Партал не знойдзены"
},
"UNKNOWN_ERROR": {
"TITLE": "Нешта пайшло не так",
"DESCRIPTION": "Невядомая памылка. Паўтарыце спробу пазней."
},
"PLAYLIST_SETTINGS": "Налады плэйліста"
},
"STREAM_URL_COPIED": "URL-адрас патоку быў скапіяваны ў буфер абмену.",
"EMPTY_LIST_VIEW": {
"NO_SEARCH_RESULTS": "Нічога не знойдзена, паспрабуйце змяніць пошукавы запыт"
},
"REMOVED_FROM_FAVORITES": "Выдалена з выбранага",
"ADDED_TO_FAVORITES": "Дададзена ў выбранае",
"SEARCH_VIEW": {
"RESULTS_FOUND": "Знойдзена {{count}} вынікаў",
"NO_RESULTS_FOR": "Не знойдзена вынікаў для \"{{term}}\""
}
},
"INFORMATION": "Інфармацыя",
"WORKSPACE": {
"SHELL": {
"GO_TO_DASHBOARD": "Back to dashboard",
"GO_TO_SOURCES": "Go to Sources",
"DROP_OVERLAY_TITLE": "Drop to add playlist",
"DROP_OVERLAY_BODY": "Release an .m3u or .m3u8 file anywhere in the workspace to import it.",
"DROP_OVERLAY_REJECTED_BODY": "Please drop an .m3u or .m3u8 file. Press Esc to dismiss.",
"DROP_OVERLAY_REJECTED_UNSUPPORTED": "Unsupported file type",
"DROP_OVERLAY_REJECTED_EMPTY": "That file is empty",
"DROP_OVERLAY_REJECTED_READ_ERROR": "Could not read that file",
"DROP_IMPORT_SUCCESS": "Importing \"{{title}}\"…",
"COMMANDS": {
"ADD_PLAYLIST_M3U_LABEL": "Add M3U playlist",
"ADD_PLAYLIST_M3U_DESCRIPTION": "Open add dialog on the M3U file or URL tab",
"ADD_PLAYLIST_XTREAM_LABEL": "Add Xtream Codes playlist",
"ADD_PLAYLIST_XTREAM_DESCRIPTION": "Open add dialog on the Xtream Codes tab",
"ADD_PLAYLIST_STALKER_LABEL": "Add Stalker portal",
"ADD_PLAYLIST_STALKER_DESCRIPTION": "Open add dialog on the Stalker Portal tab"
},
"EXTERNAL_PLAYBACK_CLOSE": "Close player"
},
"GLOBAL_FAVORITES": {
"NO_PLAYLISTS_TITLE": "No favorites to show",
"NO_PLAYLISTS_BODY": "Add a playlist to start collecting favorites from live channels, movies, and series.",
"NO_ITEMS_TITLE": "No favorites yet",
"NO_ITEMS_BODY": "Tap the star icon on any channel, movie, or series to save it here."
},
"GLOBAL_RECENT": {
"NO_PLAYLISTS_TITLE": "Nothing watched yet",
"NO_PLAYLISTS_BODY": "Add a playlist and your watching history will appear here.",
"NO_ITEMS_TITLE": "Nothing watched yet",
"NO_ITEMS_BODY": "Start watching anything from your library and it will show up here."
}
},
"DOWNLOADS": {
"NO_PLAYLISTS_TITLE": "Add a playlist to start downloading",
"NO_PLAYLISTS_BODY": "Once you add a playlist, you can save movies and episodes here for offline playback.",
"NO_ITEMS_BODY": "Use the download button on any movie or episode to save it for offline playback.",
"NO_FILTER_MATCH": "No downloads match the current filter",
"NO_FILTER_MATCH_HINT": "Try a different search term"
}
}
+820
View File
@@ -0,0 +1,820 @@
{
"CLOSE": "Schließen",
"PLAYLISTS": "Playlisten",
"CHANNELS": {
"ALL_CHANNELS": "Alle Sender",
"FAVORITES": "Favoriten",
"GROUPS": "Gruppen",
"MANAGE_GROUPS": "Gruppen verwalten",
"MANAGE_GROUPS_HINT": "Verwenden Sie \"Gruppen verwalten\", um Gruppen wieder einzublenden.",
"NO_FAVORITES": "Keine Favoriten",
"NO_VISIBLE_GROUPS": "Keine sichtbaren Gruppen",
"SEARCH_GROUPS": "Gruppen suchen",
"REMOVE_FAVORITE": "Aus Favoritenliste entfernen",
"SEARCH_CHANNEL": "Nach Sender suchen",
"UNGROUPED": "Ohne Gruppe",
"UNNAMED_CHANNEL": "Sender ohne Namen",
"UPLOAD_OR_SELECT_OTHER_PLAYLIST": "Neue Playlist hochladen oder eine andere aussuchen",
"USE_STAR_TO_FAVORITE": "Nutzen Sie das Star-Icon um Sender als Favoriten zu markieren",
"FAVORITES_UPDATED": "Favoriten wurden aktualisiert!",
"SELECT_CHANNEL_PLAYBACK": "Bitte wählen Sie einen Sender aus, um die Wiedergabe zu starten",
"SORT_BY": "Sortieren nach",
"SORT_BY_DATE": "Nach Datum sortieren (Neueste zuerst)",
"SORT_BY_RATING": "Nach Bewertung sortieren",
"SORT_BY_NAME": "Nach Name sortieren (A-Z)",
"GROUP_MANAGEMENT": {
"TITLE": "Gruppen verwalten",
"SELECTED": "Ausgewählt",
"SELECT_ALL": "Alle auswählen",
"DESELECT_ALL": "Alle abwählen",
"SEARCH_PLACEHOLDER": "Gruppen suchen...",
"NO_RESULTS": "Keine passenden Gruppen gefunden",
"SAVE": "Speichern"
}
},
"EPG": {
"TITLE": "Elektronischer Programmführer",
"EPG_NOT_AVAILABLE_CHANNEL_DESCRIPTION": "Versuchen Sie bitte die TV-Guide Einstellungen zu ändern.",
"EPG_NOT_AVAILABLE_CHANNEL_TITLE": "Ups, leider ist das TV-Programm nicht verfügbar.",
"EPG_NOT_AVAILABLE_DATE": "Ups, leider ist das TV-Programm für das ausgewählte Datum nicht verfügbar",
"LIVE_NOW": "Live jetzt",
"LIVE_STREAM": "Live stream",
"NEXT_DAY": "Zum nächsten Tag",
"PREVIOUS_DAY": "Zum vorherigen Tag",
"TIMESHIFT_AVAILABLE": "Die Timeshift-Funktion (Archiv) ist verfügbar, klicken Sie an um abzuspielen",
"FETCH_EPG": "EPG-Daten werden geladen...",
"ERROR": "Ooops, EPG konnte nicht geladen werden",
"DOWNLOAD_SUCCESS": "EPG wurde erfolgreich geladen.",
"FETCH_SUCCESS": "EPG wurde erfolgreich abgerufen",
"PROGRAM_DIALOG": {
"PROGRAM_DETAILS": "Details zum TV-Programm",
"TITLE": "Titel",
"CATEGORY": "Kategorie",
"PARENTAL_RATING_SYSTEM": "Alterskennzeichnung (USK)",
"DESCRIPTION": "Beschreibung",
"LANGUAGE": "Sprache",
"SHOW_PROGRAM_DETAILS": "Details anzeigen"
}
},
"HOME": {
"SUBTITLE": "Wählen Sie eine Playlist aus oder laden Sie eine neue Playlist hoch",
"TITLE": "IPTVnator",
"FILE_UPLOAD": {
"CHOOSE_PLAYLIST": "Playlist auswählen",
"DRAG_DROP": "Ziehen Sie Dateien per Drag & Drop",
"OR": "oder",
"REJECTED": "Datei wurde abgelehnt, nicht unterstütztes Dateiformat {{filename}}."
},
"PLAYLISTS": {
"ADDED": "Hinzugefügt am",
"ADDED_VIA_FILE": "Diese Playlist wurde aus dem Dateisystem hochgeladen",
"ADDED_VIA_URL": "Diese Playlist wurde von der URL hinzugefügt",
"ADD_FIRST": "Bitte fügen Sie eine neue Playlist hinzu",
"CHANNELS": "TV-Sender",
"NO_PLAYLISTS": "Noch keine Playlisten hinzugefügt",
"WELCOME_TITLE": "Willkommen bei IPTVnator",
"WELCOME_DESCRIPTION": "Beginnen Sie Ihre Streaming-Reise, indem Sie Ihre erste Playlist hinzufügen. Verbinden Sie sich mit Ihrem bevorzugten IPTV-Dienst und genießen Sie Live-TV, Filme und Serien.",
"ADD_YOUR_FIRST": "Ihre erste Playlist hinzufügen",
"FEATURE_M3U": "M3U/M3U8-Dateien",
"FEATURE_XTREAM": "Xtream Codes",
"FEATURE_STALKER": "Stalker Portal",
"NO_RESULTS_TITLE": "Keine Playlisten gefunden",
"NO_RESULTS_DESCRIPTION": "Keine Playlisten entsprechen Ihrer Suche. Versuchen Sie, Ihre Suchbegriffe anzupassen oder löschen Sie den Filter, um alle Playlisten anzuzeigen.",
"REMOVE": "Playlist entfernen",
"SHOW_DETAILS": "Details anzeigen",
"SEARCH_PLAYLISTS": "Suche nach Playlisten",
"INFO_DIALOG": {
"CHANNELS": "Anzahl von Sender",
"CLOSE": "Schließen",
"FROM_URL": "Von der URL hinzugefügt",
"IMPORT_DATE": "Hinzugefügt am",
"PLAYLIST_DETAILS": "Infos über die Playlist",
"TITLE": "Titel",
"USER_AGENT": "User agent",
"SAVE": "Speichern",
"ORIGINAL_FILENAME": "Original-Dateinamen",
"FILE_PATH": "Dateipfad",
"UPDATE_FAILED": "Update fehlgeschlagen",
"AUTO_UPDATE": "Auto-update",
"AUTO_UPDATE_DESCRIPTION": "Wenn die Auto-Refresh-Funktion aktiviert ist, wird die Wiedergabeliste bei jedem Start der Anwendung automatisch aktualisiert.",
"CUSTOM_USER_AGENT": "Einige IPTV-Anbieter benötigen einen bestimmten 'User-Agent', um ihre Playlist abspielen zu können.",
"EXPORT_PLAYLIST": "Als m3u exportieren",
"PASSWORD": "Passwort",
"SERVER_URL": "Server-URL",
"USERNAME": "Nutzername",
"MAC_ADDRESS": "MAC-Adresse",
"PLAYLIST_EXPORT_SUCCESS": "Playlist wurde erfolgreich exportiert.",
"PLAYLIST_EXPORT_ERROR": "Fehler: Playlist-Export fehlgeschlagen."
},
"UPDATED": "Aktualisiert am",
"REFRESH": "Aktualisieren",
"REFRESH_XTREAM": "Xtream-Playlist vom Server aktualisieren",
"REFRESH_XTREAM_DIALOG": {
"TITLE": "Xtream-Playlist aktualisieren",
"MESSAGE": "Dadurch werden lokal zwischengespeicherte Kategorien und Streams gelöscht und alles vom Remote-Server erneut importiert. Ihre Favoriten und kürzlich angesehenen Elemente bleiben erhalten. Möchten Sie wirklich fortfahren?",
"STARTED": "Aktualisierung gestartet. Navigation zur Playlist...",
"ERROR": "Playlist-Aktualisierung fehlgeschlagen. Bitte versuchen Sie es erneut.",
"IN_PROGRESS": "Playlist wird aktualisiert...",
"COLLECTING_DATA": "Favoriten und zuletzt angesehene Inhalte werden gesammelt...",
"DELETING_CONTENT": "Zwischengespeicherte Inhalte werden entfernt...",
"DELETING_CATEGORIES": "Zwischengespeicherte Kategorien werden entfernt..."
},
"REMOVE_DIALOG": {
"MESSAGE": "Sind Sie sicher, dass Sie diese Wiedergabeliste vollständig löschen möchten",
"TITLE": "Wiedergabeliste entfernen",
"SUCCESS": "Playlist wurde erfolgreich entfernt",
"IN_PROGRESS": "Wiedergabeliste wird entfernt...",
"DELETING_FAVORITES": "Favoriten werden entfernt...",
"DELETING_RECENT": "Zuletzt angesehene Inhalte werden entfernt...",
"DELETING_PROGRESS": "Wiedergabefortschritt wird entfernt...",
"DELETING_DOWNLOADS": "Downloads werden entfernt...",
"DELETING_CONTENT": "Zwischengespeicherte Inhalte werden entfernt...",
"DELETING_CATEGORIES": "Kategorien werden entfernt...",
"DELETING_PLAYLIST": "Playlist-Eintrag wird entfernt..."
},
"GLOBAL_FAVORITES": "Globale Favoriten",
"GLOBAL_FAVORITES_DESCRIPTION": "Automatisch generierte Playlist mit aggregierten Favoriten aus allen Playlists",
"MY_PLAYLISTS": "Meine Playlisten",
"MY_PLAYLISTS_SUBTITLE": "Alle verfügbaren Playlisten",
"PLAYLIST_UPDATE_SUCCESS": "Erfolg! Die Playlist wurde erfolgreich aktualisiert.",
"PLAYLIST_UPDATE_ERROR": "Fehler beim Aktualisieren der Playlist-Details.",
"AUTO_REFRESH_UPDATE_SUCCESS": "Erfolg! Die Playlists wurden erfolgreich aktualisiert",
"AUTO_REFRESH_ENABLED": "Auto-Refresh aktiviert",
"STALKER_PORTAL": "Stalker-Portal",
"XTREAM_PLAYLIST": "Xtream-Playlist",
"FEATURE_M3U_LABEL": "Add an M3U file or URL",
"FEATURE_XTREAM_LABEL": "Connect via Xtream Codes",
"FEATURE_STALKER_LABEL": "Connect to a Stalker portal",
"VALUE_PROPS_LABEL": "What you can do",
"VALUE_PROP_LIVE": "Live TV with EPG",
"VALUE_PROP_VOD": "Movies & Series",
"VALUE_PROP_MULTISOURCE": "Multi-source library",
"VALUE_PROP_OFFLINE": "Offline downloads",
"DASHBOARD_WELCOME_TAGLINE": "Your IPTV library, in one place.",
"FEATURE_LIVE_TITLE": "Live TV",
"FEATURE_LIVE_DESC": "Stream live channels with full schedule.",
"FEATURE_VOD_TITLE": "Movies & Series",
"FEATURE_VOD_DESC": "On-demand library with covers and details.",
"FEATURE_EPG_TITLE": "EPG & Catch-up",
"FEATURE_EPG_DESC": "Program guide and time-shifted playback.",
"FEATURE_OFFLINE_TITLE": "Offline downloads",
"FEATURE_OFFLINE_DESC": "Save movies and episodes for later.",
"SOURCES_WELCOME_TITLE": "Add your first playlist",
"SOURCES_WELCOME_BODY": "Pick a source type below to get started.",
"SOURCE_M3U_NEEDS": "Local file or URL pointing to an M3U/M3U8 playlist.",
"SOURCE_M3U_ADD": "Add M3U",
"SOURCE_XTREAM_NEEDS": "Username, password and server URL from your provider.",
"SOURCE_XTREAM_ADD": "Add Xtream",
"SOURCE_STALKER_NEEDS": "Portal URL and MAC address (Ministra-compatible).",
"SOURCE_STALKER_ADD": "Add Stalker",
"CONTENT_LIVE": "Live",
"CONTENT_VOD": "Movies",
"CONTENT_SERIES": "Series",
"CONTENT_EPG": "EPG",
"DASHBOARD_WELCOME_DESCRIPTION": "Connect M3U files, Xtream Codes, or Stalker portals — then enjoy live TV, movies and series on every screen."
},
"TABS": {
"FILE_UPLOAD": "Aus Dateisystem hochladen",
"RECENTLY_ADDED": "Zuletzt hinzugefügt",
"URL_UPLOAD": "Via URL hinzufügen",
"TEXT_IMPORT": "Als Text importieren",
"XTREME_IMPORT": "Xtreme-Code hinzufügen",
"STALKER_PORTAL_IMPORT": "Stalker-Portal hinzufügen"
},
"URL_UPLOAD": {
"ADD_PLAYLIST": "Playlist hinzufügen",
"PLAYLIST_URL": "URL der Playlist",
"CORS_NOTE": "Hinweis: Um CORS-Probleme zu vermeiden, verwendet die Anwendung an dieser Stelle einen öffentlichen CORS-Proxy-Dienst. Wenn Sie eine Playlist mit sensiblen Daten hochladen möchten, ist es sicherer, sie aus einer Datei zu importieren."
},
"TEXT_IMPORT": {
"LABEL": "Füge m3u(8)-Wiedergabeliste hier als Text ein",
"BUTTON_LABEL": "Importieren"
},
"XTREAM_PLAYLIST": {
"TITLE": "Playlist Titel",
"SERVER_URL": "Server URL",
"USERNAME": "Nutzername",
"PASSWORD": "Passwort",
"ADD": "Hinzufügen",
"TEST_CREDENTIALS": "Verbindung testen",
"URL_VALIDATION_ERROR": "Sollte eine gültige URL mit Protokoll sein (z. B. http://example.com oder https://example.com:4324)"
},
"STALKER_PORTAL": {
"ADD": "Hinzufügen",
"TITLE": "Titel",
"SERVER_URL": "Server-URL",
"MAC_ADDRESS": "Mac-Adresse",
"URL_VALIDATION_ERROR": "Sollte eine gültige URL mit Protokoll sein (z. B. http://example.com/c oder https://example.com/stalker_portal/c)"
},
"FILTER_BY_TYPE": "Playlist-Typen",
"FILTER_BY_NAME": "Nach Namen filtern",
"FILTER_AND_SORT": "Filtern & Sortieren",
"SORT_PLAYLISTS": "Playlisten sortieren",
"SORT_BY": "Sortieren nach",
"SORT_OPTIONS": {
"NAME_ASC": "Name (A-Z)",
"NAME_DESC": "Name (Z-A)",
"NEWEST": "Hinzugefügt (Neueste zuerst)",
"OLDEST": "Hinzugefügt (Älteste zuerst)"
},
"PLAYLIST_TYPES": {
"M3U": "M3U (lokal, URL, Text)",
"XTREAM": "Xtream",
"STALKER": "Stalker"
},
"IMPORTED_AS_TEXT": "Als Text importiert",
"PARSING_ERROR": "Fehler: Parsen fehlgeschlagen, keine gültige Playlist:"
},
"LANGUAGES": {
"ARABIC": "العربية",
"MOROCCAN_ARABIC": "العربية (اللهجة المغربية)",
"ENGLISH": "English",
"KOREAN": "한국어",
"RUSSIAN": "Русский",
"GERMAN": "Deutsch",
"SPANISH": "Español",
"CHINESE": "简体中文",
"TRADITIONAL_CHINESE": "繁體中文",
"FRENCH": "Français",
"ITALIAN": "Italiano",
"TURKISH": "Türkçe",
"JAPANESE": "日本語",
"DUTCH": "Nederlands",
"BELARUSIAN": "Беларуская",
"POLISH": "Polski",
"PORTUGUESE": "Português",
"GREEK": "Ελληνικά"
},
"SETTINGS": {
"BACK_TO_HOME": "Zurück",
"DESCRIPTION": "Bitte vergessen Sie nicht die Änderungen mit dem Speicher-Button zu bestätigen",
"GENERAL": "Allgemein",
"GENERAL_SUBTITLE": "Allgemeine App-Einstellungen ändern",
"PLAYBACK": "Wiedergabe",
"EPG_SOURCES": "EPG-Quellen",
"EPG_SOURCES_DESCRIPTION": "Eine oder mehrere URLs als EPG-Quellen hinzufügen",
"DATA": "Daten",
"ABOUT": "Info",
"NAV_GENERAL": "Allgemein",
"NAV_PLAYBACK": "Wiedergabe",
"NAV_EPG": "EPG",
"NAV_REMOTE": "Remote",
"NAV_DATA": "Daten",
"NAV_ABOUT": "Info",
"APP_PREFERENCES": "App-Einstellungen",
"HERO_EYEBROW": "Arbeitsbereich",
"HERO_TITLE": "IPTVnator anpassen",
"HERO_DESCRIPTION": "Passen Sie Wiedergabe, Programmführer, Fernzugriff und Datenverwaltung zentral an, ohne den Stil des Arbeitsbereichs zu verlieren.",
"EPG_URL_LABEL": "TV-Programm (EPG) URL",
"EPG_URL_PLACEHOLDER": "URL eingeben",
"LANGUAGE": "Sprache",
"LATEST_VERSION": "Sie nutzen die neueste Version der Anwendung",
"NEW_VERSION_AVAILABLE": "EIne neue Version der Anwendung ist verfügbar",
"REFRESH_EPG": "TV-Programm aktualisieren",
"REFRESH_ALL_EPG": "Alle aktualisieren",
"REMOVE_EPG_SOURCE": "EPG-Quelle entfernen",
"EPG_STATUS_FRESH": "Aktuell",
"EPG_STATUS_STALE": "Aktualisierung nötig",
"EPG_STATUS_ERROR": "Fehlgeschlagen",
"SAVE_CHANGES": "Änderungen speichern",
"SUBTITLE": "Die App-Einstellungen ändern",
"TITLE": "Einstellungen",
"VERSION": "Version",
"VIDEO_PLAYER_LABEL": "Videoplayer",
"PLAYER_HTML5": "HTML5-Videoplayer",
"PLAYER_VIDEOJS": "Video.js-Player",
"PLAYER_ARTPLAYER": "ArtPlayer",
"PLAYER_MPV": "MPV-Player",
"PLAYER_VLC": "VLC",
"VIDEO_PLAYER_PLACEHOLDER": "Option auswählen",
"STREAM_FORMAT": "Stream-Format",
"SETTINGS_SAVED": "Einstellungen wurden erfolgreich gespeichert!",
"THEME": "Farbdesign",
"SHOW_CAPTIONS": "Untertitel anzeigen",
"SHOW_DASHBOARD": "Dashboard anzeigen",
"SHOW_DASHBOARD_DESCRIPTION": "Dashboard in der Workspace-Leiste verfügbar halten. Wenn deaktiviert, wird Quellen zur ersten Workspace-Seite.",
"STREAM_FORMAT_DESCRIPTION": "Standard-Streamformat auswählen (Xtream)",
"REMOVE_ALL": "Delete all playlists and playlist data",
"REMOVE_ALL_BUTTON": "Delete all",
"CLEAR_EPG_DATA": "EPG-Daten löschen",
"CLEAR_EPG_DIALOG": {
"TITLE": "EPG-Daten löschen",
"MESSAGE": "Möchten Sie wirklich alle EPG-Daten aus der Datenbank entfernen? Dadurch werden alle zwischengespeicherten Programmdaten gelöscht."
},
"EPG_DATA_CLEARED": "EPG-Daten wurden gelöscht",
"EPG_DATA_CLEAR_FAILED": "EPG-Daten konnten nicht gelöscht werden. Bitte erneut versuchen.",
"CLEARING_EPG_DATA": "Wird gelöscht…",
"REMOVE_DIALOG": {
"TITLE": "Delete all playlists?",
"MESSAGE": "Delete all {{count}} playlists from the app. This also removes stored playlist data on this device.",
"SUMMARY_TITLE": "Playlist sources",
"CONSEQUENCES_TITLE": "This also removes",
"CONSEQUENCE_FAVORITES": "Favorites saved for these playlists",
"CONSEQUENCE_RECENTLY_VIEWED": "Recently viewed history",
"CONSEQUENCE_PLAYBACK": "Saved playback positions",
"CONSEQUENCE_DOWNLOADS": "Download history entries linked to those playlists",
"CONSEQUENCE_XTREAM_CACHE": "Imported Xtream categories and locally cached content",
"BACKUP_HINT": "Use Export first if you want a restorable backup before deleting.",
"CONFIRM": "Delete everything"
},
"LANGUAGE_DESCRIPTION": "Wählen Sie die Sprache der Anwendung aus",
"PLAYLISTS_REMOVED": "All playlists and playlist data were removed.",
"VERSION_DESCRIPTION": "Aktuelle Version der Anwendung",
"ABOUT_SUBTITLE": "Version, Projekt-Links und Möglichkeiten, IPTVnator zu unterstützen.",
"COMMUNITY": "Projekt & Community",
"COMMUNITY_DESCRIPTION": "Gib dem Repository einen Stern, lies den Blog oder tritt der Telegram-Gruppe für Updates und Hilfe bei.",
"LINK_BLOG": "Blog",
"LINK_GITHUB_DESCRIPTION": "Stern vergeben, Issues melden oder beitragen",
"LINK_BLOG_DESCRIPTION": "Release Notes, Tipps und Projekt-Updates",
"LINK_TELEGRAM_DESCRIPTION": "Ankündigungen, Community und Support",
"SUPPORT_TITLE": "Projekt unterstützen",
"SUPPORT_DESCRIPTION": "IPTVnator ist kostenlose Open-Source-Software, die im Offenen entwickelt wird. Wenn sie Teil deines Alltags ist, hilft ein kleiner Beitrag, das Projekt am Leben zu halten und die nächsten Schritte zu gestalten — danke!",
"SUPPORT_SPONSORS_HINT": "Wiederkehrend oder einmalig",
"SUPPORT_KOFI_HINT": "Spendiere einen Kaffee",
"REMOVE_ALL_DESCRIPTION": "Delete every M3U, Xtream, and Stalker playlist stored in the app.",
"MPV_PLAYER_PATH": "MPV-Player-Pfad",
"SHOW_CAPTIONS_DESCRIPTION": "Untertitel standardmäßig ein- oder ausblenden",
"SHOW_EXTERNAL_PLAYBACK_BAR": "Now-Playing-Fußleiste anzeigen",
"SHOW_EXTERNAL_PLAYBACK_BAR_DESCRIPTION": "Zeigt die Statusleiste für externe Player unten im Arbeitsbereich auf dem Desktop an.",
"IMPORT_DATA": "Import",
"ADD_EPG_SOURCE": "EPG-Quelle hinzufügen",
"IMPORT_ERROR": "Importfehler. Bitte versuchen Sie es mit einer anderen Datei.",
"EPG_URL_ERROR": "Der Wert ist keine gültige URL",
"EXPORT_DATA": "Export",
"VIDEO_PLAYER_DESCRIPTION": "Wählen Sie den Standard-Videoplayer aus",
"IMPORT_EXPORT_DATA": "Wiedergabelisten importieren/exportieren",
"VLC_PLAYER_PATH_LABEL": "VLC-Pfad",
"VLC_PLAYER_PATH_DESCRIPTION": "Legen Sie den Pfad zum VLC-Player in Ihrem System fest. \nEs wird der bereitgestellte Pfad zu einer VLC-Binärdatei anstelle des Standardpfads für unser System verwendet.",
"THEME_DESCRIPTION": "Wählen Sie das visuelle Thema der Anwendung aus",
"STARTUP_BEHAVIOR": "Startansicht",
"STARTUP_BEHAVIOR_DESCRIPTION": "Legen Sie fest, ob IPTVnator die erste verfügbare Workspace-Ansicht oder Ihre zuletzt geöffnete Abschnittsansicht startet. Erste Ansicht bedeutet Dashboard, wenn aktiviert, sonst Quellen.",
"STARTUP_BEHAVIOR_FIRST_VIEW": "Erste verfügbare Ansicht",
"STARTUP_BEHAVIOR_RESTORE_LAST_VIEW": "Letzte Ansicht wiederherstellen",
"EPG_NOTE": "Derzeit ist EPG nur in der Electron-basierten Version von IPTVnator verfügbar.",
"VLC_PLAYER_PATH": "VLC-Playerpfad",
"IMPORT_EXPORT_DATA_DESCRIPTION": "Exportieren oder importieren Sie Wiedergabelisten im JSON-Format, das in der Anwendung verwendet wird.",
"EPG_NOTE_URL_TEXT": "Überprüfen Sie es hier",
"MPV_PLAYER_PATH_LABEL": "MPV-Pfad",
"MPV_PLAYER_PATH_DESCRIPTION": "Legen Sie den Pfad zum MPV-Player in Ihrem System fest. Es wird der bereitgestellte Pfad zu einer MPV-Binärdatei anstelle des in $PATH gefundenen verwendet.",
"MPV_REUSE_INSTANCE_LABEL": "MPV-Instanz wiederverwenden",
"MPV_REUSE_INSTANCE_DESCRIPTION": "Wenn aktiviert, wird dasselbe MPV-Fenster zum Abspielen verschiedener Streams wiederverwendet. Wenn deaktiviert, wird jeder Stream in einem neuen MPV-Fenster geöffnet.",
"REMOTE_CONTROL": "Fernsteuerung",
"REMOTE_CONTROL_DESCRIPTION": "Fernsteuerung der Anwendung aktivieren.",
"REMOTE_CONTROL_PORT": "Fernsteuerungsport",
"REMOTE_CONTROL_PORT_DESCRIPTION": "Port für die Fernsteuerung der Anwendung. Standardmäßig wird Port 8765 verwendet.",
"REMOTE_CONTROL_URL": "Fernsteuerungs-URL",
"REMOTE_CONTROL_URL_DESCRIPTION": "Greifen Sie von einem anderen Gerät im selben Netzwerk auf die Fernsteuerung zu.",
"SHOW_QR_CODE": "QR-Code anzeigen",
"STATUS_ENABLED": "Aktiv",
"STATUS_DISABLED": "Deaktiviert",
"SOURCE_SINGULAR": "Quelle",
"SOURCE_PLURAL": "Quellen",
"PORT_RANGE_LABEL": "Port (1-65535)",
"PORT_REQUIRED": "Port ist erforderlich",
"PORT_MIN": "Port muss mindestens 1 sein",
"PORT_MAX": "Port darf maximal 65535 sein",
"PORT_PATTERN": "Nur Ziffern sind erlaubt",
"REMOVE_ALL_IN_PROGRESS": "Deleting playlist data…",
"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.",
"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",
"LIGHT_THEME": "Hell",
"SYSTEM_THEME": "System"
},
"TOP_MENU": {
"OPEN_CHANNELS_LIST": "Senderliste öffnen",
"OPEN_EPG_LIST": "TV-Guide (EPG) öffnen",
"TOGGLE_FAVORITE_FLAG": "Als Favoriten hinzufügen/entfernen",
"OPEN_MULTI_EPG": "Open Multi-EPG view"
},
"NO": "Nein",
"YES": "Ja",
"MENU": {
"OPEN": "Menü öffnen",
"SUPPORT_ARIA": "IPTVnator auf GitHub unterstützen",
"SETTINGS": "Einstellungen",
"SETTINGS_ARIA": "Einstellungen öffnen",
"BUG_REPORT": "Fehler melden",
"WHAT_IS_NEW": "Was ist neu",
"ABOUT": "Über",
"ABOUT_ARIA": "Über die Anwendung",
"SUPPORT_PROJECT": "Projekt unterstützen"
},
"XTREAM": {
"RELEASE_DATE": "Veröffentlichungsdatum",
"ACTORS": "Schauspieler",
"PLAY": "Abspielen",
"OPENING_PLAYER": "Player wird geöffnet...",
"GENRE": "Genre",
"DURATION": "Dauer",
"COUNTRY": "Land",
"NAME": "Name",
"DIRECTOR": "Regisseur",
"CAST": "Gießen",
"RATING": "Bewertung",
"AGE": "Alter",
"EPISODE": "Folge",
"RESUME": "Fortsetzen",
"RESTART": "Neu starten",
"CONTINUE_WATCHING": "Weiter schauen",
"WATCHED": "Angesehen",
"IN_PROGRESS": "In Wiedergabe",
"MARK_WATCHED": "Als angesehen markieren",
"MARK_UNWATCHED": "Als nicht angesehen markieren",
"EPISODES_WATCHED": "{{count}} von {{total}} Folgen angesehen",
"DETAIL_FALLBACK": {
"STATUS": "Portal-Metadaten fehlen",
"NOTE": "Dieses Portal hat keine erweiterten Metadaten für diesen Titel geliefert.",
"STREAM_ID": "Stream-ID",
"CATEGORY": "Kategorie",
"CONTAINER": "Format",
"SOURCE_TITLE": "Quellentitel"
},
"YEAR": "Jahr",
"YOUTUBE_TRAILER": "YouTube-Trailer",
"DESCRIPTION": "Beschreibung",
"KINOPOISK_RATING": "Bewertung Kinopoisk",
"IMDB_RATING": "IMDB-Bewertung",
"EPISODE_RUN_TIME": "Laufzeit der Episode",
"ACCOUNT_INFO": {
"TITLE": "Kontoinformationen",
"USER_INFO": "Benutzerinformationen",
"STATUS": "Status",
"USERNAME": "Benutzername",
"ACTIVE_CONNECTIONS": "Aktive Verbindungen",
"CREATED": "Erstellt",
"EXPIRES": "Läuft ab",
"TRIAL_ACCOUNT": "Testkonto",
"YES": "Ja",
"NO": "Nein",
"ALLOWED_FORMATS": "Zulässige Formate",
"SERVER_INFO": "Serverinformationen",
"LIVE_TV": "Live-TV",
"MOVIES": "Filme",
"TV_SERIES": "Serien",
"URL": "URL",
"PROTOCOL": "Protokoll",
"TIMEZONE": "Zeitzone",
"SERVER_TIME": "Serverzeit",
"PORTS": "Ports",
"HTTP_PORT": "HTTP",
"HTTPS_PORT": "HTTPS",
"RTMP_PORT": "RTMP"
}
},
"PORTALS": {
"SIDEBAR": {
"MAIN": "Allgemein",
"MOVIES": "Filme",
"LIVE_TV": "Live TV",
"SERIES": "Serien",
"LIBRARY": "Bibliothek",
"SEARCH": "Suche",
"RECENT": "Zuletzt angesehen",
"FAVORITES": "Favoriten",
"HOME": "Startseite",
"PLAYLIST_INFO": "Playlist-Info",
"ACCOUNT_INFO": "Account-Info"
},
"ALL_CATEGORIES": "Alle Kategorien",
"ADD_TO_FAVORITES": "Zu den Favoriten hinzufügen",
"REMOVE_FROM_FAVORITES": "Von Favoriten entfernen",
"MY_FAVORITES": "Meine Favoriten",
"COPY_STREAM_URL": "Stream-URL kopieren",
"ERROR_VIEW": {
"DELETE": "Löschen",
"IMPORT_CANCELLED": {
"TITLE": "Import abgebrochen",
"DESCRIPTION": "Der Playlist-Import wurde abgebrochen. Wiederholen Sie ihn, wenn Sie diese Quelle erneut laden möchten."
},
"ACCOUNT_EXPIRED": {
"TITLE": "Konto abgelaufen",
"DESCRIPTION": "Dieses Konto ist abgelaufen. \nBitte überprüfen Sie die Anmeldeinformationen in den Playlist-Einstellungen oder entfernen Sie sie."
},
"ACCOUNT_INACTIVE": {
"TITLE": "Konto inaktiv",
"DESCRIPTION": "Dieses Konto ist inaktiv. Bitte überprüfen Sie die Anmeldeinformationen in den Playlist-Einstellungen oder entfernen Sie es."
},
"HOME": "Startseite",
"EMPTY_CATEGORY": {
"TITLE": "Leere Kategorie",
"DESCRIPTION": "Diese Kategorie hat keinen Inhalt. Bitte wählen Sie eine andere Kategorie aus oder ändern Sie den Inhaltstyp"
},
"NO_CATEGORY_SELECTED": {
"TITLE": "Keine Kategorie ausgewählt",
"DESCRIPTION": "Bitte wählen Sie eine Kategorie aus, um den Inhalt anzuzeigen"
},
"UNAUTHORIZED": {
"TITLE": "Nicht autorisiert",
"DESCRIPTION": "Bitte überprüfen Sie die Anmeldeinformationen in den Playlist-Einstellungen oder entfernen Sie sie."
},
"NOT_FOUND": {
"TITLE": "Portal nicht gefunden",
"DESCRIPTION": "Bitte überprüfen Sie die Anmeldeinformationen und die Portal-URL in den Playlist-Einstellungen oder entfernen Sie sie."
},
"PORTAL_UNAVAILABLE": {
"TITLE": "Portal nicht erreichbar",
"DESCRIPTION": "Das Portal konnte nicht erreicht werden. Überprüfen Sie die Server-URL oder versuchen Sie es erneut, wenn die Quelle wieder verfügbar ist."
},
"UNKNOWN_ERROR": {
"TITLE": "Etwas ist schief gelaufen",
"DESCRIPTION": "Unbekannter Fehler, bitte versuchen Sie es später noch einmal"
},
"PLAYLIST_SETTINGS": "Playlist-Einstellungen"
},
"STREAM_URL_COPIED": "Stream-URL in die Zwischenablage kopiert",
"EMPTY_LIST_VIEW": {
"TITLE": "Keine Ergebnisse gefunden",
"NO_SEARCH_RESULTS": "Nichts gefunden. Versuchen Sie, Ihre Suchanfrage zu ändern"
},
"REMOVED_FROM_FAVORITES": "Aus den Favoriten entfernt",
"ADDED_TO_FAVORITES": "Zu den Favoriten hinzugefügt",
"SELECT_CATEGORY": "Wählen Sie eine Kategorie aus",
"PAGE": "Seite",
"SEARCH_VIEW": {
"RESULTS_FOUND": "{{count}} Ergebnisse gefunden",
"NO_RESULTS_FOR": "Keine Ergebnisse für \"{{term}}\" gefunden"
}
},
"ABOUT": {
"TITLE": "Über IPTVnator",
"DESCRIPTION": "Plattformübergreifende IPTV-Player-Anwendung mit mehreren Funktionen wie Unterstützung von M3U- und M3U8-Wiedergabelisten, Favoriten, TV-Guide, TV-Archiv/Catchup und mehr.",
"VERSION": "Version",
"TWITTER_TOOLTIP": "Auf Twitter teilen",
"GITHUB_TOOLTIP": "ITPVnator-Repository auf GitHub",
"BUY_ME_A_COFFEE_TOOLTIP": "Buy me a coffee"
},
"REFRESH": "Aktualisieren",
"UPDATE_AVAILABLE": "Update verfügbar",
"INFORMATION": "Information",
"DOWNLOADS": {
"TITLE": "Downloads",
"DOWNLOAD": "Herunterladen",
"PLAY_LOCAL": "Lokal abspielen",
"EMPTY": "Noch keine Downloads",
"EMPTY_HINT": "Filme und Episoden zum Offline-Ansehen herunterladen",
"NOT_AVAILABLE": "Downloads nicht verfügbar",
"DESKTOP_ONLY": "Diese Funktion ist nur in der Desktop-App verfügbar",
"NO_FOLDER": "Kein Download-Ordner ausgewählt",
"CHANGE_FOLDER": "Ordner ändern",
"CLEAR_COMPLETED": "Abgeschlossene löschen",
"CLEAR_COMPLETED_DIALOG": {
"TITLE": "Abgeschlossene Downloads löschen",
"MESSAGE": "Dadurch werden abgeschlossene, fehlgeschlagene und abgebrochene Einträge aus der aktuellen Download-Ansicht entfernt. Bereits auf der Festplatte gespeicherte Dateien werden nicht gelöscht."
},
"SOURCE_PLAYLIST_MISSING": "Dieser Download kann nicht mehr in der Bibliothek geöffnet werden, weil die zugehörige Playlist entfernt wurde.",
"FILE_NOT_FOUND": "Diese heruntergeladene Datei ist auf der Festplatte nicht mehr verfügbar.",
"FILE_ACTION_ERROR": "Die Dateiaktion konnte nicht ausgeführt werden.",
"CANCEL": "Abbrechen",
"RETRY": "Wiederholen",
"REMOVE": "Entfernen",
"PLAY": "Abspielen",
"REVEAL": "Im Ordner anzeigen",
"COPY_URL": "Download-URL kopieren",
"URL_COPIED": "Download-URL in die Zwischenablage kopiert",
"URL_COPY_FAILED": "URL konnte nicht kopiert werden",
"STATUS": {
"QUEUED": "In Warteschlange",
"DOWNLOADING": "Wird heruntergeladen",
"COMPLETED": "Abgeschlossen",
"FAILED": "Fehlgeschlagen",
"CANCELED": "Abgebrochen"
},
"NO_PLAYLISTS_TITLE": "Add a playlist to start downloading",
"NO_PLAYLISTS_BODY": "Once you add a playlist, you can save movies and episodes here for offline playback.",
"NO_ITEMS_BODY": "Use the download button on any movie or episode to save it for offline playback.",
"NO_FILTER_MATCH": "No downloads match the current filter",
"NO_FILTER_MATCH_HINT": "Try a different search term"
},
"REMOTE_CONTROL": {
"TITLE": "Fernbedienung",
"UP_CHANNEL": "Sender aufwärts",
"DOWN_CHANNEL": "Sender abwärts",
"HEADER": "IPTVNator Fernbedienung",
"FOOTER": "IPTVNator Fernbedienung"
},
"WORKSPACE": {
"FAVORITES_ONLY": "Nur Favoriten",
"SORT_CUSTOM": "Eigene Reihenfolge",
"SORT_DATE_DESC": "Datum (Neueste zuerst)",
"SORT_DATE_ASC": "Datum (Älteste zuerst)",
"SORT_NAME_ASC": "Name A-Z",
"SORT_NAME_DESC": "Name Z-A",
"SORT_LABEL": "Sortierung: ",
"DASHBOARD": {
"CONTINUE_WATCHING": "Weiter schauen",
"UNTITLED_SOURCE": "Unbenannte Quelle",
"GLOBAL_FAVORITES": "Globale Favoriten",
"REMOVE_FROM_HISTORY": "Aus Verlauf entfernen",
"RECENT_SOURCES": "Zuletzt verwendete Quellen",
"MANAGE_ALL": "Alle verwalten",
"RECENTLY_WATCHED": "Zuletzt angesehen",
"XTREAM_RECENTLY_ADDED": "Neu auf Xtream",
"NO_HISTORY": "Keine Elemente für diesen Filter gefunden.",
"NO_HISTORY_HINT": "Dein Wiedergabeverlauf erscheint hier, sobald du Inhalte aus deinen Playlists abspielst.",
"XTREAM": "Xtream",
"STALKER": "Stalker",
"M3U": "M3U",
"STALKER_PORTAL": "Stalker-Portal",
"PROVIDER": "Anbieter",
"TYPE_LIVE": "Live",
"TYPE_MOVIE": "Film",
"TYPE_SERIES": "Serie",
"NOT_YET_SYNCED": "Noch nicht synchronisiert"
},
"SHELL": {
"BRAND_ALT": "IPTVnator",
"RAIL_DASHBOARD": "Dashboard",
"OPEN_DASHBOARD": "Dashboard öffnen",
"RAIL_SOURCES": "Quellen",
"OPEN_SOURCES": "Quellen öffnen",
"RAIL_SETTINGS": "Einstellungen",
"OPEN_SETTINGS": "Einstellungen öffnen",
"RAIL_LIBRARY": "Bibliothek",
"RAIL_MOVIES": "Filme",
"RAIL_LIVE": "Live-TV",
"RAIL_SERIES": "Serien",
"RAIL_RECENTLY_ADDED": "Zuletzt hinzugefügt",
"RAIL_SEARCH": "Erweiterte Suche",
"RAIL_RECENT": "Zuletzt angesehen",
"RAIL_FAVORITES": "Favoriten",
"RAIL_DOWNLOADS": "Downloads",
"RAIL_ALL_CHANNELS": "Alle Sender",
"RAIL_GROUPS": "Gruppen",
"RAIL_CONTEXT_ACTIONS": "Bereichsaktionen",
"SEARCH_LABEL": "Suche",
"SEARCH_SOURCES_PLACEHOLDER": "Quellen durchsuchen (alle Playlists)...",
"SEARCH_PLAYLIST_PLACEHOLDER": "In dieser Playlist suchen...",
"SEARCH_SECTION_PLACEHOLDER": "In diesem Abschnitt suchen...",
"FILTER_SECTION_PLACEHOLDER": "Diesen Abschnitt filtern...",
"SEARCH_STATUS_LOADED_ONLY": "Nur geladene Sender",
"COMMAND_PALETTE_SHORTCUT": "Befehlspalette (Ctrl/Cmd+K)",
"OPEN_COMMAND_PALETTE": "Befehlspalette öffnen",
"ADD_PLAYLIST_ALL": "Playlist hinzufügen (alle Playlists)",
"ADD_PLAYLIST": "Playlist hinzufügen",
"OPEN_DOWNLOADS": "Downloads öffnen",
"OPEN_CONTEXT_ACTIONS": "Bereichsaktionen öffnen",
"NO_SECTION_ACTIONS": "Keine Aktionen für diesen Abschnitt",
"PLAYLIST_INFO": "Playlist-Info",
"ACCOUNT_INFO": "Kontoinfo",
"REFRESH_PLAYLIST": "Playlist aktualisieren",
"CLEAR_COMPLETED_DOWNLOADS_ALL": "Abgeschlossene Downloads löschen (alle Playlists)",
"CLEAR_COMPLETED_DOWNLOADS_ALL_ARIA": "Abgeschlossene Downloads für alle Playlists löschen",
"CLEAR_COMPLETED_DOWNLOADS_THIS_PLAYLIST": "Abgeschlossene Downloads löschen (diese Playlist)",
"CLEAR_COMPLETED_DOWNLOADS_THIS_PLAYLIST_ARIA": "Abgeschlossene Downloads für diese Playlist löschen",
"CLEAR_RECENTLY_VIEWED_SECTION": "Zuletzt angesehen löschen",
"CLEAR_RECENTLY_VIEWED_SECTION_ARIA": "Zuletzt angesehen für diesen Abschnitt löschen",
"CLEAR_RECENTLY_VIEWED_TYPE": "Zuletzt angesehen ({{type}}) löschen",
"CLEAR_RECENTLY_VIEWED_DIALOG_TITLE": "Zuletzt angesehen ({{type}}) löschen?",
"CLEAR_RECENTLY_VIEWED_DIALOG_MESSAGE_PLAYLIST": "Alle {{type}}-Einträge aus dieser Playlist werden aus dem Verlauf entfernt. Diese Aktion kann nicht rückgängig gemacht werden.",
"CLEAR_RECENTLY_VIEWED_DIALOG_MESSAGE_ALL": "Alle {{type}}-Einträge aus allen Playlists werden aus dem Verlauf entfernt. Diese Aktion kann nicht rückgängig gemacht werden.",
"CLEAR_FAVORITES_TYPE": "Favoriten ({{type}}) löschen",
"CLEAR_FAVORITES_DIALOG_TITLE": "Alle {{type}}-Favoriten entfernen?",
"CLEAR_FAVORITES_DIALOG_MESSAGE_PLAYLIST": "Alle {{type}}-Favoriten aus dieser Playlist werden entfernt. Diese Aktion kann nicht rückgängig gemacht werden.",
"CLEAR_FAVORITES_DIALOG_MESSAGE_ALL": "Alle {{type}}-Favoriten aus allen Playlists werden entfernt. Diese Aktion kann nicht rückgängig gemacht werden.",
"XTREAM_CODE": "Xtream Code",
"STALKER_PORTAL": "Stalker-Portal",
"CHANNELS_COUNT": "{{count}} Sender",
"NO_SOURCES_AVAILABLE": "Keine Quellen verfügbar",
"ONE_SOURCE_AVAILABLE": "1 Quelle verfügbar",
"SOURCES_AVAILABLE": "{{count}} Quellen verfügbar",
"XTREAM_IMPORT_TITLE": "Playlist wird synchronisiert",
"XTREAM_IMPORT_REMOTE_BADGE": "Remote-Quelle",
"XTREAM_IMPORT_LOCAL_BADGE": "Lokale Bibliothek",
"XTREAM_IMPORT_DETAIL_REMOTE": "Warte auf die Antwort des Providers.",
"XTREAM_IMPORT_DETAIL_LOCAL": "Bereitet schnellere Playlist-Wechsel für den nächsten Besuch vor.",
"XTREAM_IMPORT_PREPARING": "Lokale Bibliothek wird vorbereitet...",
"XTREAM_IMPORT_LOADING": "Playlist-Daten werden von der Quelle geladen...",
"XTREAM_IMPORT_SAVING": "Playlist-Daten werden lokal gespeichert...",
"XTREAM_IMPORT_RESTORING_FAVORITES": "Favoriten werden aus der lokalen Bibliothek wiederhergestellt...",
"XTREAM_IMPORT_RESTORING_RECENT": "Zuletzt angesehene Inhalte werden aus der lokalen Bibliothek wiederhergestellt...",
"XTREAM_IMPORT_PROGRESS": "{{type}} importiert: {{current}} / {{total}}",
"XTREAM_IMPORT_CANCEL": "Synchronisierung stoppen",
"XTREAM_IMPORT_CANCELLING": "Synchronisierung wird gestoppt...",
"COMMANDS": {
"GLOBAL_SEARCH_LABEL": "Alle Xtream-Playlists durchsuchen",
"GLOBAL_SEARCH_DESCRIPTION": "Globale Suchüberlagerung öffnen",
"PLAYLIST_SEARCH_LABEL": "Erweiterte Suche in dieser Playlist",
"PLAYLIST_SEARCH_DESCRIPTION": "Erweiterte Suchansicht der Playlist öffnen",
"OPEN_GLOBAL_FAVORITES_LABEL": "Globale Favoriten öffnen",
"OPEN_GLOBAL_FAVORITES_DESCRIPTION": "Zur aggregierten Favoritenansicht wechseln",
"OPEN_DOWNLOADS_LABEL": "Downloads öffnen",
"OPEN_DOWNLOADS_DESCRIPTION": "Zur Download-Ansicht wechseln",
"OPEN_GLOBAL_RECENT_LABEL": "Zuletzt angesehen öffnen",
"OPEN_GLOBAL_RECENT_DESCRIPTION": "Globale Zuletzt-angesehen-Seite öffnen",
"OPEN_SETTINGS_LABEL": "Einstellungen öffnen",
"OPEN_SETTINGS_DESCRIPTION": "Zu den Anwendungseinstellungen",
"OPEN_SOURCES_LABEL": "Quellen verwalten",
"OPEN_SOURCES_DESCRIPTION": "Zur Quellenverwaltung",
"OPEN_DASHBOARD_LABEL": "Dashboard öffnen",
"OPEN_DASHBOARD_DESCRIPTION": "Zum Dashboard navigieren",
"ADD_PLAYLIST_LABEL": "Neue Quelle hinzufügen",
"ADD_PLAYLIST_DESCRIPTION": "Dialog zum Hinzufügen öffnen",
"REFRESH_PLAYLIST_LABEL": "Playlist aktualisieren",
"REFRESH_PLAYLIST_DESCRIPTION": "Daten von der Quelle neu laden",
"PLAYLIST_INFO_LABEL": "Playlist-Details",
"PLAYLIST_INFO_DESCRIPTION": "Aktuelle Playlist-Informationen anzeigen",
"ACCOUNT_INFO_LABEL": "Kontoinformationen",
"ACCOUNT_INFO_DESCRIPTION": "Xtream-Server-Kontodaten anzeigen",
"OPEN_VIEW_DESCRIPTION": "Zu {{view}} wechseln",
"CLEAR_CURRENT_VIEW_DESCRIPTION": "Alle sichtbaren {{type}}-Einträge in dieser Ansicht löschen",
"OPEN_MULTI_EPG_DESCRIPTION": "Die Multi-EPG-Ansicht öffnen",
"GO_TO_VOD_LABEL": "Filme",
"GO_TO_VOD_DESCRIPTION": "Zum Filmbereich wechseln",
"GO_TO_LIVE_LABEL": "Live-TV",
"GO_TO_LIVE_DESCRIPTION": "Zum Live-TV-Bereich wechseln",
"GO_TO_SERIES_LABEL": "Serien",
"GO_TO_SERIES_DESCRIPTION": "Zum Serienbereich wechseln",
"ADD_PLAYLIST_M3U_LABEL": "Add M3U playlist",
"ADD_PLAYLIST_M3U_DESCRIPTION": "Open add dialog on the M3U file or URL tab",
"ADD_PLAYLIST_XTREAM_LABEL": "Add Xtream Codes playlist",
"ADD_PLAYLIST_XTREAM_DESCRIPTION": "Open add dialog on the Xtream Codes tab",
"ADD_PLAYLIST_STALKER_LABEL": "Add Stalker portal",
"ADD_PLAYLIST_STALKER_DESCRIPTION": "Open add dialog on the Stalker Portal tab"
},
"GO_TO_DASHBOARD": "Back to dashboard",
"GO_TO_SOURCES": "Go to Sources",
"DROP_OVERLAY_TITLE": "Drop to add playlist",
"DROP_OVERLAY_BODY": "Release an .m3u or .m3u8 file anywhere in the workspace to import it.",
"DROP_OVERLAY_REJECTED_BODY": "Please drop an .m3u or .m3u8 file. Press Esc to dismiss.",
"DROP_OVERLAY_REJECTED_UNSUPPORTED": "Unsupported file type",
"DROP_OVERLAY_REJECTED_EMPTY": "That file is empty",
"DROP_OVERLAY_REJECTED_READ_ERROR": "Could not read that file",
"DROP_IMPORT_SUCCESS": "Importing \"{{title}}\"…",
"EXTERNAL_PLAYBACK_CLOSE": "Close player"
},
"SOURCES": {
"TITLE": "Quellen",
"SUBTITLE": "Playlists filtern und sortieren",
"TYPE": "Typ",
"ALL": "Alle",
"M3U_PLAYLISTS": "M3U-Playlists",
"XTREAM_PLAYLISTS": "Xtream-Playlists",
"STALKER_PLAYLISTS": "Stalker-Playlists",
"ALL_PLAYLISTS": "Alle Playlists",
"PLAYLIST_COUNT_ONE": "1 Playlist",
"PLAYLIST_COUNT_OTHER": "{{count}} Playlists"
},
"CONTEXT": {
"CATEGORIES": "Kategorien",
"MOVIE_CATEGORIES": "Filmkategorien",
"SERIES_CATEGORIES": "Serienkategorien",
"LIVE_CATEGORIES": "Live-Kategorien",
"XTREAM_SYNCING_MOVIES": "Filmkategorien werden synchronisiert...",
"XTREAM_SYNCING_SERIES": "Serienkategorien werden synchronisiert...",
"XTREAM_SYNCING_LIVE": "Live-Kategorien werden synchronisiert...",
"XTREAM_SOURCE": "Xtream-Quelle",
"STALKER_PORTAL": "Stalker-Portal",
"MANAGE_CATEGORIES": "Kategorien verwalten",
"LOAD_CATEGORIES_ERROR": "Kategorien konnten nicht geladen werden",
"LOAD_CATEGORIES_ERROR_HINT": "Bitte erneut versuchen oder die Portal-Einstellungen prüfen.",
"FILTER_BY_TYPE": "Nach Typ filtern",
"ITEM_COUNT_ONE": "1 Element",
"ITEM_COUNT_OTHER": "{{count}} Elemente",
"SEARCH": "Suchen",
"SEARCH_CATEGORIES": "Kategorien suchen"
},
"COMMAND_PALETTE": {
"TITLE": "Befehlspalette",
"SUBTITLE": "Globale und kontextbezogene Aktionen",
"SEARCH_PLACEHOLDER": "Zum Filtern der Befehle tippen",
"SEARCH_LABEL": "Befehle filtern",
"EMPTY": "Keine Befehle gefunden",
"GROUP_GLOBAL": "Globale Aktionen",
"GROUP_PLAYLIST": "Diese Playlist",
"GROUP_VIEW": "Aktuelle Ansicht",
"GROUP_SECTION": "Dieser Abschnitt"
},
"GLOBAL_FAVORITES": {
"TITLE": "Globale Favoriten",
"SUBTITLE": "Live-TV aus allen Playlists",
"SEARCH_PLACEHOLDER": "Favoriten durchsuchen...",
"NO_RESULTS": "Keine Ergebnisse",
"NO_RESULTS_HINT": "Versuche einen anderen Suchbegriff",
"EMPTY_TITLE": "Noch keine Live-TV-Favoriten",
"EMPTY_HINT": "Markiere Live-Kanäle aus M3U-, Xtream- oder Stalker-Playlists mit einem Stern, damit sie hier erscheinen.",
"EMPTY_PLAYER": "Wähle einen Sender zum Starten",
"UNKNOWN_CHANNEL": "Unbekannt",
"NO_PLAYLISTS_TITLE": "No favorites to show",
"NO_PLAYLISTS_BODY": "Add a playlist to start collecting favorites from live channels, movies, and series.",
"NO_ITEMS_TITLE": "No favorites yet",
"NO_ITEMS_BODY": "Tap the star icon on any channel, movie, or series to save it here."
},
"GLOBAL_RECENT": {
"NO_PLAYLISTS_TITLE": "Nothing watched yet",
"NO_PLAYLISTS_BODY": "Add a playlist and your watching history will appear here.",
"NO_ITEMS_TITLE": "Nothing watched yet",
"NO_ITEMS_BODY": "Start watching anything from your library and it will show up here."
}
}
}
+551
View File
@@ -0,0 +1,551 @@
{
"CLOSE": "Κλείσιμο",
"PLAYLISTS": "Λίστα Αναπαραγωγής",
"HOME": {
"TITLE": "IPTVnator",
"SUBTITLE": "Παρακαλώ επιλέξτε μια λίστα αναπαραγωγής από την λίστα ή προσθέστε μια νέα",
"TABS": {
"RECENTLY_ADDED": "Λίστες που έχουν προστεθεί πρόσφατα",
"FILE_UPLOAD": "Προσθήκη αρχείου",
"URL_UPLOAD": "Προσθήκη διεύθυνσης URL",
"TEXT_IMPORT": "Προσθήκη κειμένου",
"XTREME_IMPORT": "Προσθήκη Xtreme Code",
"STALKER_PORTAL_IMPORT": "Προσθήκη Stalker Portal"
},
"PLAYLISTS": {
"NO_PLAYLISTS": "Δεν προστέθηκε λίστα αναπαραγωγής",
"ADD_FIRST": "Παρακαλώ προσθέστε την πρώτη σας λίστα",
"WELCOME_TITLE": "Καλώς ήλθατε στο IPTVnator",
"WELCOME_DESCRIPTION": "Ξεκινήστε την διασκέδαση προσθέτοντας την πρώτη σας λίστα αναπαραγωγής. Συνδεθείτε στην αγαπημένη σας υπηρεσία IPTV και απολαύστε ζωντανή τηλεόραση, ταινίες και σειρές.",
"ADD_YOUR_FIRST": "Προσθέστε την πρώτη σας λίστα αναπαραγωγής",
"FEATURE_M3U": "M3U/M3U8 Αρχεία",
"FEATURE_XTREAM": "Xtream Codes",
"FEATURE_STALKER": "Stalker Portal",
"NO_RESULTS_TITLE": "Δεν βρέθηκε λίστα αναπαραγωγής",
"NO_RESULTS_DESCRIPTION": "Δεν υπάρχουν λίστες αναπαραγωγής που να αντιστοιχούν στην αναζήτησή σας. Δοκιμάστε να προσαρμόσετε τους όρους αναζήτησης ή να καταργήσετε το φίλτρο για να δείτε όλες τις λίστες αναπαραγωγής.",
"ADDED_VIA_URL": "Προστέθηκε από ανέβασμα διεύθυνσης URL. URL:",
"ADDED_VIA_FILE": "Προστέθηκε από ανέβασμα αρχείου",
"XTREAM_PLAYLIST": "Xtream playlist",
"STALKER_PORTAL": "Stalker portal",
"CHANNELS": "Κανάλια",
"ADDED": "Προστέθηκε",
"SHOW_DETAILS": "Λεπτομέρειες λίστας αναπαραγωγής",
"REMOVE": "Διαγραφή λίστας αναπαραγωγής",
"SEARCH_PLAYLISTS": "Αναζήτηση των λιστών αναπαραγωγής με βάση τον τίτλο",
"INFO_DIALOG": {
"PLAYLIST_DETAILS": "Λεπτομέρειες λίστας αναπαραγωγής",
"TITLE": "Title",
"FROM_URL": "Προστέθηκε από διεύθυνση URL",
"IMPORT_DATE": "Προσθήκη ημερομηνίας",
"CHANNELS": "Αριθμός καναλιών",
"CLOSE": "Κλείσιμο",
"SAVE": "Αποθήκευση",
"USER_AGENT": "User agent",
"ORIGINAL_FILENAME": "Αρχικό όνομα αρχείου",
"FILE_PATH": "Διαδρομή αρχείου",
"UPDATE_FAILED": "Σφάλμα αναβάθμισης της τελευταίας λίστας αναπαραγωγής",
"AUTO_UPDATE": "Αυτόματη αναβάθμιση",
"AUTO_UPDATE_DESCRIPTION": "Εάν η λειτουργία αυτόματης ανανέωσης είναι ενεργοποιημένη, η λίστα αναπαραγωγής θα ενημερώνεται αυτόματα κάθε φορά που ξεκινά η εφαρμογή.",
"CUSTOM_USER_AGENT": "Ορισμένοι πάροχοι IPTV χρειάζονται έναν συγκεκριμένο user-agent για να αναπαράγουν τη λίστα αναπαραγωγής τους.",
"EXPORT_PLAYLIST": "Εξαγωγή λίστας αναπαραγωγής σε m3u",
"SERVER_URL": "Διεύθηνση URL του σέρβερ",
"USERNAME": "Όνομα χρήστη",
"PASSWORD": "Κωδικός πρόσβασης",
"MAC_ADDRESS": "Mac Address",
"PLAYLIST_EXPORT_SUCCESS": "Η εξαγωγή της λίστας αναπαραγωγής ολοκληρώθηκε με επιτυχία.",
"PLAYLIST_EXPORT_ERROR": "Σφάλμα: Η εξαγωγή της λίστας αναπαραγωγής απέτυχε.",
"COPY_URL": "Αντιγραφή διεύθηνσης URL στο πρόχειρο",
"URL_COPIED": "Η διεύθυνση URL αντιγράφηκε στο πρόχειρο"
},
"REMOVE_DIALOG": {
"TITLE": "Διαγραφή λίστας αναπαραγωγής",
"MESSAGE": "Είστε βέβαιοι ότι θέλετε να διαγράψετε οριστικά αυτήν τη λίστα αναπαραγωγής;",
"SUCCESS": "Η λίστα αναπαραγωγής αφαιρέθηκε με επιτυχία."
},
"UPDATED": "Ενημερώθηκε",
"REFRESH": "Ανανέωση λίστας αναπαραγωγής",
"REFRESH_XTREAM": "Ανανέωση Xtream λίστας από το τηλεκοντρόλ",
"REFRESH_XTREAM_DIALOG": {
"TITLE": "Ανανέωση Xtream λίστας",
"MESSAGE": "Αυτό θα διαγράψει τις τοπικά αποθηκευμένες κατηγορίες και ροές και θα εισαγάγει ξανά τα πάντα από τον απομακρυσμένο διακομιστή. Τα αγαπημένα σας και τα πρόσφατα προβληθέντα στοιχεία θα διατηρηθούν. Είστε βέβαιοι ότι θέλετε να συνεχίσετε;",
"STARTED": "Η ανανέωση ξεκίνησε. Πλοήγηση στη λίστα αναπαραγωγής...",
"ERROR": "Η ανανέωση της λίστας αναπαραγωγής απέτυχε. Δοκιμάστε ξανά."
},
"GLOBAL_FAVORITES": "Βασικά Αγαπημένα",
"GLOBAL_FAVORITES_DESCRIPTION": "Αυτόματα δημιουργημένη λίστα αναπαραγωγής με συλλογή αγαπημένων από όλες τις λίστες αναπαραγωγής",
"MY_PLAYLISTS": "Οι λίστες αναπαραγωγής μου",
"MY_PLAYLISTS_SUBTITLE": "όλες οι διαθέσιμες λίστες αναπαραγωγής",
"PLAYLIST_UPDATE_SUCCESS": "Επιτυχία! Η λίστα αναπαραγωγής ενημερώθηκε με επιτυχία.",
"PLAYLIST_UPDATE_ERROR": "Σφάλμα κατά την ενημέρωση των λεπτομερειών της λίστας αναπαραγωγής.",
"AUTO_REFRESH_UPDATE_SUCCESS": "Επιτυχία! Οι λίστες αναπαραγωγής ενημερώθηκαν με επιτυχία",
"AUTO_REFRESH_ENABLED": "Η αυτόματη ανανέωση είναι ενεργοποιημένη",
"FEATURE_M3U_LABEL": "Add an M3U file or URL",
"FEATURE_XTREAM_LABEL": "Connect via Xtream Codes",
"FEATURE_STALKER_LABEL": "Connect to a Stalker portal",
"VALUE_PROPS_LABEL": "What you can do",
"VALUE_PROP_LIVE": "Live TV with EPG",
"VALUE_PROP_VOD": "Movies & Series",
"VALUE_PROP_MULTISOURCE": "Multi-source library",
"VALUE_PROP_OFFLINE": "Offline downloads",
"DASHBOARD_WELCOME_TAGLINE": "Your IPTV library, in one place.",
"FEATURE_LIVE_TITLE": "Live TV",
"FEATURE_LIVE_DESC": "Stream live channels with full schedule.",
"FEATURE_VOD_TITLE": "Movies & Series",
"FEATURE_VOD_DESC": "On-demand library with covers and details.",
"FEATURE_EPG_TITLE": "EPG & Catch-up",
"FEATURE_EPG_DESC": "Program guide and time-shifted playback.",
"FEATURE_OFFLINE_TITLE": "Offline downloads",
"FEATURE_OFFLINE_DESC": "Save movies and episodes for later.",
"SOURCES_WELCOME_TITLE": "Add your first playlist",
"SOURCES_WELCOME_BODY": "Pick a source type below to get started.",
"SOURCE_M3U_NEEDS": "Local file or URL pointing to an M3U/M3U8 playlist.",
"SOURCE_M3U_ADD": "Add M3U",
"SOURCE_XTREAM_NEEDS": "Username, password and server URL from your provider.",
"SOURCE_XTREAM_ADD": "Add Xtream",
"SOURCE_STALKER_NEEDS": "Portal URL and MAC address (Ministra-compatible).",
"SOURCE_STALKER_ADD": "Add Stalker",
"CONTENT_LIVE": "Live",
"CONTENT_VOD": "Movies",
"CONTENT_SERIES": "Series",
"CONTENT_EPG": "EPG",
"DASHBOARD_WELCOME_DESCRIPTION": "Connect M3U files, Xtream Codes, or Stalker portals — then enjoy live TV, movies and series on every screen."
},
"FILE_UPLOAD": {
"DRAG_DROP": "Σύρετε και αποθέστε αρχεία εδώ",
"OR": "or",
"CHOOSE_PLAYLIST": "επιλέξτε μια λίστα αναπαραγωγής",
"REJECTED": "Το αρχείο απορρίφθηκε, η μορφή αρχείου δεν υποστηρίζεται {{filename}}."
},
"URL_UPLOAD": {
"PLAYLIST_URL": "Διεύθηνση URL λίστας αναπαραγωγής (m3u, m3u8)",
"ADD_PLAYLIST": "Προσθήκη λίστας αναπαραγωγής",
"CORS_NOTE": "Σημείωση: Για την αποφυγή προβλημάτων CORS σε αυτό το σημείο, η εφαρμογή χρησιμοποιεί μια δημόσια υπηρεσία CORS Proxy. Εάν θέλετε να ανεβάσετε μια λίστα αναπαραγωγής με ευαίσθητα δεδομένα, είναι πιο ασφαλές να την εισαγάγετε από ένα αρχείο."
},
"TEXT_IMPORT": {
"LABEL": "Προσθήκη m3u(8) λίστας αναπαραγωγής ως κείμενο",
"BUTTON_LABEL": "Εισαγωγή"
},
"XTREAM_PLAYLIST": {
"TITLE": "Τίτλος λίστας αναπαραγωγής",
"SERVER_URL": "Διεύθηνση URL σέρβερ",
"USERNAME": "Όνομα χρήστη",
"PASSWORD": "Κωδικός πρόσβασης",
"ADD": "Προσθήκη",
"TEST_CREDENTIALS": "Δοκιμή διαπιστευτήριων",
"URL_VALIDATION_ERROR": "Θα πρέπει να είναι μια έγκυρη διεύθυνση URL με πρωτόκολλο (π.χ. http://example.com ή https://example.com:4324)"
},
"STALKER_PORTAL": {
"TITLE": "Τίτλος",
"MAC_ADDRESS": "Mac Address",
"SERIAL_NUMBER": "Σειριακός αριθμός (Προαιρετικό)",
"SERIAL_NUMBER_HINT": "Χρησιμοποιήστε εάν είστε ήδη εγγεγραμμένος στον πάροχο",
"DEVICE_ID_1": "Αναγνωριστικό συσκευής 1 (Προαιρετικό)",
"DEVICE_ID_2": "Αναγνωριστικό συσκευής 2 (Προαιρετικό)",
"DEVICE_ID_HINT": "64 δεκαεξαδικοί χαρακτήρες - χρησιμοποιήστε εάν ο πάροχος απαιτεί συγκεκριμένο αναγνωριστικό συσκευής",
"SIGNATURE_1": "Υπογραφή 1 (Προαιρετικό)",
"SIGNATURE_2": "Υπογραφή 2 (Προαιρετικό)",
"SIGNATURE_HINT": "64 δεκαεξαδικοί χαρακτήρες - χρησιμοποιήστε εάν ο πάροχος απαιτεί υπογραφές επαλήθευσης συσκευής",
"SERVER_URL": "Διεύθηνση URL σέρβερ",
"URL_VALIDATION_ERROR": "Θα πρέπει να είναι μια έγκυρη διεύθυνση URL με πρωτόκολλο (π.χ. http://example.com/c ή https://example.com/stalker_portal/c)",
"ADD": "Προσθήκη",
"VALIDATING": "Επικύρωση πύλης..."
},
"FILTER_BY_NAME": "Φιλτράρισμα κατά όνομα",
"FILTER_BY_TYPE": "Τύποι λιστών αναπαραγωγής",
"FILTER_AND_SORT": "Φιλτράρισμα & Ταξινόμηση",
"SORT_PLAYLISTS": "Ταξινόμηση λιστών αναπαραγωγής",
"SORT_BY": "Ταξινόμηση κατά",
"SORT_OPTIONS": {
"NAME_ASC": "Όνομα (A-Z)",
"NAME_DESC": "Όνομα (Z-A)",
"NEWEST": "Ημερομηνία προσθήκης (Πρώτα τα νεότερα)",
"OLDEST": "Ημερομηνία προσθήκης (Πρώτα το παλαιότερο)"
},
"PLAYLIST_TYPES": {
"M3U": "M3U (τοπικό, διεύθυνση url, κείμενο)",
"XTREAM": "Xtream",
"STALKER": "Stalker"
},
"IMPORTED_AS_TEXT": "Εισήχθη ως κείμενο",
"PARSING_ERROR": "Σφάλμα: Η ανάλυση απέτυχε, δεν είναι έγκυρη λίστα αναπαραγωγής:"
},
"SETTINGS": {
"TITLE": "Ρυθμίσεις",
"SUBTITLE": "Αλλαγή της διαμόρφωσης της εφαρμογής",
"DESCRIPTION": "Παρακαλώ προσαρμόστε τις επιλογές από την παρακάτω λίστα και επιβεβαιώστε με το κουμπί αποθήκευσης αλλαγών",
"EPG_URL_LABEL": "EPG Url (*.xml ή *.xml.gz)",
"EPG_URL_PLACEHOLDER": "Εξαγωγή μιας διεύθυνσης URL",
"REFRESH_EPG": "Ανανέωση EPG",
"REFRESH_ALL_EPG": "Ανανέωση όλων",
"REMOVE_EPG_SOURCE": "Αφαίρεση πηγής EPG",
"EPG_STATUS_FRESH": "Ενημερωμένο",
"EPG_STATUS_STALE": "Χρειάζεται ανανέωση",
"EPG_STATUS_ERROR": "Αποτυχία",
"VIDEO_PLAYER_LABEL": "Προγράμμα αναπαραγωγής βίντεο",
"VIDEO_PLAYER_PLACEHOLDER": "Επιλέξτε μια επιλογή",
"VERSION": "Έκδοση",
"SAVE_CHANGES": "Αποθήκευση αλλαγών",
"BACK_TO_HOME": "Πίσω",
"NEW_VERSION_AVAILABLE": "Υπάρχει διαθέσιμη μια νέα έκδοση",
"LATEST_VERSION": "Χρησιμοποιείτε την πιο πρόσφατη έκδοση",
"STREAM_FORMAT": "Μορφή Stream",
"LANGUAGE": "Γλώσσα",
"SETTINGS_SAVED": "Επιτυχία! Η διαμόρφωση αποθηκεύτηκε.",
"THEME": "Οπτικό θέμα",
"SHOW_CAPTIONS": "Εμφάνιση υπότιτλων",
"ADD_EPG_SOURCE": "Προσθήκη πηγής EPG",
"CLEAR_EPG_DATA": "Διαγραφή δεδομένων EPG",
"CLEAR_EPG_DIALOG": {
"TITLE": "Διαγραφή δεδομένων EPG",
"MESSAGE": "Είστε βέβαιοι ότι θέλετε να καταργήσετε όλα τα δεδομένα EPG (Ηλεκτρονικός Οδηγός Προγράμματος) από τη βάση δεδομένων; Αυτή η ενέργεια θα διαγράψει όλους τους αποθηκευμένους προγραμματισμούς εγγραφής."
},
"EPG_DATA_CLEARED": "Τα δεδομένα EPG έχουν διαγραφεί",
"EPG_DATA_CLEAR_FAILED": "Αποτυχία διαγραφής δεδομένων EPG. Παρακαλώ δοκιμάστε ξανά.",
"CLEARING_EPG_DATA": "Διαγραφή…",
"EPG_URL_ERROR": "Η τιμή δεν είναι έγκυρη διεύθυνση URL",
"VIDEO_PLAYER_DESCRIPTION": "Επιλογή προεπιλεγμένου προγράμματος αναπαραγωγής βίντεο",
"STREAM_FORMAT_DESCRIPTION": "Επιλογή προεπιλεγμένης μορφής ροής (xtream)",
"LANGUAGE_DESCRIPTION": "Επιλέξτε τη γλώσσα της εφαρμογής",
"THEME_DESCRIPTION": "Επιλέξτε οπτικό θέμα της εφαρμογής",
"SHOW_CAPTIONS_DESCRIPTION": "Εμφάνιση ή απόκρυψη υποτίτλων από προεπιλογή",
"VERSION_DESCRIPTION": "Τρέχουσα έκδοση της εφαρμογής",
"EPG_NOTE": "Προς το παρόν, το EPG είναι διαθέσιμο μόνο στην ηλεκτρονική έκδοση του IPTVnator.",
"EPG_NOTE_URL_TEXT": "Ελέγξτε το εδώ",
"IMPORT_EXPORT_DATA": "Εισαγωγή/εξαγωγή λιστών αναπαραγωγής",
"IMPORT_EXPORT_DATA_DESCRIPTION": "Εξαγωγή ή εισαγωγή λιστών αναπαραγωγής στη μορφή JSON που χρησιμοποιείται στην εφαρμογή.",
"IMPORT_DATA": "Εισαγωγή",
"EXPORT_DATA": "Εξαγωγή",
"REMOVE_ALL": "Delete all playlists and playlist data",
"REMOVE_ALL_BUTTON": "Delete all",
"REMOVE_ALL_DESCRIPTION": "Delete every M3U, Xtream, and Stalker playlist stored in the app.",
"REMOVE_DIALOG": {
"TITLE": "Delete all playlists?",
"MESSAGE": "Delete all {{count}} playlists from the app. This also removes stored playlist data on this device.",
"SUMMARY_TITLE": "Playlist sources",
"CONSEQUENCES_TITLE": "This also removes",
"CONSEQUENCE_FAVORITES": "Favorites saved for these playlists",
"CONSEQUENCE_RECENTLY_VIEWED": "Recently viewed history",
"CONSEQUENCE_PLAYBACK": "Saved playback positions",
"CONSEQUENCE_DOWNLOADS": "Download history entries linked to those playlists",
"CONSEQUENCE_XTREAM_CACHE": "Imported Xtream categories and locally cached content",
"BACKUP_HINT": "Use Export first if you want a restorable backup before deleting.",
"CONFIRM": "Delete everything"
},
"IMPORT_ERROR": "Σφάλμα εισαγωγής, δοκιμάστε με άλλο αρχείο.",
"PLAYLISTS_REMOVED": "All playlists and playlist data were removed.",
"MPV_PLAYER_PATH_LABEL": "διαδρομή mpv",
"MPV_PLAYER_PATH_DESCRIPTION": "Ορίστε τη διαδρομή προς το mpv player στο σύστημά σας. Θα χρησιμοποιήσει την παρεχόμενη διαδρομή προς ένα δυαδικό αρχείο mpv αντί για αυτήν που βρίσκεται στο $PATH.",
"MPV_PLAYER_PATH": "διαδρομή mpv προγράμματος αναπαραγωγής",
"MPV_REUSE_INSTANCE_LABEL": "Επαναχρησιμοποίηση της παρουσίας MPV",
"MPV_REUSE_INSTANCE_DESCRIPTION": "Όταν είναι ενεργοποιημένη, το ίδιο παράθυρο MPV θα επαναχρησιμοποιηθεί για την αναπαραγωγή διαφορετικών ροών. Όταν είναι απενεργοποιημένη, κάθε ροή ανοίγει σε ένα νέο παράθυρο MPV.",
"VLC_PLAYER_PATH_LABEL": "διαδρομή VLC",
"VLC_PLAYER_PATH_DESCRIPTION": "Ορίστε τη διαδρομή προς το VLC player στο σύστημά σας. Θα χρησιμοποιήσει την παρεχόμενη διαδρομή προς ένα δυαδικό αρχείο VLC αντί για την προεπιλεγμένη διαδρομή για το σύστημά μας.",
"VLC_PLAYER_PATH": "διαδρομή VLC player",
"REMOTE_CONTROL": "Τηλεχειριστήριο",
"REMOTE_CONTROL_DESCRIPTION": "Ενεργοποιήστε τον τηλεχειρισμό της εφαρμογής.",
"REMOTE_CONTROL_PORT": "Θύρα τηλεχειριστηρίου",
"REMOTE_CONTROL_PORT_DESCRIPTION": "Θύρα που χρησιμοποιείται για τον τηλεχειρισμό της εφαρμογής. Η θύρα 8765 χρησιμοποιείται από προεπιλογή.",
"REMOTE_CONTROL_URL": "διεύθυνση URL για τηλεχειρισμό",
"REMOTE_CONTROL_URL_DESCRIPTION": "Αποκτήστε πρόσβαση στο τηλεχειριστήριο από άλλη συσκευή στο ίδιο δίκτυο.",
"SHOW_QR_CODE": "Εμφάνιση QR code",
"PORT_REQUIRED": "Απαιτείται θύρα",
"PORT_MIN": "Η θύρα πρέπει να είναι τουλάχιστον 1",
"PORT_MAX": "Η θύρα πρέπει να είναι το πολύ 65535",
"PORT_PATTERN": "Επιτρέπονται μόνο αριθμητικά ψηφία",
"REMOVE_ALL_IN_PROGRESS": "Deleting playlist data…",
"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.",
"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": "Σκούρο θέμα",
"LIGHT_THEME": "Ανοιχτόχρωμο θέμα",
"SYSTEM_THEME": "Θέμα συστήματος"
},
"CHANNELS": {
"SEARCH_CHANNEL": "Αναζήτηση καναλιού",
"UPLOAD_OR_SELECT_OTHER_PLAYLIST": "Μεταφορτώστε ή επιλέξτε άλλη λίστα αναπαραγωγής",
"ALL_CHANNELS": "Όλα τα κανάλια",
"GROUPS": "Ομάδες",
"UNGROUPED": "Μη ομαδοποιημένα",
"UNNAMED_CHANNEL": "Κανάλι χωρίς όνομα",
"FAVORITES": "Αγαπημένα",
"NO_FAVORITES": "Δεν υπάρχουν ακόμα αγαπημένα",
"USE_STAR_TO_FAVORITE": "Χρησιμοποιήστε το εικονίδιο με το «αστέρι» για να προσθέσετε κανάλια στα αγαπημένα σας.",
"REMOVE_FAVORITE": "Αφαίρεση από τα αγαπημένα",
"FAVORITES_UPDATED": "Τα αγαπημένα ενημερώθηκαν!",
"SORT_BY": "Ταξινόμηση κατά",
"SORT_BY_DATE": "Ταξινόμηση κατά Ημερομηνία Προσθήκης (Πρώτα τα Νεότερα)",
"SORT_BY_RATING": "Ταξινόμηση κατά Βαθμολογία",
"SORT_BY_NAME": "Ταξινόμηση κατά Όνομα (A-Z)"
},
"TOP_MENU": {
"OPEN_CHANNELS_LIST": "Άνοιγμα λίστας καναλιών",
"TOGGLE_FAVORITE_FLAG": "Εναλλαγή σημαίας αγαπημένων",
"OPEN_EPG_LIST": "Άνοιγμα λίστας EPG",
"OPEN_MULTI_EPG": "Άνοιγμα προβολής Πολλαπλού EPG",
"SHOW_INFO": "Εμφάνιση πληροφοριών προγράμματος (Πατήστε το I)"
},
"EPG": {
"TITLE": "Ηλεκτρονικός Οδηγός Προγράμματος",
"NEXT_DAY": "Επόμενη μέρα",
"PREVIOUS_DAY": "Προηγούμενη ημέρα",
"LIVE_NOW": "Ζωντανά τώρα",
"LIVE_STREAM": "Ζωντανή ροή",
"TIMESHIFT_AVAILABLE": "Η χρονική μετατόπιση είναι διαθέσιμη, κάντε κλικ για αναπαραγωγή.",
"EPG_NOT_AVAILABLE_DATE": "Ωχ, το EPG δεν είναι διαθέσιμο για την επιλεγμένη ημερομηνία",
"EPG_NOT_AVAILABLE_CHANNEL_TITLE": "Ωχ, το EPG δεν είναι διαθέσιμο για αυτό το κανάλι.",
"EPG_NOT_AVAILABLE_CHANNEL_DESCRIPTION": "Προσθέστε/αλλάξτε τη διεύθυνση URL της λίστας EPG στις ρυθμίσεις της εφαρμογής.",
"FETCH_EPG": "Ανάκτηση δεδομένων EPG...",
"ERROR": "Ωχ, δεν ήταν δυνατή η φόρτωση του EPG.",
"DOWNLOAD_SUCCESS": "Το EPG λήφθηκε με επιτυχία.",
"NO_PROGRAM_INFO": "Δεν υπάρχουν διαθέσιμες πληροφορίες προγράμματος",
"PROGRAM_DIALOG": {
"PROGRAM_DETAILS": "Λεπτομέρειες για το τηλεοπτικό πρόγραμμα",
"TITLE": "Τίτλος",
"CATEGORY": "Κατηγορία",
"PARENTAL_RATING_SYSTEM": "Βαθμολογία",
"DESCRIPTION": "Περιγραφή",
"LANGUAGE": "Γλώσσα",
"SHOW_PROGRAM_DETAILS": "Εμφάνιση λεπτομερειών σχετικά με αυτό το πρόγραμμα",
"EPISODE": "Επεισόδιο",
"DURATION": "Διάρκεια"
},
"FETCH_SUCCESS": "Το EPG ανακτήθηκε με επιτυχία",
"IMPORT_PROGRESS": "Εισαγωγή Ηλεκτρονικού Οδηγού Προγράμματος (EPG)",
"CHANNELS": "κανάλια",
"PROGRAMS": "προγράμματα",
"LOADING": "Φόρτωση",
"QUEUED": "Σε ουρά",
"TOTAL_CHANNELS": "Σύνολο καναλιών",
"TOTAL_PROGRAMS": "Σύνολο προγραμμάτων",
"UP_TO_DATE": "Το EPG είναι ενημερωμένο, δεν απαιτείται συγχρονισμός",
"RETRY": "Επανάληψη"
},
"LANGUAGES": {
"ARABIC": "العربية",
"MOROCCAN_ARABIC": "العربية (اللهجة المغربية)",
"ENGLISH": "English",
"KOREAN": "한국어",
"RUSSIAN": "Русский",
"GERMAN": "Deutsch",
"SPANISH": "Español",
"CHINESE": "简体中文",
"TRADITIONAL_CHINESE": "繁體中文",
"FRENCH": "Français",
"ITALIAN": "Italiano",
"TURKISH": "Türkçe",
"JAPANESE": "日本語",
"DUTCH": "Nederlands",
"BELARUSIAN": "Беларуская",
"POLISH": "Polski",
"PORTUGUESE": "Português",
"GREEK": "Ελληνικά"
},
"YES": "Ναι",
"NO": "Όχι",
"MENU": {
"OPEN": "Άνοιγμα μενού",
"SUPPORT_ARIA": "Υποστήριξη του IPTVnator στο GitHub",
"SETTINGS": "Ρυθμίσεις",
"SETTINGS_ARIA": "Άνοιγμα ρυθμίσεων",
"BUG_REPORT": "Αναφορά σφάλματος",
"WHAT_IS_NEW": "Τι νέο υπάρχει",
"ABOUT": "Πληροφορίες",
"ABOUT_ARIA": "Σχετικά με την εφαρμογή",
"SUPPORT_PROJECT": "Υποστήριξη του έργου"
},
"ABOUT": {
"TITLE": "Σχετικά με το IPTVnator",
"DESCRIPTION": "Εφαρμογή αναπαραγωγής IPTV από πολλαπλές πλατφόρμες με πολλαπλές λειτουργίες, όπως υποστήριξη λιστών αναπαραγωγής m3u και m3u8, αγαπημένα, οδηγό τηλεόρασης, αρχείο/catchup τηλεόρασης και πολλά άλλα.",
"VERSION": "Έκδοση",
"GITHUB_TOOLTIP": "ITPVnator repository στο GitHub",
"BUY_ME_A_COFFEE_TOOLTIP": "Κέρασέ μου έναν καφέ",
"TWITTER_TOOLTIP": "Κοινοποίηση στο Twitter"
},
"UPDATE_AVAILABLE": "Διαθέσιμη ενημέρωση",
"REFRESH": "Ανανέωση",
"XTREAM": {
"PLAY": "Αναπαραγωγή",
"OPENING_PLAYER": "Εκκίνηση προγράμματος αναπαραγωγής...",
"NAME": "Όνομα",
"RELEASE_DATE": "Ημερομηνία κυκλοφορίας",
"GENRE": "Είδος",
"COUNTRY": "Χώρα",
"ACTORS": "Ηθοποιοί",
"DIRECTOR": "Σκηνοθέτης",
"DURATION": "Διάρκεια",
"CAST": "Πρόσωπα",
"EPISODE_RUN_TIME": "Διάρκεια επεισοδίου",
"RATING": "Βαθμολογία",
"IMDB_RATING": " Βαθμολογία IMDB",
"KINOPOISK_RATING": "Βαθμολογία Kinopoisk",
"DESCRIPTION": "Περιγραφή",
"YEAR": "Έτος",
"AGE": "Ηλικία",
"YOUTUBE_TRAILER": "YouTube Trailer",
"EPISODE": "Επεισόδιο",
"ACCOUNT_INFO": {
"TITLE": "Πληροφορίες Λογαριασμού",
"USER_INFO": "Πληροφορίες χρήστη",
"STATUS": "Κατάσταση",
"USERNAME": "Όνομα χρήστη",
"ACTIVE_CONNECTIONS": "Ενεργές συνδέσεις",
"CREATED": "Δημιουργήθηκε",
"EXPIRES": "Λήγει",
"TRIAL_ACCOUNT": "Δοκιμαστικός Λογαριασμός",
"YES": "Ναι",
"NO": "Όχι",
"ALLOWED_FORMATS": "Επιτρεπόμενες μορφές",
"SERVER_INFO": "Πληροφορίες διακομιστή",
"LIVE_TV": "Ζωντανή TV",
"MOVIES": "Ταινίες",
"TV_SERIES": "Σειρές",
"URL": "Διεύθυνση URL",
"PROTOCOL": "Πρωτόκολλο",
"TIMEZONE": "Ζώνη ώρας",
"SERVER_TIME": "Ώρα διακομιστή",
"PORTS": "Θύρες",
"HTTP_PORT": "HTTP",
"HTTPS_PORT": "HTTPS",
"RTMP_PORT": "RTMP"
},
"CATEGORY_MANAGEMENT": {
"TITLE": "Διαχείριση κατηγοριών",
"LOADING": "Φόρτωση κατηγοριών...",
"SELECTED": "Επιλεγμένα",
"SELECT_ALL": "Επιλογή όλων",
"DESELECT_ALL": "Αποεπιλογή όλων",
"SEARCH_PLACEHOLDER": "Αναζήτηση κατηγοριών...",
"NO_RESULTS": "Δεν βρέθηκαν αντίστοιχες κατηγορίες",
"NO_CATEGORIES": "Δεν υπάρχουν διαθέσιμες κατηγορίες",
"SAVE": "Αποθήκευση"
}
},
"PORTALS": {
"ALL_CATEGORIES": "Όλες οι κατηγορίες",
"MY_FAVORITES": "Τα αγαπημένα μου",
"ADD_TO_FAVORITES": "Προσθήκη στα αγαπημένα",
"REMOVE_FROM_FAVORITES": "Αφαίρεση από τα αγαπημένα",
"REMOVED_FROM_FAVORITES": "Αφαιρέθηκε από τα αγαπημένα",
"ADDED_TO_FAVORITES": "Προστέθηκε στα αγαπημένα",
"SIDEBAR": {
"MAIN": "Κύριο",
"MOVIES": "Ταινίες",
"LIVE_TV": "Ζωντανή TV",
"SERIES": "Σειρές",
"LIBRARY": "Βιβλιοθήκη",
"SEARCH": "Αναζήτηση",
"RECENT": "Πρόσφατα",
"RECENTLY_ADDED": "Πρόσφατα προστέθηκε",
"FAVORITES": "Αγαπημένα",
"HOME": "Αρχικό",
"PLAYLIST_INFO": "Πληροφορίες λίστας αναπαραγωγής",
"ACCOUNT_INFO": "Πληροφορίες λογαριασμού"
},
"ERROR_VIEW": {
"ACCOUNT_EXPIRED": {
"TITLE": "Ο λογαριασμός έληξε",
"DESCRIPTION": "Αυτός ο λογαριασμός έχει λήξει. Ελέγξτε τα διαπιστευτήρια στις ρυθμίσεις της λίστας αναπαραγωγής ή καταργήστε τον."
},
"UNAUTHORIZED": {
"TITLE": "Ανεξουσιοδότητος",
"DESCRIPTION": "Ελέγξτε τα διαπιστευτήρια στις ρυθμίσεις της λίστας αναπαραγωγής ή καταργήστε τα."
},
"NOT_FOUND": {
"TITLE": "Ο διακομιστής δεν βρέθηκε",
"DESCRIPTION": "Παρακαλώ ελέγξτε τα διαπιστευτήρια και τη διεύθυνση URL της πύλης στις ρυθμίσεις της λίστας αναπαραγωγής ή καταργήστε την."
},
"EMPTY_CATEGORY": {
"TITLE": "Κενή κατηγορία",
"DESCRIPTION": "Αυτή η κατηγορία δεν έχει περιεχόμενο, επιλέξτε άλλη κατηγορία ή αλλάξτε τον τύπο περιεχομένου"
},
"UNKNOWN_ERROR": {
"TITLE": "Κάτι πήγε στραβά",
"DESCRIPTION": "Άγνωστο σφάλμα, δοκιμάστε ξανά αργότερα"
},
"NO_CATEGORY_SELECTED": {
"TITLE": "Δεν έχει επιλεγεί κατηγορία",
"DESCRIPTION": "Επιλέξτε μια κατηγορία για να δείτε το περιεχόμενο"
},
"PLAYLIST_SETTINGS": "Ρυθμίσεις λίστας αναπαραγωγής",
"HOME": "Αρχικό",
"DELETE": "Διαγραφή"
},
"EMPTY_LIST_VIEW": {
"TITLE": "Δεν βρέθηκαν αποτελέσματα",
"NO_SEARCH_RESULTS": "Δεν βρέθηκε τίποτα, δοκιμάστε να αλλάξετε το αίτημα αναζήτησής σας"
},
"SEARCH_VIEW": {
"INITIAL_TITLE": "Αναζήτηση περιεχομένου",
"INITIAL_DESCRIPTION": "Εισαγάγετε τουλάχιστον 3 χαρακτήρες για αναζήτηση σε ζωντανές τηλεοπτικές μεταδόσεις, ταινίες και σειρές.",
"RESULTS_FOUND": "Βρέθηκαν {{count}} αποτελέσματα",
"NO_RESULTS_FOR": "Δεν βρέθηκαν αποτελέσματα για \"{{term}}\""
},
"STREAM_URL_COPIED": "Η διεύθυνση URL ροής αντιγράφηκε στο πρόχειρο",
"COPY_STREAM_URL": "Αντιγραφή διεύθηνσης URL ροής",
"SELECT_CATEGORY": "Επιλέξτε μια κατηγορία",
"PAGE": "Σελίδα",
"CONTENT_NOT_AVAILABLE": "Αυτό το περιεχόμενο δεν είναι διαθέσιμο σε αυτόν τον διακομιστή",
"PLAYBACK_ERROR": "Αποτυχία λήψης διεύθυνσης URL αναπαραγωγής",
"LOADING_SEASONS": "Φόρτωση σεζόν...",
"NO_EPISODES": "Δεν υπάρχουν διαθέσιμα επεισόδια"
},
"INFORMATION": "Πληροφορίες",
"REMOTE_CONTROL": {
"TITLE": "Τηλεχειριστήριο",
"SUBTITLE": "Ελέγξτε το πρόγραμμα αναπαραγωγής IPTV σας από απόσταση",
"UP_CHANNEL": "Πάνω κανάλι",
"DOWN_CHANNEL": "Κάτω κανάλι",
"HEADER": "IPTVNator Τηλεχειριστήριο",
"FOOTER": "IPTVNator Τηλεχειριστήριο"
},
"WORKSPACE": {
"SHELL": {
"GO_TO_DASHBOARD": "Back to dashboard",
"GO_TO_SOURCES": "Go to Sources",
"DROP_OVERLAY_TITLE": "Drop to add playlist",
"DROP_OVERLAY_BODY": "Release an .m3u or .m3u8 file anywhere in the workspace to import it.",
"DROP_OVERLAY_REJECTED_BODY": "Please drop an .m3u or .m3u8 file. Press Esc to dismiss.",
"DROP_OVERLAY_REJECTED_UNSUPPORTED": "Unsupported file type",
"DROP_OVERLAY_REJECTED_EMPTY": "That file is empty",
"DROP_OVERLAY_REJECTED_READ_ERROR": "Could not read that file",
"DROP_IMPORT_SUCCESS": "Importing \"{{title}}\"…",
"COMMANDS": {
"ADD_PLAYLIST_M3U_LABEL": "Add M3U playlist",
"ADD_PLAYLIST_M3U_DESCRIPTION": "Open add dialog on the M3U file or URL tab",
"ADD_PLAYLIST_XTREAM_LABEL": "Add Xtream Codes playlist",
"ADD_PLAYLIST_XTREAM_DESCRIPTION": "Open add dialog on the Xtream Codes tab",
"ADD_PLAYLIST_STALKER_LABEL": "Add Stalker portal",
"ADD_PLAYLIST_STALKER_DESCRIPTION": "Open add dialog on the Stalker Portal tab"
},
"EXTERNAL_PLAYBACK_CLOSE": "Close player"
},
"GLOBAL_FAVORITES": {
"NO_PLAYLISTS_TITLE": "No favorites to show",
"NO_PLAYLISTS_BODY": "Add a playlist to start collecting favorites from live channels, movies, and series.",
"NO_ITEMS_TITLE": "No favorites yet",
"NO_ITEMS_BODY": "Tap the star icon on any channel, movie, or series to save it here."
},
"GLOBAL_RECENT": {
"NO_PLAYLISTS_TITLE": "Nothing watched yet",
"NO_PLAYLISTS_BODY": "Add a playlist and your watching history will appear here.",
"NO_ITEMS_TITLE": "Nothing watched yet",
"NO_ITEMS_BODY": "Start watching anything from your library and it will show up here."
}
},
"DOWNLOADS": {
"NO_PLAYLISTS_TITLE": "Add a playlist to start downloading",
"NO_PLAYLISTS_BODY": "Once you add a playlist, you can save movies and episodes here for offline playback.",
"NO_ITEMS_BODY": "Use the download button on any movie or episode to save it for offline playback.",
"NO_FILTER_MATCH": "No downloads match the current filter",
"NO_FILTER_MATCH_HINT": "Try a different search term"
}
}
+955
View File
@@ -0,0 +1,955 @@
{
"CANCEL": "Cancel",
"CLEAR": "Clear",
"CLOSE": "Close",
"SHOW_MORE": "More",
"SHOW_LESS": "Less",
"PLAYLISTS": "Playlists",
"HOME": {
"TITLE": "IPTVnator",
"SUBTITLE": "Please select a playlist from the list or add a new playlist",
"TABS": {
"RECENTLY_ADDED": "Recently added playlists",
"FILE_UPLOAD": "Add via file upload",
"URL_UPLOAD": "Add via URL",
"TEXT_IMPORT": "Import from text",
"XTREME_IMPORT": "Add Xtreme Code",
"STALKER_PORTAL_IMPORT": "Add Stalker Portal"
},
"PLAYLISTS": {
"NO_PLAYLISTS": "No playlists were added",
"ADD_FIRST": "Please add your first playlist",
"WELCOME_TITLE": "Welcome to IPTVnator",
"WELCOME_DESCRIPTION": "Start your streaming journey by adding your first playlist. Connect to your favorite IPTV service and enjoy live TV, movies, and series.",
"ADD_YOUR_FIRST": "Add Your First Playlist",
"FEATURE_M3U": "M3U/M3U8 Files",
"FEATURE_XTREAM": "Xtream Codes",
"FEATURE_STALKER": "Stalker Portal",
"FEATURE_M3U_LABEL": "Add an M3U file or URL",
"FEATURE_XTREAM_LABEL": "Connect via Xtream Codes",
"FEATURE_STALKER_LABEL": "Connect to a Stalker portal",
"VALUE_PROPS_LABEL": "What you can do",
"VALUE_PROP_LIVE": "Live TV with EPG",
"VALUE_PROP_VOD": "Movies & Series",
"VALUE_PROP_MULTISOURCE": "Multi-source library",
"VALUE_PROP_OFFLINE": "Offline downloads",
"DASHBOARD_WELCOME_TAGLINE": "Your IPTV library, in one place.",
"DASHBOARD_WELCOME_DESCRIPTION": "Connect M3U files, Xtream Codes, or Stalker portals — then enjoy live TV, movies and series on every screen.",
"FEATURE_LIVE_TITLE": "Live TV",
"FEATURE_LIVE_DESC": "Stream live channels with full schedule.",
"FEATURE_VOD_TITLE": "Movies & Series",
"FEATURE_VOD_DESC": "On-demand library with covers and details.",
"FEATURE_EPG_TITLE": "EPG & Catch-up",
"FEATURE_EPG_DESC": "Program guide and time-shifted playback.",
"FEATURE_OFFLINE_TITLE": "Offline downloads",
"FEATURE_OFFLINE_DESC": "Save movies and episodes for later.",
"SOURCES_WELCOME_TITLE": "Add your first playlist",
"SOURCES_WELCOME_BODY": "Pick a source type below to get started.",
"SOURCE_M3U_NEEDS": "Local file or URL pointing to an M3U/M3U8 playlist.",
"SOURCE_M3U_ADD": "Add M3U",
"SOURCE_XTREAM_NEEDS": "Username, password and server URL from your provider.",
"SOURCE_XTREAM_ADD": "Add Xtream",
"SOURCE_STALKER_NEEDS": "Portal URL and MAC address (Ministra-compatible).",
"SOURCE_STALKER_ADD": "Add Stalker",
"CONTENT_LIVE": "Live",
"CONTENT_VOD": "Movies",
"CONTENT_SERIES": "Series",
"CONTENT_EPG": "EPG",
"NO_RESULTS_TITLE": "No playlists found",
"NO_RESULTS_DESCRIPTION": "No playlists match your search. Try adjusting your search terms or clear the filter to see all playlists.",
"ADDED_VIA_URL": "Added via URL upload. URL:",
"ADDED_VIA_FILE": "Added via file upload",
"XTREAM_PLAYLIST": "Xtream playlist",
"STALKER_PORTAL": "Stalker portal",
"CHANNELS": "Channels",
"ADDED": "Added",
"SHOW_DETAILS": "Show playlist details",
"REMOVE": "Remove playlist",
"SEARCH_PLAYLISTS": "Search playlists by title",
"INFO_DIALOG": {
"PLAYLIST_DETAILS": "Playlist details",
"TITLE": "Title",
"FROM_URL": "Added from the URL",
"IMPORT_DATE": "Import date",
"CHANNELS": "Number of channels",
"CLOSE": "Close",
"SAVE": "Save",
"USER_AGENT": "User agent",
"ORIGINAL_FILENAME": "Original filename",
"FILE_PATH": "File path",
"UPDATE_FAILED": "Last playlist update failed",
"AUTO_UPDATE": "Auto-update",
"AUTO_UPDATE_DESCRIPTION": "If the auto-refresh function is activated, the playlist will be updated automatically each time the app is started.",
"CUSTOM_USER_AGENT": "Some IPTV providers need a specific user-agent in order to play their playlist.",
"EXPORT_PLAYLIST": "Export playlist as m3u",
"SERVER_URL": "Server URL",
"USERNAME": "Username",
"PASSWORD": "Password",
"MAC_ADDRESS": "Mac Address",
"PLAYLIST_EXPORT_SUCCESS": "Playlist was exported successfully.",
"PLAYLIST_EXPORT_ERROR": "Error: Playlist export failed.",
"COPY_URL": "Copy URL to clipboard",
"URL_COPIED": "URL copied to clipboard"
},
"REMOVE_DIALOG": {
"TITLE": "Remove playlist",
"MESSAGE": "Are you sure you want to delete this playlist completely?",
"SUCCESS": "Playlist was removed successfully",
"IN_PROGRESS": "Removing playlist...",
"DELETING_FAVORITES": "Removing favorites...",
"DELETING_RECENT": "Removing recently viewed...",
"DELETING_PROGRESS": "Removing playback progress...",
"DELETING_DOWNLOADS": "Removing downloads...",
"DELETING_CONTENT": "Removing cached content...",
"DELETING_CATEGORIES": "Removing categories...",
"DELETING_PLAYLIST": "Removing playlist record..."
},
"UPDATED": "Updated",
"REFRESH": "Refresh playlist",
"REFRESH_XTREAM": "Refresh Xtream playlist from remote",
"REFRESH_XTREAM_DIALOG": {
"TITLE": "Refresh Xtream Playlist",
"MESSAGE": "This will delete locally cached categories and streams and re-import everything from the remote server. Your favorites and recently viewed items will be preserved. Are you sure you want to continue?",
"STARTED": "Refresh started. Navigating to playlist...",
"ERROR": "Failed to refresh playlist. Please try again.",
"IN_PROGRESS": "Refreshing playlist...",
"COLLECTING_DATA": "Collecting favorites and recently viewed...",
"DELETING_CONTENT": "Removing cached content...",
"DELETING_CATEGORIES": "Removing cached categories..."
},
"GLOBAL_FAVORITES": "Global favorites",
"GLOBAL_FAVORITES_DESCRIPTION": "Auto-generated playlist with aggregated favorites from all playlists",
"MY_PLAYLISTS": "My playlists",
"MY_PLAYLISTS_SUBTITLE": "all available playlists",
"PLAYLIST_UPDATE_SUCCESS": "Success! The playlist was successfully updated.",
"PLAYLIST_UPDATE_ERROR": "Error updating playlist details.",
"PLAYLIST_UPDATE_FILE_NOT_FOUND": "Playlist refresh failed. The local file is no longer available. Check the file path or re-import the playlist.",
"PLAYLIST_UPDATE_FILE_ACCESS_ERROR": "Playlist refresh failed. The app can no longer access the local file.",
"AUTO_REFRESH_UPDATE_SUCCESS": "Success! The playlists were successfully updated",
"AUTO_REFRESH_ENABLED": "Auto-refresh enabled"
},
"FILE_UPLOAD": {
"DRAG_DROP": "Drop an .m3u or .m3u8 file here",
"OR": "or",
"CHOOSE_PLAYLIST": "click to browse",
"BROWSE": "Browse files",
"REJECTED": "File was rejected, unsupported file format {{filename}}."
},
"URL_UPLOAD": {
"PLAYLIST_URL": "Playlist URL (m3u, m3u8)",
"ADD_PLAYLIST": "Add playlist",
"CORS_NOTE": "Note: In order to avoid CORS issues at this point the application uses a public CORS Proxy service. If you want to upload a playlist with sensitive data, it's more secure to import it from a file.",
"ERROR_FETCH_FAILED": "Failed to fetch the playlist. Please check the URL and try again.",
"ERROR_403": "Access denied (403): The server refused the request. The URL may require authentication or the playlist is restricted.",
"ERROR_404": "Playlist not found (404): The URL does not point to a valid playlist. Please check the URL.",
"ERROR_401": "Unauthorized (401): Authentication is required to access this playlist."
},
"TEXT_IMPORT": {
"LABEL": "Insert m3u(8) playlist as text",
"BUTTON_LABEL": "Import"
},
"XTREAM_PLAYLIST": {
"TITLE": "Playlist title",
"SERVER_URL": "Server URL",
"USERNAME": "Username",
"PASSWORD": "Password",
"ADD": "Add",
"TEST_CREDENTIALS": "Test credentials",
"TEST_CONNECTION": "Test connection",
"TESTING": "Testing…",
"URL_VALIDATION_ERROR": "Should be a valid url with protocol (e.g. http://example.com or https://example.com:4324)"
},
"KIRATV": {
"ADD_PLAYLIST_TITLE": "Connect KiraTV",
"FIXED_SERVER": "Server:",
"FIXED_PLAYLIST_TITLE": "Playlist:",
"WELCOME_TITLE": "Welcome to KiraTV",
"WELCOME_TAGLINE": "Your IPTV for the whole family",
"WELCOME_DESCRIPTION": "Sign in with your Kira Cloud username and password to watch live TV, movies, and series.",
"ADD_FIRST_CTA": "Sign in"
},
"STALKER_PORTAL": {
"TITLE": "Title",
"MAC_ADDRESS": "Mac Address",
"SERIAL_NUMBER": "Serial Number (Optional)",
"SERIAL_NUMBER_HINT": "Use if already registered with provider",
"DEVICE_ID_1": "Device ID 1 (Optional)",
"DEVICE_ID_2": "Device ID 2 (Optional)",
"DEVICE_ID_HINT": "64 hex characters - use if provider requires specific device ID",
"SIGNATURE_1": "Signature 1 (Optional)",
"SIGNATURE_2": "Signature 2 (Optional)",
"SIGNATURE_HINT": "64 hex characters - use if provider requires device verification signatures",
"SERVER_URL": "Server URL",
"URL_VALIDATION_ERROR": "Should be a valid url with protocol (e.g. http://example.com/c or https://example.com/stalker_portal/c)",
"ADD": "Add",
"VALIDATING": "Validating portal..."
},
"FILTER_BY_NAME": "Filter by name",
"FILTER_BY_TYPE": "Playlist Types",
"FILTER_AND_SORT": "Filter & Sort",
"SORT_PLAYLISTS": "Sort playlists",
"SORT_BY": "Sort By",
"SORT_OPTIONS": {
"NAME_ASC": "Name (A-Z)",
"NAME_DESC": "Name (Z-A)",
"NEWEST": "Date added (Newest first)",
"OLDEST": "Date added (Oldest first)",
"CUSTOM_ORDER": "Custom order (Drag & Drop)"
},
"PLAYLIST_TYPES": {
"M3U": "M3U (local, url, text)",
"XTREAM": "Xtream",
"STALKER": "Stalker"
},
"IMPORTED_AS_TEXT": "Imported as text",
"PARSING_ERROR": "Error: Parsing failed, not a valid playlist:"
},
"SETTINGS": {
"TITLE": "Settings",
"GENERAL": "General",
"GENERAL_SUBTITLE": "Change the configuration of the application",
"PLAYBACK": "Playback",
"EPG_SOURCES": "EPG sources",
"EPG_SOURCES_DESCRIPTION": "Add one or more URLs as EPG sources",
"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",
"HERO_TITLE": "Shape how IPTVnator feels",
"HERO_DESCRIPTION": "Tune playback, guides, remote access and data handling from one place without losing the current workspace style.",
"SUBTITLE": "Change the configuration of the application",
"DESCRIPTION": "Please adapt the options from the list below and confirm with the save changes button",
"EPG_URL_LABEL": "EPG Url (*.xml or *.xml.gz)",
"EPG_URL_PLACEHOLDER": "Enter an URL",
"REFRESH_EPG": "Refresh EPG",
"REFRESH_ALL_EPG": "Refresh all",
"REMOVE_EPG_SOURCE": "Remove EPG source",
"EPG_STATUS_FRESH": "Up to date",
"EPG_STATUS_STALE": "Needs refresh",
"EPG_STATUS_ERROR": "Failed",
"VIDEO_PLAYER_LABEL": "Video player",
"PLAYER_HTML5": "HTML5 video player",
"PLAYER_VIDEOJS": "Video.js player",
"PLAYER_ARTPLAYER": "ArtPlayer",
"PLAYER_EMBEDDED_MPV": "Embedded MPV (Experimental, macOS)",
"PLAYER_MPV": "MPV player",
"PLAYER_VLC": "VLC",
"VIDEO_PLAYER_PLACEHOLDER": "Select an option",
"VERSION": "Version",
"SAVE_CHANGES": "Save changes",
"BACK_TO_HOME": "Back",
"NEW_VERSION_AVAILABLE": "There is a new version available",
"LATEST_VERSION": "You are using the latest version",
"STREAM_FORMAT": "Stream Format",
"LANGUAGE": "Language",
"SETTINGS_SAVED": "Success! Configuration was saved.",
"THEME": "Visual theme",
"SHOW_CAPTIONS": "Show subtitles",
"SHOW_DASHBOARD": "Show dashboard",
"SHOW_DASHBOARD_DESCRIPTION": "Keep Dashboard available in the workspace rail. When disabled, Sources becomes the first workspace page.",
"ADD_EPG_SOURCE": "Add EPG source",
"CLEAR_EPG_DATA": "Clear EPG data",
"CLEAR_EPG_DIALOG": {
"TITLE": "Clear EPG data",
"MESSAGE": "Are you sure you want to remove all EPG (Electronic Program Guide) data from the database? This will delete all cached program schedules."
},
"EPG_DATA_CLEARED": "EPG data has been cleared",
"EPG_DATA_CLEAR_FAILED": "Failed to clear EPG data. Please try again.",
"CLEARING_EPG_DATA": "Clearing…",
"EPG_URL_ERROR": "The value is not a valid URL",
"VIDEO_PLAYER_DESCRIPTION": "Select default video player",
"STREAM_FORMAT_DESCRIPTION": "Select default stream format (xtream)",
"LANGUAGE_DESCRIPTION": "Select language of the application",
"THEME_DESCRIPTION": "Select visual theme of the application",
"STARTUP_BEHAVIOR": "Startup view",
"STARTUP_BEHAVIOR_DESCRIPTION": "Choose whether IPTVnator opens the first available workspace view or restores your last section-level view. First view means Dashboard when enabled, otherwise Sources.",
"STARTUP_BEHAVIOR_FIRST_VIEW": "First available view",
"STARTUP_BEHAVIOR_RESTORE_LAST_VIEW": "Restore last view",
"SHOW_CAPTIONS_DESCRIPTION": "Show or hide subtitles by default",
"SHOW_EXTERNAL_PLAYBACK_BAR": "Show now playing footer",
"SHOW_EXTERNAL_PLAYBACK_BAR_DESCRIPTION": "Keep the external-player status bar visible at the bottom of the workspace on desktop.",
"VERSION_DESCRIPTION": "Current version of the application",
"ABOUT_SUBTITLE": "Version, project links and ways to support IPTVnator.",
"EMBEDDED_MPV_NOTICE_TITLE": "Embedded MPV runtime",
"EMBEDDED_MPV_NOTICE_DESCRIPTION": "macOS builds can include bundled libmpv and FFmpeg libraries for the experimental Embedded MPV player. Users do not need to install the MPV app separately; external MPV and VLC remain available as fallback players.",
"COMMUNITY": "Project & community",
"COMMUNITY_DESCRIPTION": "Star the repository, read the blog or join the Telegram group for updates and help.",
"LINK_BLOG": "Blog",
"LINK_GITHUB_DESCRIPTION": "Star the repo, open an issue or contribute",
"LINK_BLOG_DESCRIPTION": "Release notes, tips and project updates",
"LINK_TELEGRAM_DESCRIPTION": "Announcements, community and support",
"SUPPORT_TITLE": "Support the project",
"SUPPORT_DESCRIPTION": "IPTVnator is free and open source, built in the open. If it is part of your daily routine, a small contribution helps keep the project alive and shape what comes next — thank you.",
"SUPPORT_SPONSORS_HINT": "Recurring or one-time",
"SUPPORT_KOFI_HINT": "Buy me a coffee",
"EPG_NOTE": "Currently EPG is available only in the electron-based version of IPTVnator.",
"EPG_NOTE_URL_TEXT": "Check it here",
"IMPORT_EXPORT_DATA": "Import/export playlist backups",
"IMPORT_EXPORT_DATA_DESCRIPTION": "Export or restore playlist backups including M3U snapshots, Xtream/Stalker connection metadata, user state, and EPG source URLs.",
"IMPORT_DATA": "Import",
"EXPORT_DATA": "Export",
"EXPORTING_DATA": "Exporting…",
"REMOVE_ALL": "Delete all playlists and playlist data",
"REMOVE_ALL_BUTTON": "Delete all",
"REMOVE_ALL_DESCRIPTION": "Delete every M3U, Xtream, and Stalker playlist stored in the app.",
"REMOVE_DIALOG": {
"TITLE": "Delete all playlists?",
"MESSAGE": "Delete all {{count}} playlists from the app. This also removes stored playlist data on this device.",
"SUMMARY_TITLE": "Playlist sources",
"CONSEQUENCES_TITLE": "This also removes",
"CONSEQUENCE_FAVORITES": "Favorites saved for these playlists",
"CONSEQUENCE_RECENTLY_VIEWED": "Recently viewed history",
"CONSEQUENCE_PLAYBACK": "Saved playback positions",
"CONSEQUENCE_DOWNLOADS": "Download history entries linked to those playlists",
"CONSEQUENCE_XTREAM_CACHE": "Imported Xtream categories and locally cached content",
"BACKUP_HINT": "Use Export first if you want a restorable backup before deleting.",
"CONFIRM": "Delete everything"
},
"IMPORT_ERROR": "Import error, please try with another file.",
"PLAYLISTS_REMOVED": "All playlists and playlist data were removed.",
"MPV_PLAYER_PATH_LABEL": "mpv path",
"MPV_PLAYER_PATH_DESCRIPTION": "Set path to mpv player in your system. It will use the provided path to a mpv binary instead of using the one found in $PATH.",
"MPV_PLAYER_PATH": "mpv player path",
"MPV_REUSE_INSTANCE_LABEL": "Reuse MPV instance",
"MPV_REUSE_INSTANCE_DESCRIPTION": "When enabled, the same MPV window will be reused for playing different streams. When disabled, each stream opens in a new MPV window.",
"VLC_PLAYER_PATH_LABEL": "VLC path",
"VLC_PLAYER_PATH_DESCRIPTION": "Set path to VLC player in your system. It will use the provided path to a VLC binary instead of the default path for our system.",
"VLC_PLAYER_PATH": "VLC player path",
"REMOTE_CONTROL": "Remote control",
"REMOTE_CONTROL_DESCRIPTION": "Enable remote control of the application.",
"REMOTE_CONTROL_PORT": "Remote control port",
"REMOTE_CONTROL_PORT_DESCRIPTION": "Port used for remote control of the application. Port 8765 is used by default.",
"REMOTE_CONTROL_URL": "Remote control URL",
"REMOTE_CONTROL_URL_DESCRIPTION": "Access the remote control from another device on the same network.",
"SHOW_QR_CODE": "Show QR code",
"STATUS_ENABLED": "Enabled",
"STATUS_DISABLED": "Disabled",
"SOURCE_SINGULAR": "source",
"SOURCE_PLURAL": "sources",
"PORT_RANGE_LABEL": "Port (1-65535)",
"PORT_REQUIRED": "Port is required",
"PORT_MIN": "Port must be at least 1",
"PORT_MAX": "Port must be at most 65535",
"PORT_PATTERN": "Only digits are allowed",
"REMOVE_ALL_IN_PROGRESS": "Deleting playlist data…",
"REMOVE_ALL_PROGRESS": "Deleting playlist data… {{current}} / {{total}}",
"PLAYLISTS_REMOVE_FAILED": "Could not delete playlists. Please try again."
},
"THEMES": {
"DARK_THEME": "Dark theme",
"LIGHT_THEME": "Light theme",
"SYSTEM_THEME": "System theme"
},
"CHANNELS": {
"SEARCH_CHANNEL": "Search channel",
"UPLOAD_OR_SELECT_OTHER_PLAYLIST": "Upload or select other playlist",
"ALL_CHANNELS": "All channels",
"GROUPS": "Groups",
"MANAGE_GROUPS": "Manage groups",
"MANAGE_GROUPS_HINT": "Use manage groups to show groups again.",
"NO_VISIBLE_GROUPS": "No visible groups",
"SEARCH_GROUPS": "Search groups",
"UNGROUPED": "Ungrouped",
"UNNAMED_CHANNEL": "Unnamed Channel",
"FAVORITES": "Favorites",
"NO_FAVORITES": "No favorites yet",
"USE_STAR_TO_FAVORITE": "Please use 'star' icon to add channels to your favorites.",
"REMOVE_FAVORITE": "Remove from favorites",
"ADD_FAVORITE": "Add to favorites",
"SHOW_DETAILS": "Show channel details",
"FAVORITES_UPDATED": "Favorites were updated!",
"SELECT_CHANNEL_PLAYBACK": "Please select a channel to start playback",
"SORT_BY": "Sort by",
"SORT_BY_DATE": "Sort by Date Added (Newest First)",
"SORT_BY_RATING": "Sort by Rating",
"SORT_BY_NAME": "Sort by Name (A-Z)",
"LOAD_MORE": "Load more",
"REMAINING": "remaining",
"LOADING": "Loading channels...",
"LOADING_MORE": "Loading more...",
"NO_SEARCH_RESULTS": "No channels found",
"NO_CHANNELS_FOUND": "No channels found",
"TRY_DIFFERENT_SEARCH": "Try a different search term",
"DETAILS_DIALOG": {
"TITLE": "Channel details",
"DESCRIPTION": "Read-only metadata parsed from the playlist file.",
"SUMMARY": "Summary",
"TVG": "TVG metadata",
"CATCHUP": "Catchup",
"HTTP": "HTTP headers",
"NAME": "Name",
"CHANNEL_ID": "Channel ID",
"STREAM_URL": "Stream URL",
"GROUP": "Group",
"RADIO": "Radio",
"CATCHUP_AVAILABLE": "Catchup available",
"WINDOW": "Archive window",
"PLAYBACK_SUPPORTED": "Playback supported",
"EPG_PARAMS": "EPG params",
"TIMESHIFT": "Timeshift",
"TVG_ID": "TVG ID",
"TVG_NAME": "TVG name",
"TVG_URL": "TVG URL",
"TVG_LOGO": "TVG logo",
"TVG_REC": "TVG rec",
"CATCHUP_TYPE": "Catchup type",
"CATCHUP_SOURCE": "Catchup source",
"CATCHUP_DAYS": "Catchup days",
"HTTP_ORIGIN": "Origin",
"HTTP_REFERRER": "Referrer",
"HTTP_USER_AGENT": "User-Agent",
"EMPTY": "Not provided",
"NOT_AVAILABLE": "Not available",
"DAYS_ONE": "1 day",
"DAYS_OTHER": "{{count}} days"
},
"GROUP_MANAGEMENT": {
"TITLE": "Manage groups",
"SELECTED": "Selected",
"SELECT_ALL": "Select all",
"DESELECT_ALL": "Deselect all",
"SEARCH_PLACEHOLDER": "Search groups...",
"NO_RESULTS": "No matching groups found",
"SAVE": "Save"
}
},
"TOP_MENU": {
"OPEN_CHANNELS_LIST": "Open channel list",
"TOGGLE_FAVORITE_FLAG": "Toggle favorite flag",
"OPEN_EPG_LIST": "Open EPG list",
"OPEN_MULTI_EPG": "Open Multi-EPG view",
"SHOW_INFO": "Show program info (Press I)"
},
"EPG": {
"TITLE": "Electronic Program Guide",
"NEXT_DAY": "Next day",
"PREVIOUS_DAY": "Previous day",
"LIVE_NOW": "Live now",
"LIVE_STREAM": "Live stream",
"TIMESHIFT_AVAILABLE": "Timeshift is available, click to play",
"ARCHIVE_PLAYBACK_UNAVAILABLE_TITLE": "Archive playback is unavailable",
"ARCHIVE_PLAYBACK_UNAVAILABLE_DESCRIPTION": "This provider exposes schedule history for the channel, but does not expose playable archive/catch-up playback.",
"EPG_NOT_AVAILABLE_DATE": "Ooops, EPG is not available for the selected date",
"EPG_NOT_AVAILABLE_CHANNEL_TITLE": "Ooops, EPG is not available for this channel.",
"EPG_NOT_AVAILABLE_CHANNEL_DESCRIPTION": "Please add/change the URL of the EPG list in the settings of the app.",
"FETCH_EPG": "Fetching EPG data...",
"ERROR": "Ooops, EPG could not be loaded.",
"DOWNLOAD_SUCCESS": "EPG was successfully downloaded.",
"NO_PROGRAM_INFO": "No program information available",
"PROGRAM_DIALOG": {
"PROGRAM_DETAILS": "Details about the TV program",
"TITLE": "Title",
"CATEGORY": "Category",
"PARENTAL_RATING_SYSTEM": "Rating",
"DESCRIPTION": "Description",
"LANGUAGE": "Language",
"SHOW_PROGRAM_DETAILS": "Show details about this program",
"EPISODE": "Episode",
"DURATION": "Duration"
},
"FETCH_SUCCESS": "EPG was fetched successfully",
"IMPORT_PROGRESS": "EPG Import",
"CHANNELS": "channels",
"PROGRAMS": "programs",
"LOADING": "Loading",
"QUEUED": "Queued",
"TOTAL_CHANNELS": "Total channels",
"TOTAL_PROGRAMS": "Total programs",
"UP_TO_DATE": "EPG is up-to-date, no sync needed",
"RETRY": "Retry"
},
"LANGUAGES": {
"ARABIC": "العربية",
"MOROCCAN_ARABIC": "العربية (اللهجة المغربية)",
"ENGLISH": "English",
"KOREAN": "한국어",
"RUSSIAN": "Русский",
"GERMAN": "Deutsch",
"SPANISH": "Español",
"CHINESE": "简体中文",
"TRADITIONAL_CHINESE": "繁體中文",
"FRENCH": "Français",
"ITALIAN": "Italiano",
"TURKISH": "Türkçe",
"JAPANESE": "日本語",
"DUTCH": "Nederlands",
"BELARUSIAN": "Беларуская",
"POLISH": "Polski",
"PORTUGUESE": "Português",
"GREEK": "Ελληνικά"
},
"YES": "Yes",
"NO": "No",
"MENU": {
"OPEN": "Open menu",
"SUPPORT_ARIA": "Support IPTVnator on GitHub",
"SETTINGS": "Settings",
"SETTINGS_ARIA": "Open settings",
"BUG_REPORT": "Report a bug",
"WHAT_IS_NEW": "What is new",
"ABOUT": "About",
"ABOUT_ARIA": "About the application",
"SUPPORT_PROJECT": "Support project"
},
"ABOUT": {
"TITLE": "About IPTVnator",
"DESCRIPTION": "Cross-platform IPTV player application with multiple features, such as support of m3u and m3u8 playlists, favorites, TV guide, TV archive/catchup and more.",
"VERSION": "Version",
"GITHUB_TOOLTIP": "ITPVnator repository on GitHub",
"BUY_ME_A_COFFEE_TOOLTIP": "Buy me a coffee",
"TWITTER_TOOLTIP": "Share on Twitter"
},
"UPDATE_AVAILABLE": "Update available",
"REFRESH": "Refresh",
"XTREAM": {
"PLAY": "Play",
"OPENING_PLAYER": "Opening player...",
"NAME": "Name",
"RELEASE_DATE": "Release date",
"GENRE": "Genre",
"COUNTRY": "Country",
"ACTORS": "Actors",
"DIRECTOR": "Director",
"DURATION": "Duration",
"CAST": "Cast",
"EPISODE_RUN_TIME": "Episode run time",
"RATING": "Rating",
"IMDB_RATING": " Rating IMDB",
"KINOPOISK_RATING": "Rating Kinopoisk",
"DESCRIPTION": "Description",
"YEAR": "Year",
"AGE": "Age",
"YOUTUBE_TRAILER": "YouTube Trailer",
"EPISODE": "Episode",
"RESUME": "Resume",
"RESTART": "Start Over",
"CONTINUE_WATCHING": "Continue Watching",
"WATCHED": "Watched",
"IN_PROGRESS": "In Progress",
"MARK_WATCHED": "Mark as Watched",
"MARK_UNWATCHED": "Mark as Unwatched",
"EPISODES_WATCHED": "{{count}} of {{total}} episodes watched",
"DETAIL_FALLBACK": {
"STATUS": "Portal metadata unavailable",
"NOTE": "Extended metadata was not provided by this portal.",
"STREAM_ID": "Stream ID",
"CATEGORY": "Category",
"CONTAINER": "Format",
"SOURCE_TITLE": "Source title"
},
"ACCOUNT_INFO": {
"TITLE": "Account Information",
"USER_INFO": "User Information",
"STATUS": "Status",
"USERNAME": "Username",
"ACTIVE_CONNECTIONS": "Active Connections",
"CREATED": "Created",
"EXPIRES": "Expires",
"TRIAL_ACCOUNT": "Trial Account",
"YES": "Yes",
"NO": "No",
"ALLOWED_FORMATS": "Allowed Formats",
"SERVER_INFO": "Server Information",
"LIVE_TV": "Live TV",
"MOVIES": "Movies",
"TV_SERIES": "TV Series",
"URL": "URL",
"PROTOCOL": "Protocol",
"TIMEZONE": "Timezone",
"SERVER_TIME": "Server Time",
"PORTS": "Ports",
"HTTP_PORT": "HTTP",
"HTTPS_PORT": "HTTPS",
"RTMP_PORT": "RTMP"
},
"CATEGORY_MANAGEMENT": {
"TITLE": "Manage Categories",
"LOADING": "Loading categories...",
"SELECTED": "Selected",
"SELECT_ALL": "Select All",
"DESELECT_ALL": "Deselect All",
"SEARCH_PLACEHOLDER": "Search categories...",
"NO_RESULTS": "No matching categories found",
"SAVE": "Save"
}
},
"PORTALS": {
"ALL_CATEGORIES": "All categories",
"MY_FAVORITES": "My favorites",
"ADD_TO_FAVORITES": "Add to favorites",
"REMOVE_FROM_FAVORITES": "Remove from favorites",
"REMOVED_FROM_FAVORITES": "Removed from favorites",
"ADDED_TO_FAVORITES": "Added to favorites",
"FAVORITES": "Favorites",
"RECENTLY_VIEWED": "Recently viewed",
"THIS_PLAYLIST": "This playlist",
"ALL_PLAYLISTS": "All playlists",
"LIVE_TV": "Live TV",
"MOVIES": "Movies",
"SERIES": "Series",
"SEARCH": "Search",
"NO_FAVORITES": "No favorites yet",
"NO_RECENT_ITEMS": "No recently viewed items",
"REMOVE_FROM_RECENT": "Remove from recently viewed",
"BROWSE_ALL_MOVIES": "Browse all movies",
"BROWSE_ALL_SERIES": "Browse all series",
"BROWSE_ALL_LIVE": "Browse all live TV",
"SIDEBAR": {
"MAIN": "Main",
"MOVIES": "Movies",
"LIVE_TV": "Live TV",
"SERIES": "Series",
"LIBRARY": "Library",
"SEARCH": "Search",
"RECENT": "Recent",
"RECENTLY_ADDED": "Recently added",
"FAVORITES": "Favorites",
"HOME": "Home",
"PLAYLIST_INFO": "Playlist info",
"ACCOUNT_INFO": "Account info"
},
"ERROR_VIEW": {
"IMPORT_CANCELLED": {
"TITLE": "Import cancelled",
"DESCRIPTION": "The playlist import was cancelled. Retry when you want to continue loading this source."
},
"ACCOUNT_EXPIRED": {
"TITLE": "Account expired",
"DESCRIPTION": "This account has been expired. Please check the credentials in playlist settings or remove it."
},
"ACCOUNT_INACTIVE": {
"TITLE": "Account inactive",
"DESCRIPTION": "This account is inactive. Please check the credentials in playlist settings or remove it."
},
"UNAUTHORIZED": {
"TITLE": "Unauthorized",
"DESCRIPTION": "Please check the credentials in playlist settings or remove it."
},
"NOT_FOUND": {
"TITLE": "Portal not found",
"DESCRIPTION": "Please check the credentials and portal url in playlist settings or remove it."
},
"PORTAL_UNAVAILABLE": {
"TITLE": "Portal unavailable",
"DESCRIPTION": "The portal could not be reached. Check the server URL or retry when the source is available again."
},
"EMPTY_CATEGORY": {
"TITLE": "No content in this category",
"DESCRIPTION": "Select another category or switch the content type."
},
"UNKNOWN_ERROR": {
"TITLE": "Something went wrong",
"DESCRIPTION": "Unknown error, please try again later"
},
"NO_CATEGORY_SELECTED": {
"TITLE": "No category selected",
"DESCRIPTION": "Please select a category to see the content"
},
"PLAYLIST_SETTINGS": "Playlist Settings",
"HOME": "Home",
"DELETE": "Delete"
},
"EMPTY_LIST_VIEW": {
"TITLE": "No results found",
"NO_SEARCH_RESULTS": "Nothing found, try to change you search request"
},
"SEARCH_VIEW": {
"INITIAL_TITLE": "Search for content",
"INITIAL_DESCRIPTION": "Enter at least 3 characters to search across live TV, movies and series.",
"RESULTS_FOUND": "Found {{count}} results",
"NO_RESULTS_FOR": "No results found for \"{{term}}\"",
"GROUP_BY_PLAYLIST": "Group results by playlist",
"XTREAM_ONLY_NOTE": "Global search is currently available for Xtream playlists only.",
"VISIBLE_CATEGORIES_ONLY": "Visible categories only"
},
"STREAM_URL_COPIED": "Stream URL copied to clipboard",
"COPY_STREAM_URL": "Copy Stream URL",
"SELECT_CATEGORY": "Select a category",
"PAGE": "Page",
"CONTENT_NOT_AVAILABLE": "This content is not available on this server",
"PLAYBACK_ERROR": "Failed to get playback URL",
"LOADING_SEASONS": "Loading seasons...",
"NO_EPISODES": "No episodes available"
},
"INFORMATION": "Information",
"DOWNLOADS": {
"TITLE": "Downloads",
"DOWNLOAD": "Download",
"PLAY_LOCAL": "Play Local",
"EMPTY": "No downloads yet",
"EMPTY_HINT": "Download movies and episodes to watch offline",
"NO_PLAYLISTS_TITLE": "Add a playlist to start downloading",
"NO_PLAYLISTS_BODY": "Once you add a playlist, you can save movies and episodes here for offline playback.",
"NO_ITEMS_BODY": "Use the download button on any movie or episode to save it for offline playback.",
"NO_FILTER_MATCH": "No downloads match the current filter",
"NO_FILTER_MATCH_HINT": "Try a different search term",
"NOT_AVAILABLE": "Downloads not available",
"DESKTOP_ONLY": "This feature is only available in the desktop app",
"NO_FOLDER": "No download folder selected",
"CHANGE_FOLDER": "Change Folder",
"CLEAR_COMPLETED": "Clear Completed",
"CLEAR_COMPLETED_DIALOG": {
"TITLE": "Clear completed downloads",
"MESSAGE": "This removes completed, failed, and canceled entries from the current downloads view. It does not delete any files that were already downloaded to disk."
},
"SOURCE_PLAYLIST_MISSING": "This download can no longer open in the library because its source playlist was removed.",
"FILE_NOT_FOUND": "This downloaded file is no longer available on disk.",
"FILE_ACTION_ERROR": "The file action could not be completed.",
"CANCEL": "Cancel",
"RETRY": "Retry",
"REMOVE": "Remove",
"PLAY": "Play",
"REVEAL": "Show in Folder",
"COPY_URL": "Copy download URL",
"URL_COPIED": "Download URL copied to clipboard",
"URL_COPY_FAILED": "Failed to copy URL to clipboard",
"STATUS": {
"QUEUED": "Queued",
"DOWNLOADING": "Downloading",
"COMPLETED": "Completed",
"FAILED": "Failed",
"CANCELED": "Canceled"
}
},
"REMOTE_CONTROL": {
"TITLE": "Remote control",
"SUBTITLE": "Control your IPTV player remotely",
"UP_CHANNEL": "Channel Up",
"DOWN_CHANNEL": "Channel Down",
"HEADER": "IPTVNator Remote Control",
"FOOTER": "IPTVNator Remote Control"
},
"WORKSPACE": {
"FAVORITES_ONLY": "Favorites only",
"SORT_CUSTOM": "Custom order",
"SORT_DATE_DESC": "Date Added (Latest First)",
"SORT_DATE_ASC": "Date Added (Oldest First)",
"SORT_NAME_ASC": "Name A-Z",
"SORT_NAME_DESC": "Name Z-A",
"SORT_LABEL": "Sort: ",
"DASHBOARD": {
"CONTINUE_WATCHING": "Continue Watching",
"UNTITLED_SOURCE": "Untitled source",
"GLOBAL_FAVORITES": "Global Favorites",
"REMOVE_FROM_HISTORY": "Remove from history",
"RECENT_SOURCES": "Recently Used Sources",
"MANAGE_ALL": "Manage all",
"RECENTLY_WATCHED": "Recently Watched",
"XTREAM_RECENTLY_ADDED": "Recently Added on Xtream",
"NO_HISTORY": "No items found for this filter.",
"NO_HISTORY_HINT": "Your watching history will appear here once you start playing content from your playlists.",
"XTREAM": "Xtream",
"STALKER": "Stalker",
"M3U": "M3U",
"STALKER_PORTAL": "Stalker Portal",
"PROVIDER": "Provider",
"TYPE_LIVE": "Live",
"TYPE_MOVIE": "Movie",
"TYPE_SERIES": "Series",
"NOT_YET_SYNCED": "Not yet synced"
},
"SHELL": {
"BRAND_ALT": "IPTVnator",
"RAIL_DASHBOARD": "Dashboard",
"OPEN_DASHBOARD": "Open dashboard",
"RAIL_SOURCES": "Sources",
"OPEN_SOURCES": "Open sources",
"RAIL_GLOBAL_FAVORITES": "Global favorites",
"RAIL_GLOBAL_RECENT": "Recently viewed",
"RAIL_SETTINGS": "Settings",
"OPEN_SETTINGS": "Open settings",
"RAIL_LIBRARY": "Library",
"RAIL_MOVIES": "Movies",
"RAIL_LIVE": "Live TV",
"RAIL_SERIES": "Series",
"RAIL_RECENTLY_ADDED": "Recently added",
"RAIL_SEARCH": "Advanced search",
"RAIL_RECENT": "Recently viewed",
"RAIL_FAVORITES": "Favorites",
"RAIL_DOWNLOADS": "Downloads",
"EXTERNAL_PLAYBACK_CLOSE": "Close player",
"RAIL_ALL_CHANNELS": "All channels",
"RAIL_GROUPS": "Groups",
"RAIL_CONTEXT_ACTIONS": "Section actions",
"QUICK_PLAYER_LABEL": "Player",
"QUICK_PLAYER_ARTPLAYER": "ArtPlayer (in app)",
"QUICK_PLAYER_VLC": "VLC (external)",
"SEARCH_LABEL": "Search",
"SEARCH_SOURCES_PLACEHOLDER": "Search sources (all playlists)...",
"SEARCH_PLAYLIST_PLACEHOLDER": "Search in this playlist...",
"SEARCH_SECTION_PLACEHOLDER": "Search in this section...",
"FILTER_SECTION_PLACEHOLDER": "Filter this section...",
"SEARCH_STATUS_LOADED_ONLY": "Loaded channels only",
"COMMAND_PALETTE_SHORTCUT": "Command palette (Ctrl/Cmd+K)",
"OPEN_COMMAND_PALETTE": "Open command palette",
"ADD_PLAYLIST_ALL": "Add playlist",
"ADD_PLAYLIST": "Add playlist",
"OPEN_DOWNLOADS": "Open downloads",
"OPEN_CONTEXT_ACTIONS": "Open section actions",
"NO_SECTION_ACTIONS": "No actions for this section",
"PLAYLIST_INFO": "Playlist info",
"ACCOUNT_INFO": "Account info",
"REFRESH_PLAYLIST": "Refresh playlist",
"CLEAR_COMPLETED_DOWNLOADS_ALL": "Clear completed downloads (all playlists)",
"CLEAR_COMPLETED_DOWNLOADS_ALL_ARIA": "Clear completed downloads for all playlists",
"CLEAR_COMPLETED_DOWNLOADS_THIS_PLAYLIST": "Clear completed downloads (this playlist)",
"CLEAR_COMPLETED_DOWNLOADS_THIS_PLAYLIST_ARIA": "Clear completed downloads for this playlist",
"CLEAR_RECENTLY_VIEWED_SECTION": "Clear recently viewed",
"CLEAR_RECENTLY_VIEWED_SECTION_ARIA": "Clear recently viewed for this section",
"CLEAR_RECENTLY_VIEWED_TYPE": "Clear recently viewed {{type}}",
"CLEAR_RECENTLY_VIEWED_DIALOG_TITLE": "Clear recently viewed {{type}}?",
"CLEAR_RECENTLY_VIEWED_DIALOG_MESSAGE_PLAYLIST": "All {{type}} items from this playlist will be removed from your recently viewed history. This action cannot be undone.",
"CLEAR_RECENTLY_VIEWED_DIALOG_MESSAGE_ALL": "All {{type}} items across all playlists will be removed from your recently viewed history. This action cannot be undone.",
"CLEAR_FAVORITES_TYPE": "Clear {{type}} favorites",
"CLEAR_FAVORITES_DIALOG_TITLE": "Remove all {{type}} favorites?",
"CLEAR_FAVORITES_DIALOG_MESSAGE_PLAYLIST": "All {{type}} favorites from this playlist will be removed. This action cannot be undone.",
"CLEAR_FAVORITES_DIALOG_MESSAGE_ALL": "All {{type}} favorites across all playlists will be removed. This action cannot be undone.",
"XTREAM_CODE": "Xtream Code",
"STALKER_PORTAL": "Stalker Portal",
"CHANNELS_COUNT": "{{count}} channels",
"NO_SOURCES_AVAILABLE": "No sources available",
"ONE_SOURCE_AVAILABLE": "1 source available",
"SOURCES_AVAILABLE": "{{count}} sources available",
"GO_TO_DASHBOARD": "Back to dashboard",
"GO_TO_SOURCES": "Go to Sources",
"DROP_OVERLAY_TITLE": "Drop to add playlist",
"DROP_OVERLAY_BODY": "Release an .m3u or .m3u8 file anywhere in the workspace to import it.",
"DROP_OVERLAY_REJECTED_BODY": "Please drop an .m3u or .m3u8 file. Press Esc to dismiss.",
"DROP_OVERLAY_REJECTED_UNSUPPORTED": "Unsupported file type",
"DROP_OVERLAY_REJECTED_EMPTY": "That file is empty",
"DROP_OVERLAY_REJECTED_READ_ERROR": "Could not read that file",
"DROP_IMPORT_SUCCESS": "Importing \"{{title}}\"…",
"XTREAM_IMPORT_TITLE": "Syncing playlist",
"XTREAM_IMPORT_REMOTE_BADGE": "Remote source",
"XTREAM_IMPORT_LOCAL_BADGE": "Local library",
"XTREAM_IMPORT_DETAIL_REMOTE": "Waiting on the provider response.",
"XTREAM_IMPORT_DETAIL_LOCAL": "Preparing faster playlist switching for the next visit.",
"XTREAM_IMPORT_PREPARING": "Preparing local library...",
"XTREAM_IMPORT_LOADING": "Fetching playlist data from source...",
"XTREAM_IMPORT_SAVING": "Saving playlist data locally...",
"XTREAM_IMPORT_RESTORING_FAVORITES": "Restoring favorites from local library...",
"XTREAM_IMPORT_RESTORING_RECENT": "Restoring recently viewed from local library...",
"XTREAM_IMPORT_PROGRESS": "{{type}} imported: {{current}} / {{total}}",
"XTREAM_IMPORT_CANCEL": "Stop sync",
"XTREAM_IMPORT_CANCELLING": "Stopping sync...",
"COMMANDS": {
"GLOBAL_SEARCH_LABEL": "Search all Xtream playlists",
"GLOBAL_SEARCH_DESCRIPTION": "Open global search overlay",
"PLAYLIST_SEARCH_LABEL": "Advanced search this playlist",
"PLAYLIST_SEARCH_DESCRIPTION": "Open advanced playlist search",
"OPEN_GLOBAL_FAVORITES_LABEL": "Open global favorites",
"OPEN_GLOBAL_FAVORITES_DESCRIPTION": "Navigate to aggregated favorites",
"OPEN_DOWNLOADS_LABEL": "Open downloads",
"OPEN_DOWNLOADS_DESCRIPTION": "Navigate to downloads view",
"OPEN_GLOBAL_RECENT_LABEL": "Open recently viewed",
"OPEN_GLOBAL_RECENT_DESCRIPTION": "Open global recently viewed page",
"OPEN_SETTINGS_LABEL": "Open settings",
"OPEN_SETTINGS_DESCRIPTION": "Navigate to application settings",
"OPEN_SOURCES_LABEL": "Manage sources",
"OPEN_SOURCES_DESCRIPTION": "Navigate to source management",
"OPEN_DASHBOARD_LABEL": "Open dashboard",
"OPEN_DASHBOARD_DESCRIPTION": "Navigate to the dashboard",
"ADD_PLAYLIST_LABEL": "Add new source",
"ADD_PLAYLIST_DESCRIPTION": "Open add playlist dialog",
"ADD_PLAYLIST_M3U_LABEL": "Add M3U playlist",
"ADD_PLAYLIST_M3U_DESCRIPTION": "Open add dialog on the M3U file or URL tab",
"ADD_PLAYLIST_XTREAM_LABEL": "Add Xtream Codes playlist",
"ADD_PLAYLIST_XTREAM_DESCRIPTION": "Open add dialog on the Xtream Codes tab",
"ADD_PLAYLIST_STALKER_LABEL": "Add Stalker portal",
"ADD_PLAYLIST_STALKER_DESCRIPTION": "Open add dialog on the Stalker Portal tab",
"REFRESH_PLAYLIST_LABEL": "Refresh playlist",
"REFRESH_PLAYLIST_DESCRIPTION": "Re-sync data from remote source",
"PLAYLIST_INFO_LABEL": "Playlist details",
"PLAYLIST_INFO_DESCRIPTION": "Show current playlist information",
"ACCOUNT_INFO_LABEL": "Account info",
"ACCOUNT_INFO_DESCRIPTION": "Show Xtream server account details",
"OPEN_VIEW_DESCRIPTION": "Navigate to {{view}}",
"CLEAR_CURRENT_VIEW_DESCRIPTION": "Clear all visible {{type}} items in this view",
"OPEN_MULTI_EPG_DESCRIPTION": "Open the multi-channel EPG view",
"GO_TO_VOD_LABEL": "Movies",
"GO_TO_VOD_DESCRIPTION": "Jump to movies section",
"GO_TO_LIVE_LABEL": "Live TV",
"GO_TO_LIVE_DESCRIPTION": "Jump to live TV section",
"GO_TO_SERIES_LABEL": "Series",
"GO_TO_SERIES_DESCRIPTION": "Jump to series section"
}
},
"SOURCES": {
"TITLE": "Sources",
"SUBTITLE": "Filter and sort playlists",
"TYPE": "Type",
"ALL": "All",
"M3U_PLAYLISTS": "M3U Playlists",
"XTREAM_PLAYLISTS": "Xtream Playlists",
"STALKER_PLAYLISTS": "Stalker Playlists",
"ALL_PLAYLISTS": "All Playlists",
"PLAYLIST_COUNT_ONE": "1 playlist",
"PLAYLIST_COUNT_OTHER": "{{count}} playlists"
},
"CONTEXT": {
"CATEGORIES": "Categories",
"MOVIE_CATEGORIES": "Movie Categories",
"SERIES_CATEGORIES": "Series Categories",
"LIVE_CATEGORIES": "Live Categories",
"XTREAM_SYNCING_MOVIES": "Syncing movie categories...",
"XTREAM_SYNCING_SERIES": "Syncing series categories...",
"XTREAM_SYNCING_LIVE": "Syncing live categories...",
"XTREAM_SOURCE": "Xtream source",
"STALKER_PORTAL": "Stalker portal",
"MANAGE_CATEGORIES": "Manage categories",
"LOAD_CATEGORIES_ERROR": "Unable to load categories",
"LOAD_CATEGORIES_ERROR_HINT": "Please retry or verify portal settings.",
"FILTER_BY_TYPE": "Filter by type",
"ITEM_COUNT_ONE": "1 item",
"ITEM_COUNT_OTHER": "{{count}} items",
"SEARCH": "Search",
"SEARCH_CATEGORIES": "Search categories"
},
"COMMAND_PALETTE": {
"TITLE": "Command palette",
"SUBTITLE": "Global and contextual actions",
"SEARCH_PLACEHOLDER": "Type to filter commands",
"SEARCH_LABEL": "Filter commands",
"EMPTY": "No commands found",
"GROUP_GLOBAL": "Global actions",
"GROUP_PLAYLIST": "This playlist",
"GROUP_VIEW": "Current view",
"GROUP_SECTION": "This section"
},
"GLOBAL_FAVORITES": {
"TITLE": "Global Favorites",
"SUBTITLE": "Live TV from all playlists",
"SEARCH_PLACEHOLDER": "Search favorites...",
"NO_RESULTS": "No results",
"NO_RESULTS_HINT": "Try a different search term",
"EMPTY_TITLE": "No live TV favorites yet",
"EMPTY_HINT": "Star live channels from M3U, Xtream, or Stalker playlists to see them here.",
"EMPTY_PLAYER": "Select a channel to start watching",
"NO_PLAYLISTS_TITLE": "No favorites to show",
"NO_PLAYLISTS_BODY": "Add a playlist to start collecting favorites from live channels, movies, and series.",
"NO_ITEMS_TITLE": "No favorites yet",
"NO_ITEMS_BODY": "Tap the star icon on any channel, movie, or series to save it here.",
"UNKNOWN_CHANNEL": "Unknown"
},
"GLOBAL_RECENT": {
"NO_PLAYLISTS_TITLE": "Nothing watched yet",
"NO_PLAYLISTS_BODY": "Add a playlist and your watching history will appear here.",
"NO_ITEMS_TITLE": "Nothing watched yet",
"NO_ITEMS_BODY": "Start watching anything from your library and it will show up here."
}
}
}
+955
View File
@@ -0,0 +1,955 @@
{
"CLOSE": "Cerrar",
"HOME": {
"TITLE": "IPTVnator",
"SUBTITLE": "Selecciona una lista de reproducción del listado o añade una nueva lista al cargar archivos o por una url",
"TABS": {
"RECENTLY_ADDED": "Listas añadidas recientemente",
"FILE_UPLOAD": "Añadir y cargar archivo",
"URL_UPLOAD": "Añadir por url",
"TEXT_IMPORT": "Importar como texto",
"STALKER_PORTAL_IMPORT": "Agregar portal de acosador",
"XTREME_IMPORT": "Add Xtreme Code"
},
"PLAYLISTS": {
"NO_PLAYLISTS": "No se añadieron listas de reproducción",
"ADD_FIRST": "Por favor, añade tu primera lista de la otra pestaña",
"WELCOME_TITLE": "Bienvenido a IPTVnator",
"WELCOME_DESCRIPTION": "Comience su viaje de streaming agregando su primera lista de reproducción. Conéctese a su servicio IPTV favorito y disfrute de TV en vivo, películas y series.",
"ADD_YOUR_FIRST": "Agregar su primera lista",
"FEATURE_M3U": "Archivos M3U/M3U8",
"FEATURE_XTREAM": "Xtream Codes",
"FEATURE_STALKER": "Portal Stalker",
"NO_RESULTS_TITLE": "No se encontraron listas",
"NO_RESULTS_DESCRIPTION": "Ninguna lista coincide con su búsqueda. Intente ajustar los términos de búsqueda o borrar el filtro para ver todas las listas.",
"ADDED_VIA_URL": "Añadido por carga de URL. URL:",
"ADDED_VIA_FILE": "Añadido por carga de archivo",
"CHANNELS": "Canales",
"ADDED": "Añadido",
"SHOW_DETAILS": "Mostrar detalles de la lista",
"REMOVE": "Quitar lista",
"INFO_DIALOG": {
"PLAYLIST_DETAILS": "Detalles de la lista",
"TITLE": "Título",
"FROM_URL": "Añadida desde la URL",
"IMPORT_DATE": "Fecha de importación",
"CHANNELS": "Número de canales",
"CLOSE": "Cerrar",
"SAVE": "Guardar",
"USER_AGENT": "Agente de usuario",
"ORIGINAL_FILENAME": "Nombre de archivo original",
"FILE_PATH": "Ruta de archivo",
"UPDATE_FAILED": "Última actualización de la lista fallida",
"AUTO_UPDATE": "Auto-actualizar",
"AUTO_UPDATE_DESCRIPTION": "Si la función de auto-actualizar se activa, la lista de reproducción se refrescará automáticamente cada vez que se inicia la app.",
"CUSTOM_USER_AGENT": "Algunos proveedores de IPTV necesitan especificar el agente de usuario para reproducir su lista de reproducción.",
"PASSWORD": "Contraseña",
"SERVER_URL": "URL del servidor",
"USERNAME": "Nombre de usuario",
"MAC_ADDRESS": "Dirección MAC",
"EXPORT_PLAYLIST": "Export playlist as m3u",
"PLAYLIST_EXPORT_SUCCESS": "Playlist was exported successfully.",
"PLAYLIST_EXPORT_ERROR": "Error: Playlist export failed.",
"COPY_URL": "Copy URL to clipboard",
"URL_COPIED": "URL copied to clipboard"
},
"REMOVE_DIALOG": {
"TITLE": "Quitar lista de reproducción",
"MESSAGE": "¿Estás seguro de quitar esta lista de reproducción por completo?",
"SUCCESS": "Playlist was removed successfully",
"IN_PROGRESS": "Removing playlist...",
"DELETING_FAVORITES": "Removing favorites...",
"DELETING_RECENT": "Removing recently viewed...",
"DELETING_PROGRESS": "Removing playback progress...",
"DELETING_DOWNLOADS": "Removing downloads...",
"DELETING_CONTENT": "Removing cached content...",
"DELETING_CATEGORIES": "Removing categories...",
"DELETING_PLAYLIST": "Removing playlist record..."
},
"UPDATED": "Actualizado",
"REFRESH": "Actualizar lista",
"GLOBAL_FAVORITES": "Favoritos globales",
"GLOBAL_FAVORITES_DESCRIPTION": "Lista autogenerada con los favoritos agregados de todas las listas",
"MY_PLAYLISTS": "Mis listas",
"PLAYLIST_UPDATE_SUCCESS": "¡Éxito! La lista de reproducción se actualizó correctamente.",
"STALKER_PORTAL": "Stalker Portal",
"FEATURE_M3U_LABEL": "Add an M3U file or URL",
"FEATURE_XTREAM_LABEL": "Connect via Xtream Codes",
"FEATURE_STALKER_LABEL": "Connect to a Stalker portal",
"VALUE_PROPS_LABEL": "What you can do",
"VALUE_PROP_LIVE": "Live TV with EPG",
"VALUE_PROP_VOD": "Movies & Series",
"VALUE_PROP_MULTISOURCE": "Multi-source library",
"VALUE_PROP_OFFLINE": "Offline downloads",
"DASHBOARD_WELCOME_TAGLINE": "Your IPTV library, in one place.",
"FEATURE_LIVE_TITLE": "Live TV",
"FEATURE_LIVE_DESC": "Stream live channels with full schedule.",
"FEATURE_VOD_TITLE": "Movies & Series",
"FEATURE_VOD_DESC": "On-demand library with covers and details.",
"FEATURE_EPG_TITLE": "EPG & Catch-up",
"FEATURE_EPG_DESC": "Program guide and time-shifted playback.",
"FEATURE_OFFLINE_TITLE": "Offline downloads",
"FEATURE_OFFLINE_DESC": "Save movies and episodes for later.",
"SOURCES_WELCOME_TITLE": "Add your first playlist",
"SOURCES_WELCOME_BODY": "Pick a source type below to get started.",
"SOURCE_M3U_NEEDS": "Local file or URL pointing to an M3U/M3U8 playlist.",
"SOURCE_M3U_ADD": "Add M3U",
"SOURCE_XTREAM_NEEDS": "Username, password and server URL from your provider.",
"SOURCE_XTREAM_ADD": "Add Xtream",
"SOURCE_STALKER_NEEDS": "Portal URL and MAC address (Ministra-compatible).",
"SOURCE_STALKER_ADD": "Add Stalker",
"CONTENT_LIVE": "Live",
"CONTENT_VOD": "Movies",
"CONTENT_SERIES": "Series",
"CONTENT_EPG": "EPG",
"DASHBOARD_WELCOME_DESCRIPTION": "Connect M3U files, Xtream Codes, or Stalker portals — then enjoy live TV, movies and series on every screen.",
"XTREAM_PLAYLIST": "Xtream playlist",
"SEARCH_PLAYLISTS": "Search playlists by title",
"REFRESH_XTREAM": "Refresh Xtream playlist from remote",
"REFRESH_XTREAM_DIALOG": {
"TITLE": "Refresh Xtream Playlist",
"MESSAGE": "This will delete locally cached categories and streams and re-import everything from the remote server. Your favorites and recently viewed items will be preserved. Are you sure you want to continue?",
"STARTED": "Refresh started. Navigating to playlist...",
"ERROR": "Failed to refresh playlist. Please try again.",
"IN_PROGRESS": "Refreshing playlist...",
"COLLECTING_DATA": "Collecting favorites and recently viewed...",
"DELETING_CONTENT": "Removing cached content...",
"DELETING_CATEGORIES": "Removing cached categories..."
},
"MY_PLAYLISTS_SUBTITLE": "all available playlists",
"PLAYLIST_UPDATE_ERROR": "Error updating playlist details.",
"PLAYLIST_UPDATE_FILE_NOT_FOUND": "Playlist refresh failed. The local file is no longer available. Check the file path or re-import the playlist.",
"PLAYLIST_UPDATE_FILE_ACCESS_ERROR": "Playlist refresh failed. The app can no longer access the local file.",
"AUTO_REFRESH_UPDATE_SUCCESS": "Success! The playlists were successfully updated",
"AUTO_REFRESH_ENABLED": "Auto-refresh enabled"
},
"FILE_UPLOAD": {
"DRAG_DROP": "Arrastre & suelte archivos aquí",
"OR": "o",
"CHOOSE_PLAYLIST": "Escoga una lista de reproducción",
"REJECTED": "El archivo fue rechazado, formato de archivo no compatible {{filename}}.",
"BROWSE": "Browse files"
},
"URL_UPLOAD": {
"PLAYLIST_URL": "Lista de reproducción (m3u, m3u8)",
"ADD_PLAYLIST": "Añadir lista",
"CORS_NOTE": "Note: In order to avoid CORS issues at this point the application uses a public CORS Proxy service. If you want to upload a playlist with sensitive data, it's more secure to import it from a file.",
"ERROR_FETCH_FAILED": "Failed to fetch the playlist. Please check the URL and try again.",
"ERROR_403": "Access denied (403): The server refused the request. The URL may require authentication or the playlist is restricted.",
"ERROR_404": "Playlist not found (404): The URL does not point to a valid playlist. Please check the URL.",
"ERROR_401": "Unauthorized (401): Authentication is required to access this playlist."
},
"TEXT_IMPORT": {
"LABEL": "Inserte la playlist m3u(8) como texto",
"BUTTON_LABEL": "Importar"
},
"STALKER_PORTAL": {
"ADD": "Agregar",
"TITLE": "Título",
"SERVER_URL": "URL del servidor",
"MAC_ADDRESS": "Dirección Mac",
"URL_VALIDATION_ERROR": "Debe ser una URL válida con protocolo (por ejemplo, http://example.com/c o https://example.com/stalker_portal/c).",
"SERIAL_NUMBER": "Serial Number (Optional)",
"SERIAL_NUMBER_HINT": "Use if already registered with provider",
"DEVICE_ID_1": "Device ID 1 (Optional)",
"DEVICE_ID_2": "Device ID 2 (Optional)",
"DEVICE_ID_HINT": "64 hex characters - use if provider requires specific device ID",
"SIGNATURE_1": "Signature 1 (Optional)",
"SIGNATURE_2": "Signature 2 (Optional)",
"SIGNATURE_HINT": "64 hex characters - use if provider requires device verification signatures",
"VALIDATING": "Validating portal..."
},
"FILTER_BY_TYPE": "Filtrar por tipo",
"IMPORTED_AS_TEXT": "Importado como texto",
"FILTER_BY_NAME": "Filtrar por nombre",
"PARSING_ERROR": "Error: Error al analizar, no es una lista de reproducción válida:",
"XTREAM_PLAYLIST": {
"TITLE": "Título de la lista",
"SERVER_URL": "URL del servidor",
"USERNAME": "Usuario",
"PASSWORD": "Contraseña",
"ADD": "Añadir",
"TEST_CREDENTIALS": "Probar credenciales",
"TEST_CONNECTION": "Probar conexión",
"TESTING": "Probando…",
"URL_VALIDATION_ERROR": "Debe ser una URL válida con protocolo (por ejemplo, http://example.com o https://example.com:4324)."
},
"KIRATV": {
"ADD_PLAYLIST_TITLE": "Conectar KiraTV",
"FIXED_SERVER": "Servidor:",
"FIXED_PLAYLIST_TITLE": "Lista:",
"WELCOME_TITLE": "Bienvenido a KiraTV",
"WELCOME_TAGLINE": "Tu IPTV para toda la familia",
"WELCOME_DESCRIPTION": "Inicia sesión con tu usuario y contraseña de Kira Cloud para ver TV en directo, películas y series.",
"ADD_FIRST_CTA": "Iniciar sesión"
},
"FILTER_AND_SORT": "Filter & Sort",
"SORT_PLAYLISTS": "Sort playlists",
"SORT_BY": "Sort By",
"SORT_OPTIONS": {
"NAME_ASC": "Name (A-Z)",
"NAME_DESC": "Name (Z-A)",
"NEWEST": "Date added (Newest first)",
"OLDEST": "Date added (Oldest first)",
"CUSTOM_ORDER": "Custom order (Drag & Drop)"
},
"PLAYLIST_TYPES": {
"M3U": "M3U (local, url, text)",
"XTREAM": "Xtream",
"STALKER": "Stalker"
}
},
"SETTINGS": {
"TITLE": "Ajustes",
"GENERAL": "General",
"GENERAL_SUBTITLE": "Cambia la configuracion general de la aplicacion",
"PLAYBACK": "Reproduccion",
"EPG_SOURCES": "Fuentes EPG",
"EPG_SOURCES_DESCRIPTION": "Agrega una o varias URL como fuentes EPG",
"DATA": "Datos",
"ABOUT": "Acerca de",
"NAV_GENERAL": "General",
"NAV_PLAYBACK": "Reproduccion",
"NAV_EPG": "EPG",
"NAV_REMOTE": "Remoto",
"NAV_DATA": "Datos",
"NAV_ABOUT": "Acerca de",
"APP_PREFERENCES": "Preferencias de la app",
"HERO_EYEBROW": "Ajustes del espacio de trabajo",
"HERO_TITLE": "Configura como se siente IPTVnator",
"HERO_DESCRIPTION": "Ajusta reproduccion, guias, acceso remoto y manejo de datos desde un solo lugar sin perder el estilo actual del espacio de trabajo.",
"SUBTITLE": "Cambiar la configuración de la aplicación",
"DESCRIPTION": "Por favor, adapta las opciones de la siguiente lista y confirma con un botón de guardar",
"EPG_URL_LABEL": "Url de la EPG (*.xml o *.xml.gz)",
"EPG_URL_PLACEHOLDER": "Ingresa una URL",
"REFRESH_EPG": "Actualizar EPG",
"REFRESH_ALL_EPG": "Actualizar todo",
"REMOVE_EPG_SOURCE": "Eliminar fuente EPG",
"EPG_STATUS_FRESH": "Actualizado",
"EPG_STATUS_STALE": "Necesita actualización",
"EPG_STATUS_ERROR": "Error",
"VIDEO_PLAYER_LABEL": "Reproductor de vídeo",
"PLAYER_HTML5": "Reproductor HTML5",
"PLAYER_VIDEOJS": "Reproductor Video.js",
"PLAYER_ARTPLAYER": "ArtPlayer",
"PLAYER_MPV": "Reproductor MPV",
"PLAYER_VLC": "VLC",
"VIDEO_PLAYER_PLACEHOLDER": "Selecciona una opción",
"VERSION": "Versión",
"SAVE_CHANGES": "Guardar cambios",
"BACK_TO_HOME": "Volver al inicio",
"NEW_VERSION_AVAILABLE": "Hay una nueva versión disponible",
"LATEST_VERSION": "Estás usando la versión reciente",
"STREAM_FORMAT": "Formato de transmision",
"LANGUAGE": "Idioma",
"SETTINGS_SAVED": "¡Completado! La configuración se guardó.",
"THEME": "Tema visual",
"SHOW_CAPTIONS": "Mostrar subtítulos",
"REMOVE_ALL": "Delete all playlists and playlist data",
"REMOVE_ALL_BUTTON": "Delete all",
"CLEAR_EPG_DATA": "Borrar datos EPG",
"CLEAR_EPG_DIALOG": {
"TITLE": "Borrar datos EPG",
"MESSAGE": "¿Seguro que quieres eliminar todos los datos EPG de la base de datos? Esto borrará toda la programacion almacenada en caché."
},
"EPG_DATA_CLEARED": "Los datos EPG se borraron",
"EPG_DATA_CLEAR_FAILED": "No se pudieron borrar los datos EPG. Inténtalo de nuevo.",
"CLEARING_EPG_DATA": "Borrando…",
"REMOVE_DIALOG": {
"TITLE": "Delete all playlists?",
"MESSAGE": "Delete all {{count}} playlists from the app. This also removes stored playlist data on this device.",
"SUMMARY_TITLE": "Playlist sources",
"CONSEQUENCES_TITLE": "This also removes",
"CONSEQUENCE_FAVORITES": "Favorites saved for these playlists",
"CONSEQUENCE_RECENTLY_VIEWED": "Recently viewed history",
"CONSEQUENCE_PLAYBACK": "Saved playback positions",
"CONSEQUENCE_DOWNLOADS": "Download history entries linked to those playlists",
"CONSEQUENCE_XTREAM_CACHE": "Imported Xtream categories and locally cached content",
"BACKUP_HINT": "Use Export first if you want a restorable backup before deleting.",
"CONFIRM": "Delete everything"
},
"LANGUAGE_DESCRIPTION": "Seleccione el idioma de la aplicación",
"PLAYLISTS_REMOVED": "All playlists and playlist data were removed.",
"VERSION_DESCRIPTION": "Versión actual de la aplicación.",
"MPV_PLAYER_PATH": "ruta del reproductor mpv",
"MPV_PLAYER_PATH_DESCRIPTION": "Establece la ruta al reproductor mpv en tu sistema. Se usará la ruta proporcionada al binario de mpv en lugar de la encontrada en $PATH.",
"MPV_REUSE_INSTANCE_LABEL": "Reutilizar instancia de MPV",
"MPV_REUSE_INSTANCE_DESCRIPTION": "Cuando esta opción está activada, se reutiliza la misma ventana de MPV para reproducir distintos streams. Cuando está desactivada, cada stream se abre en una nueva ventana de MPV.",
"SHOW_CAPTIONS_DESCRIPTION": "Mostrar u ocultar subtítulos por defecto",
"IMPORT_DATA": "Importar",
"ADD_EPG_SOURCE": "Agregar fuente EPG",
"IMPORT_ERROR": "Error de importación, intente con otro archivo.",
"EPG_URL_ERROR": "El valor no es una URL válida.",
"EXPORT_DATA": "Exportar",
"EXPORTING_DATA": "Exportando…",
"VIDEO_PLAYER_DESCRIPTION": "Seleccionar reproductor de vídeo predeterminado",
"IMPORT_EXPORT_DATA": "Importar/exportar copias de seguridad",
"VLC_PLAYER_PATH_LABEL": "ruta VLC",
"VLC_PLAYER_PATH_DESCRIPTION": "Establezca la ruta al reproductor VLC en su sistema. \nUtilizará la ruta proporcionada a un binario VLC en lugar de la ruta predeterminada para nuestro sistema.",
"THEME_DESCRIPTION": "Seleccione el tema visual de la aplicación.",
"EPG_NOTE": "Actualmente, EPG está disponible sólo en la versión electrónica de IPTVnator.",
"VLC_PLAYER_PATH": "Ruta del reproductor VLC",
"IMPORT_EXPORT_DATA_DESCRIPTION": "Exporte o restaure copias de seguridad con instantáneas M3U, metadatos de conexión de Xtream/Stalker, estado del usuario y URLs de EPG.",
"EPG_NOTE_URL_TEXT": "Compruébalo aquí",
"MPV_PLAYER_PATH_LABEL": "Ruta de mpv",
"REMOVE_ALL_DESCRIPTION": "Delete every M3U, Xtream, and Stalker playlist stored in the app.",
"REMOTE_CONTROL": "Control remoto",
"REMOTE_CONTROL_DESCRIPTION": "Habilita el control remoto de la aplicación.",
"REMOTE_CONTROL_PORT": "Puerto de control remoto",
"REMOTE_CONTROL_PORT_DESCRIPTION": "Puerto usado para el control remoto de la aplicación. El puerto 8765 se usa de forma predeterminada.",
"REMOTE_CONTROL_URL": "URL de control remoto",
"REMOTE_CONTROL_URL_DESCRIPTION": "Accede al control remoto desde otro dispositivo en la misma red.",
"SHOW_QR_CODE": "Mostrar codigo QR",
"STATUS_ENABLED": "Activado",
"STATUS_DISABLED": "Desactivado",
"SOURCE_SINGULAR": "fuente",
"SOURCE_PLURAL": "fuentes",
"PORT_RANGE_LABEL": "Puerto (1-65535)",
"PORT_REQUIRED": "El puerto es obligatorio",
"PORT_MIN": "El puerto debe ser al menos 1",
"PORT_MAX": "El puerto debe ser como máximo 65535",
"PORT_PATTERN": "Solo se permiten digitos",
"STREAM_FORMAT_DESCRIPTION": "Selecciona el formato de transmision predeterminado (Xtream)",
"REMOVE_ALL_IN_PROGRESS": "Deleting playlist data…",
"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.",
"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",
"PLAYER_EMBEDDED_MPV": "Embedded MPV (Experimental, macOS)",
"SHOW_DASHBOARD": "Show dashboard",
"SHOW_DASHBOARD_DESCRIPTION": "Keep Dashboard available in the workspace rail. When disabled, Sources becomes the first workspace page.",
"STARTUP_BEHAVIOR": "Startup view",
"STARTUP_BEHAVIOR_DESCRIPTION": "Choose whether IPTVnator opens the first available workspace view or restores your last section-level view. First view means Dashboard when enabled, otherwise Sources.",
"STARTUP_BEHAVIOR_FIRST_VIEW": "First available view",
"STARTUP_BEHAVIOR_RESTORE_LAST_VIEW": "Restore last view",
"SHOW_EXTERNAL_PLAYBACK_BAR": "Show now playing footer",
"SHOW_EXTERNAL_PLAYBACK_BAR_DESCRIPTION": "Keep the external-player status bar visible at the bottom of the workspace on desktop.",
"ABOUT_SUBTITLE": "Version, project links and ways to support IPTVnator.",
"EMBEDDED_MPV_NOTICE_TITLE": "Embedded MPV runtime",
"EMBEDDED_MPV_NOTICE_DESCRIPTION": "macOS builds can include bundled libmpv and FFmpeg libraries for the experimental Embedded MPV player. Users do not need to install the MPV app separately; external MPV and VLC remain available as fallback players.",
"COMMUNITY": "Project & community",
"COMMUNITY_DESCRIPTION": "Star the repository, read the blog or join the Telegram group for updates and help.",
"LINK_BLOG": "Blog",
"LINK_GITHUB_DESCRIPTION": "Star the repo, open an issue or contribute",
"LINK_BLOG_DESCRIPTION": "Release notes, tips and project updates",
"LINK_TELEGRAM_DESCRIPTION": "Announcements, community and support",
"SUPPORT_TITLE": "Support the project",
"SUPPORT_DESCRIPTION": "IPTVnator is free and open source, built in the open. If it is part of your daily routine, a small contribution helps keep the project alive and shape what comes next — thank you.",
"SUPPORT_SPONSORS_HINT": "Recurring or one-time",
"SUPPORT_KOFI_HINT": "Buy me a coffee"
},
"THEMES": {
"DARK_THEME": "Tema oscuro",
"LIGHT_THEME": "Tema claro",
"SYSTEM_THEME": "Tema del sistema"
},
"CHANNELS": {
"SEARCH_CHANNEL": "Buscar canal",
"UPLOAD_OR_SELECT_OTHER_PLAYLIST": "Carga o selecciona una lista de reproducción",
"ALL_CHANNELS": "Todos los canales",
"GROUPS": "Grupos",
"UNGROUPED": "Desagrupado",
"UNNAMED_CHANNEL": "Canal sin nombre",
"FAVORITES": "Favoritos",
"NO_FAVORITES": "Sin favoritos",
"USE_STAR_TO_FAVORITE": "Por favor, use el ícono de la 'estrella' para añadir canales a la lista.",
"REMOVE_FAVORITE": "Quitar de favoritos",
"FAVORITES_UPDATED": "¡Se actualizaron los favoritos!",
"MANAGE_GROUPS": "Manage groups",
"MANAGE_GROUPS_HINT": "Use manage groups to show groups again.",
"NO_VISIBLE_GROUPS": "No visible groups",
"SEARCH_GROUPS": "Search groups",
"ADD_FAVORITE": "Add to favorites",
"SHOW_DETAILS": "Show channel details",
"SELECT_CHANNEL_PLAYBACK": "Please select a channel to start playback",
"SORT_BY": "Sort by",
"SORT_BY_DATE": "Sort by Date Added (Newest First)",
"SORT_BY_RATING": "Sort by Rating",
"SORT_BY_NAME": "Sort by Name (A-Z)",
"LOAD_MORE": "Load more",
"REMAINING": "remaining",
"LOADING": "Loading channels...",
"LOADING_MORE": "Loading more...",
"NO_SEARCH_RESULTS": "No channels found",
"NO_CHANNELS_FOUND": "No channels found",
"TRY_DIFFERENT_SEARCH": "Try a different search term",
"DETAILS_DIALOG": {
"TITLE": "Channel details",
"DESCRIPTION": "Read-only metadata parsed from the playlist file.",
"SUMMARY": "Summary",
"TVG": "TVG metadata",
"CATCHUP": "Catchup",
"HTTP": "HTTP headers",
"NAME": "Name",
"CHANNEL_ID": "Channel ID",
"STREAM_URL": "Stream URL",
"GROUP": "Group",
"RADIO": "Radio",
"CATCHUP_AVAILABLE": "Catchup available",
"WINDOW": "Archive window",
"PLAYBACK_SUPPORTED": "Playback supported",
"EPG_PARAMS": "EPG params",
"TIMESHIFT": "Timeshift",
"TVG_ID": "TVG ID",
"TVG_NAME": "TVG name",
"TVG_URL": "TVG URL",
"TVG_LOGO": "TVG logo",
"TVG_REC": "TVG rec",
"CATCHUP_TYPE": "Catchup type",
"CATCHUP_SOURCE": "Catchup source",
"CATCHUP_DAYS": "Catchup days",
"HTTP_ORIGIN": "Origin",
"HTTP_REFERRER": "Referrer",
"HTTP_USER_AGENT": "User-Agent",
"EMPTY": "Not provided",
"NOT_AVAILABLE": "Not available",
"DAYS_ONE": "1 day",
"DAYS_OTHER": "{{count}} days"
},
"GROUP_MANAGEMENT": {
"TITLE": "Manage groups",
"SELECTED": "Selected",
"SELECT_ALL": "Select all",
"DESELECT_ALL": "Deselect all",
"SEARCH_PLACEHOLDER": "Search groups...",
"NO_RESULTS": "No matching groups found",
"SAVE": "Save"
}
},
"TOP_MENU": {
"OPEN_CHANNELS_LIST": "Abrir lista de canales",
"TOGGLE_FAVORITE_FLAG": "Alternar bandera favorita",
"OPEN_EPG_LIST": "Abrir lista EPG",
"OPEN_MULTI_EPG": "Abrir vista Multi-EPG",
"SHOW_INFO": "Show program info (Press I)"
},
"EPG": {
"NEXT_DAY": "Día siguiente",
"PREVIOUS_DAY": "Día anterior",
"LIVE_NOW": "Ahora en vivo",
"LIVE_STREAM": "Transmisión en vivo",
"TIMESHIFT_AVAILABLE": "Timeshift está disponible, clic para reproducir",
"EPG_NOT_AVAILABLE_DATE": "Vaya, no está disponible la EPG de esa fecha",
"EPG_NOT_AVAILABLE_CHANNEL_TITLE": "Vaya, no está disponible la EPG del canal.",
"EPG_NOT_AVAILABLE_CHANNEL_DESCRIPTION": "Por favor añada/cargue la url de la lista EPG en los ajustes de la app.",
"FETCH_EPG": "Obteniendo datos de EPG...",
"ERROR": "¡Vaya! Esta EPG no se pudo cargar.",
"DOWNLOAD_SUCCESS": "La EPG se ha descargado correctamente.",
"PROGRAM_DIALOG": {
"PROGRAM_DETAILS": "Detalles sobre el programa de TV",
"TITLE": "Título",
"CATEGORY": "Género",
"PARENTAL_RATING_SYSTEM": "Sistema de calificación de contenidos televisivos",
"DESCRIPTION": "Descripción",
"LANGUAGE": "Idioma",
"SHOW_PROGRAM_DETAILS": "Mostrar detalles del programa",
"EPISODE": "Episode",
"DURATION": "Duration"
},
"TITLE": "Electronic Program Guide",
"ARCHIVE_PLAYBACK_UNAVAILABLE_TITLE": "Archive playback is unavailable",
"ARCHIVE_PLAYBACK_UNAVAILABLE_DESCRIPTION": "This provider exposes schedule history for the channel, but does not expose playable archive/catch-up playback.",
"NO_PROGRAM_INFO": "No program information available",
"FETCH_SUCCESS": "EPG was fetched successfully",
"IMPORT_PROGRESS": "EPG Import",
"CHANNELS": "channels",
"PROGRAMS": "programs",
"LOADING": "Loading",
"QUEUED": "Queued",
"TOTAL_CHANNELS": "Total channels",
"TOTAL_PROGRAMS": "Total programs",
"UP_TO_DATE": "EPG is up-to-date, no sync needed",
"RETRY": "Retry"
},
"LANGUAGES": {
"ARABIC": "العربية",
"MOROCCAN_ARABIC": "العربية (اللهجة المغربية)",
"ENGLISH": "English",
"KOREAN": "한국어",
"RUSSIAN": "Русский",
"GERMAN": "Deutsch",
"SPANISH": "Español",
"CHINESE": "简体中文",
"TRADITIONAL_CHINESE": "繁體中文",
"FRENCH": "Français",
"ITALIAN": "Italiano",
"TURKISH": "Türkçe",
"JAPANESE": "日本語",
"DUTCH": "Nederlands",
"BELARUSIAN": "Беларуская",
"POLISH": "Polski",
"PORTUGUESE": "Português",
"GREEK": "Ελληνικά"
},
"YES": "Sí",
"NO": "No",
"MENU": {
"OPEN": "Abrir menú",
"SUPPORT_ARIA": "Apoyar IPTVnator en GitHub",
"SETTINGS": "Ajustes",
"SETTINGS_ARIA": "Abrir ajustes",
"BUG_REPORT": "Reportar un bug",
"WHAT_IS_NEW": "Novedades",
"ABOUT": "Acerca de",
"ABOUT_ARIA": "Acerca de la aplicación",
"SUPPORT_PROJECT": "Proyecto de apoyo"
},
"XTREAM": {
"RELEASE_DATE": "Fecha de lanzamiento",
"ACTORS": "Actores",
"PLAY": "Reproducir",
"GENRE": "Género",
"DURATION": "Duración",
"COUNTRY": "País",
"NAME": "Nombre",
"DIRECTOR": "Director",
"CAST": "Elenco",
"RATING": "Clasificación",
"AGE": "Edad",
"EPISODE": "Episodio",
"RESUME": "Continuar",
"RESTART": "Reiniciar",
"CONTINUE_WATCHING": "Continuar viendo",
"WATCHED": "Visto",
"IN_PROGRESS": "En progreso",
"MARK_WATCHED": "Marcar como visto",
"MARK_UNWATCHED": "Marcar como no visto",
"EPISODES_WATCHED": "{{count}} de {{total}} episodios vistos",
"YEAR": "Año",
"YOUTUBE_TRAILER": "Tráiler de YouTube",
"DESCRIPTION": "Descripción",
"KINOPOISK_RATING": "Calificación de Kinopoisk",
"IMDB_RATING": "Calificación IMDB",
"EPISODE_RUN_TIME": "Tiempo de ejecución del episodio",
"OPENING_PLAYER": "Opening player...",
"DETAIL_FALLBACK": {
"STATUS": "Portal metadata unavailable",
"NOTE": "Extended metadata was not provided by this portal.",
"STREAM_ID": "Stream ID",
"CATEGORY": "Category",
"CONTAINER": "Format",
"SOURCE_TITLE": "Source title"
},
"ACCOUNT_INFO": {
"TITLE": "Account Information",
"USER_INFO": "User Information",
"STATUS": "Status",
"USERNAME": "Username",
"ACTIVE_CONNECTIONS": "Active Connections",
"CREATED": "Created",
"EXPIRES": "Expires",
"TRIAL_ACCOUNT": "Trial Account",
"YES": "Yes",
"NO": "No",
"ALLOWED_FORMATS": "Allowed Formats",
"SERVER_INFO": "Server Information",
"LIVE_TV": "Live TV",
"MOVIES": "Movies",
"TV_SERIES": "TV Series",
"URL": "URL",
"PROTOCOL": "Protocol",
"TIMEZONE": "Timezone",
"SERVER_TIME": "Server Time",
"PORTS": "Ports",
"HTTP_PORT": "HTTP",
"HTTPS_PORT": "HTTPS",
"RTMP_PORT": "RTMP"
},
"CATEGORY_MANAGEMENT": {
"TITLE": "Manage Categories",
"LOADING": "Loading categories...",
"SELECTED": "Selected",
"SELECT_ALL": "Select All",
"DESELECT_ALL": "Deselect All",
"SEARCH_PLACEHOLDER": "Search categories...",
"NO_RESULTS": "No matching categories found",
"SAVE": "Save"
}
},
"PORTALS": {
"ALL_CATEGORIES": "Todas las categorias",
"ADD_TO_FAVORITES": "Agregar a los favoritos",
"REMOVE_FROM_FAVORITES": "Quitar de favoritos",
"MY_FAVORITES": "Mis favoritos",
"COPY_STREAM_URL": "Copiar URL de transmisión",
"ERROR_VIEW": {
"DELETE": "Borrar",
"ACCOUNT_EXPIRED": {
"TITLE": "Cuenta caducada",
"DESCRIPTION": "Esta cuenta ha caducado. \nVerifique las credenciales en la configuración de la lista de reproducción o elimínelas."
},
"HOME": "Hogar",
"EMPTY_CATEGORY": {
"TITLE": "categoría vacía",
"DESCRIPTION": "Esta categoría no tiene contenido, seleccione otra categoría o cambie el tipo de contenido"
},
"UNAUTHORIZED": {
"TITLE": "No autorizado",
"DESCRIPTION": "Verifique las credenciales en la configuración de la lista de reproducción o elimínelas."
},
"UNKNOWN_ERROR": {
"TITLE": "algo salió mal",
"DESCRIPTION": "Error desconocido, inténtalo de nuevo más tarde."
},
"PLAYLIST_SETTINGS": "Configuración de lista de reproducción",
"IMPORT_CANCELLED": {
"TITLE": "Import cancelled",
"DESCRIPTION": "The playlist import was cancelled. Retry when you want to continue loading this source."
},
"ACCOUNT_INACTIVE": {
"TITLE": "Account inactive",
"DESCRIPTION": "This account is inactive. Please check the credentials in playlist settings or remove it."
},
"NOT_FOUND": {
"TITLE": "Portal not found",
"DESCRIPTION": "Please check the credentials and portal url in playlist settings or remove it."
},
"PORTAL_UNAVAILABLE": {
"TITLE": "Portal unavailable",
"DESCRIPTION": "The portal could not be reached. Check the server URL or retry when the source is available again."
},
"NO_CATEGORY_SELECTED": {
"TITLE": "No category selected",
"DESCRIPTION": "Please select a category to see the content"
}
},
"STREAM_URL_COPIED": "URL de transmisión copiada al portapapeles",
"EMPTY_LIST_VIEW": {
"NO_SEARCH_RESULTS": "No se encontró nada, intenta cambiar tu solicitud de búsqueda.",
"TITLE": "No results found"
},
"REMOVED_FROM_FAVORITES": "Eliminado de favoritos",
"ADDED_TO_FAVORITES": "Añadido a favoritos",
"SEARCH_VIEW": {
"RESULTS_FOUND": "Se encontraron {{count}} resultados",
"NO_RESULTS_FOR": "No se encontraron resultados para \"{{term}}\"",
"INITIAL_TITLE": "Search for content",
"INITIAL_DESCRIPTION": "Enter at least 3 characters to search across live TV, movies and series.",
"GROUP_BY_PLAYLIST": "Group results by playlist",
"XTREAM_ONLY_NOTE": "Global search is currently available for Xtream playlists only.",
"VISIBLE_CATEGORIES_ONLY": "Visible categories only"
},
"FAVORITES": "Favorites",
"RECENTLY_VIEWED": "Recently viewed",
"THIS_PLAYLIST": "This playlist",
"ALL_PLAYLISTS": "All playlists",
"LIVE_TV": "Live TV",
"MOVIES": "Movies",
"SERIES": "Series",
"SEARCH": "Search",
"NO_FAVORITES": "No favorites yet",
"NO_RECENT_ITEMS": "No recently viewed items",
"REMOVE_FROM_RECENT": "Remove from recently viewed",
"BROWSE_ALL_MOVIES": "Browse all movies",
"BROWSE_ALL_SERIES": "Browse all series",
"BROWSE_ALL_LIVE": "Browse all live TV",
"SIDEBAR": {
"MAIN": "Main",
"MOVIES": "Movies",
"LIVE_TV": "Live TV",
"SERIES": "Series",
"LIBRARY": "Library",
"SEARCH": "Search",
"RECENT": "Recent",
"RECENTLY_ADDED": "Recently added",
"FAVORITES": "Favorites",
"HOME": "Home",
"PLAYLIST_INFO": "Playlist info",
"ACCOUNT_INFO": "Account info"
},
"SELECT_CATEGORY": "Selecciona una categoría",
"PAGE": "Page",
"CONTENT_NOT_AVAILABLE": "This content is not available on this server",
"PLAYBACK_ERROR": "Failed to get playback URL",
"LOADING_SEASONS": "Loading seasons...",
"NO_EPISODES": "No episodes available"
},
"ABOUT": {
"TITLE": "Acerca de IPTVnator",
"VERSION": "Versión",
"TWITTER_TOOLTIP": "Compartir en Twitter",
"GITHUB_TOOLTIP": "Repositorio ITPVnator en GitHub",
"BUY_ME_A_COFFEE_TOOLTIP": "Buy me a coffee",
"DESCRIPTION": "Cross-platform IPTV player application with multiple features, such as support of m3u and m3u8 playlists, favorites, TV guide, TV archive/catchup and more."
},
"REFRESH": "Actualizar",
"UPDATE_AVAILABLE": "Actualización disponible",
"INFORMATION": "Información",
"DOWNLOADS": {
"TITLE": "Descargas",
"DOWNLOAD": "Descargar",
"PLAY_LOCAL": "Reproducir local",
"EMPTY": "Sin descargas aún",
"EMPTY_HINT": "Descarga películas y episodios para ver sin conexión",
"NOT_AVAILABLE": "Descargas no disponibles",
"DESKTOP_ONLY": "Esta función solo está disponible en la aplicación de escritorio",
"NO_FOLDER": "No se ha seleccionado carpeta de descarga",
"CHANGE_FOLDER": "Cambiar carpeta",
"CLEAR_COMPLETED": "Limpiar completados",
"CANCEL": "Cancelar",
"RETRY": "Reintentar",
"REMOVE": "Eliminar",
"PLAY": "Reproducir",
"REVEAL": "Mostrar en carpeta",
"STATUS": {
"QUEUED": "En cola",
"DOWNLOADING": "Descargando",
"COMPLETED": "Completado",
"FAILED": "Fallido",
"CANCELED": "Cancelado"
},
"NO_PLAYLISTS_TITLE": "Add a playlist to start downloading",
"NO_PLAYLISTS_BODY": "Once you add a playlist, you can save movies and episodes here for offline playback.",
"NO_ITEMS_BODY": "Use the download button on any movie or episode to save it for offline playback.",
"NO_FILTER_MATCH": "No downloads match the current filter",
"NO_FILTER_MATCH_HINT": "Try a different search term",
"CLEAR_COMPLETED_DIALOG": {
"TITLE": "Clear completed downloads",
"MESSAGE": "This removes completed, failed, and canceled entries from the current downloads view. It does not delete any files that were already downloaded to disk."
},
"SOURCE_PLAYLIST_MISSING": "This download can no longer open in the library because its source playlist was removed.",
"FILE_NOT_FOUND": "This downloaded file is no longer available on disk.",
"FILE_ACTION_ERROR": "The file action could not be completed.",
"COPY_URL": "Copy download URL",
"URL_COPIED": "Download URL copied to clipboard",
"URL_COPY_FAILED": "Failed to copy URL to clipboard"
},
"WORKSPACE": {
"SHELL": {
"GO_TO_DASHBOARD": "Volver al panel",
"GO_TO_SOURCES": "Ir a fuentes",
"DROP_OVERLAY_TITLE": "Suelta para añadir lista",
"DROP_OVERLAY_BODY": "Suelta un archivo .m3u o .m3u8 en cualquier parte del espacio de trabajo para importarlo.",
"DROP_OVERLAY_REJECTED_BODY": "Suelta un archivo .m3u o .m3u8. Pulsa Esc para cerrar.",
"DROP_OVERLAY_REJECTED_UNSUPPORTED": "Tipo de archivo no admitido",
"DROP_OVERLAY_REJECTED_EMPTY": "Ese archivo está vacío",
"DROP_OVERLAY_REJECTED_READ_ERROR": "No se pudo leer el archivo",
"DROP_IMPORT_SUCCESS": "Importando «{{title}}»…",
"COMMANDS": {
"ADD_PLAYLIST_M3U_LABEL": "Añadir lista M3U",
"ADD_PLAYLIST_M3U_DESCRIPTION": "Abrir el diálogo en la pestaña de archivo o URL M3U",
"ADD_PLAYLIST_XTREAM_LABEL": "Añadir lista Xtream Codes",
"ADD_PLAYLIST_XTREAM_DESCRIPTION": "Abrir el diálogo en la pestaña Xtream Codes",
"ADD_PLAYLIST_STALKER_LABEL": "Añadir portal Stalker",
"ADD_PLAYLIST_STALKER_DESCRIPTION": "Abrir el diálogo en la pestaña Portal Stalker",
"GLOBAL_SEARCH_LABEL": "Buscar en todas las listas Xtream",
"GLOBAL_SEARCH_DESCRIPTION": "Abrir búsqueda global",
"PLAYLIST_SEARCH_LABEL": "Búsqueda avanzada en esta lista",
"PLAYLIST_SEARCH_DESCRIPTION": "Abrir búsqueda avanzada de la lista",
"OPEN_GLOBAL_FAVORITES_LABEL": "Abrir favoritos globales",
"OPEN_GLOBAL_FAVORITES_DESCRIPTION": "Ir a favoritos agregados",
"OPEN_DOWNLOADS_LABEL": "Abrir descargas",
"OPEN_DOWNLOADS_DESCRIPTION": "Ir a la vista de descargas",
"OPEN_GLOBAL_RECENT_LABEL": "Abrir visto recientemente",
"OPEN_GLOBAL_RECENT_DESCRIPTION": "Abrir página global de recientes",
"OPEN_SETTINGS_LABEL": "Abrir ajustes",
"OPEN_SETTINGS_DESCRIPTION": "Ir a los ajustes de la aplicación",
"OPEN_SOURCES_LABEL": "Gestionar fuentes",
"OPEN_SOURCES_DESCRIPTION": "Ir a la gestión de fuentes",
"OPEN_DASHBOARD_LABEL": "Abrir panel",
"OPEN_DASHBOARD_DESCRIPTION": "Ir al panel",
"ADD_PLAYLIST_LABEL": "Añadir fuente",
"ADD_PLAYLIST_DESCRIPTION": "Abrir diálogo para añadir lista",
"REFRESH_PLAYLIST_LABEL": "Actualizar lista",
"REFRESH_PLAYLIST_DESCRIPTION": "Volver a sincronizar con el origen",
"PLAYLIST_INFO_LABEL": "Detalles de la lista",
"PLAYLIST_INFO_DESCRIPTION": "Mostrar información de la lista actual",
"ACCOUNT_INFO_LABEL": "Info de la cuenta",
"ACCOUNT_INFO_DESCRIPTION": "Mostrar datos de la cuenta Xtream",
"OPEN_VIEW_DESCRIPTION": "Ir a {{view}}",
"CLEAR_CURRENT_VIEW_DESCRIPTION": "Borrar todos los elementos visibles de {{type}} en esta vista",
"OPEN_MULTI_EPG_DESCRIPTION": "Abrir la guía multi-canal",
"GO_TO_VOD_LABEL": "Películas",
"GO_TO_VOD_DESCRIPTION": "Ir a películas",
"GO_TO_LIVE_LABEL": "TV en directo",
"GO_TO_LIVE_DESCRIPTION": "Ir a TV en directo",
"GO_TO_SERIES_LABEL": "Series",
"GO_TO_SERIES_DESCRIPTION": "Ir a series"
},
"EXTERNAL_PLAYBACK_CLOSE": "Cerrar reproductor",
"BRAND_ALT": "IPTVnator",
"RAIL_DASHBOARD": "Panel",
"OPEN_DASHBOARD": "Abrir panel",
"RAIL_SOURCES": "Fuentes",
"OPEN_SOURCES": "Abrir fuentes",
"RAIL_GLOBAL_FAVORITES": "Favoritos globales",
"RAIL_GLOBAL_RECENT": "Visto recientemente",
"RAIL_SETTINGS": "Ajustes",
"OPEN_SETTINGS": "Abrir ajustes",
"RAIL_LIBRARY": "Biblioteca",
"RAIL_MOVIES": "Películas",
"RAIL_LIVE": "TV en directo",
"RAIL_SERIES": "Series",
"RAIL_RECENTLY_ADDED": "Añadidos recientemente",
"RAIL_SEARCH": "Búsqueda avanzada",
"RAIL_RECENT": "Visto recientemente",
"RAIL_FAVORITES": "Favoritos",
"RAIL_DOWNLOADS": "Descargas",
"RAIL_ALL_CHANNELS": "Todos los canales",
"RAIL_GROUPS": "Grupos",
"RAIL_CONTEXT_ACTIONS": "Acciones de la sección",
"SEARCH_LABEL": "Buscar",
"SEARCH_SOURCES_PLACEHOLDER": "Buscar fuentes (todas las listas)…",
"SEARCH_PLAYLIST_PLACEHOLDER": "Buscar en esta lista…",
"SEARCH_SECTION_PLACEHOLDER": "Buscar en esta sección…",
"FILTER_SECTION_PLACEHOLDER": "Filtrar esta sección…",
"SEARCH_STATUS_LOADED_ONLY": "Solo canales cargados",
"COMMAND_PALETTE_SHORTCUT": "Paleta de comandos (Ctrl/Cmd+K)",
"OPEN_COMMAND_PALETTE": "Abrir paleta de comandos",
"ADD_PLAYLIST_ALL": "Añadir lista",
"ADD_PLAYLIST": "Añadir lista",
"OPEN_DOWNLOADS": "Abrir descargas",
"OPEN_CONTEXT_ACTIONS": "Abrir acciones de la sección",
"NO_SECTION_ACTIONS": "No hay acciones para esta sección",
"PLAYLIST_INFO": "Info de la lista",
"ACCOUNT_INFO": "Info de la cuenta",
"REFRESH_PLAYLIST": "Actualizar lista",
"CLEAR_COMPLETED_DOWNLOADS_ALL": "Borrar descargas completadas (todas las listas)",
"CLEAR_COMPLETED_DOWNLOADS_ALL_ARIA": "Borrar descargas completadas de todas las listas",
"CLEAR_COMPLETED_DOWNLOADS_THIS_PLAYLIST": "Borrar descargas completadas (esta lista)",
"CLEAR_COMPLETED_DOWNLOADS_THIS_PLAYLIST_ARIA": "Borrar descargas completadas de esta lista",
"CLEAR_RECENTLY_VIEWED_SECTION": "Borrar visto recientemente",
"CLEAR_RECENTLY_VIEWED_SECTION_ARIA": "Borrar visto recientemente de esta sección",
"CLEAR_RECENTLY_VIEWED_TYPE": "Borrar visto recientemente ({{type}})",
"CLEAR_RECENTLY_VIEWED_DIALOG_TITLE": "¿Borrar visto recientemente ({{type}})?",
"CLEAR_RECENTLY_VIEWED_DIALOG_MESSAGE_PLAYLIST": "Se quitarán del historial todos los elementos de {{type}} de esta lista. No se puede deshacer.",
"CLEAR_RECENTLY_VIEWED_DIALOG_MESSAGE_ALL": "Se quitarán del historial todos los elementos de {{type}} de todas las listas. No se puede deshacer.",
"CLEAR_FAVORITES_TYPE": "Borrar favoritos de {{type}}",
"CLEAR_FAVORITES_DIALOG_TITLE": "¿Quitar todos los favoritos de {{type}}?",
"CLEAR_FAVORITES_DIALOG_MESSAGE_PLAYLIST": "Se quitarán todos los favoritos de {{type}} de esta lista. No se puede deshacer.",
"CLEAR_FAVORITES_DIALOG_MESSAGE_ALL": "Se quitarán todos los favoritos de {{type}} de todas las listas. No se puede deshacer.",
"XTREAM_CODE": "Código Xtream",
"STALKER_PORTAL": "Portal Stalker",
"CHANNELS_COUNT": "{{count}} canales",
"NO_SOURCES_AVAILABLE": "No hay fuentes disponibles",
"ONE_SOURCE_AVAILABLE": "1 fuente disponible",
"SOURCES_AVAILABLE": "{{count}} fuentes disponibles",
"XTREAM_IMPORT_TITLE": "Sincronizando lista",
"XTREAM_IMPORT_REMOTE_BADGE": "Fuente remota",
"XTREAM_IMPORT_LOCAL_BADGE": "Biblioteca local",
"XTREAM_IMPORT_DETAIL_REMOTE": "Esperando respuesta del proveedor.",
"XTREAM_IMPORT_DETAIL_LOCAL": "Preparando un cambio de lista más rápido para la próxima visita.",
"XTREAM_IMPORT_PREPARING": "Preparando biblioteca local…",
"XTREAM_IMPORT_LOADING": "Obteniendo datos de la lista…",
"XTREAM_IMPORT_SAVING": "Guardando datos de la lista en local…",
"XTREAM_IMPORT_RESTORING_FAVORITES": "Restaurando favoritos desde local…",
"XTREAM_IMPORT_RESTORING_RECENT": "Restaurando visto recientemente desde local…",
"XTREAM_IMPORT_PROGRESS": "{{type}} importados: {{current}} / {{total}}",
"XTREAM_IMPORT_CANCEL": "Detener sincronización",
"XTREAM_IMPORT_CANCELLING": "Deteniendo sincronización…",
"QUICK_PLAYER_LABEL": "Reproductor",
"QUICK_PLAYER_ARTPLAYER": "ArtPlayer (en la app)",
"QUICK_PLAYER_VLC": "VLC (externo)"
},
"GLOBAL_FAVORITES": {
"NO_PLAYLISTS_TITLE": "No favorites to show",
"NO_PLAYLISTS_BODY": "Add a playlist to start collecting favorites from live channels, movies, and series.",
"NO_ITEMS_TITLE": "No favorites yet",
"NO_ITEMS_BODY": "Tap the star icon on any channel, movie, or series to save it here.",
"TITLE": "Global Favorites",
"SUBTITLE": "Live TV from all playlists",
"SEARCH_PLACEHOLDER": "Search favorites...",
"NO_RESULTS": "No results",
"NO_RESULTS_HINT": "Try a different search term",
"EMPTY_TITLE": "No live TV favorites yet",
"EMPTY_HINT": "Star live channels from M3U, Xtream, or Stalker playlists to see them here.",
"EMPTY_PLAYER": "Select a channel to start watching",
"UNKNOWN_CHANNEL": "Unknown"
},
"GLOBAL_RECENT": {
"NO_PLAYLISTS_TITLE": "Nothing watched yet",
"NO_PLAYLISTS_BODY": "Add a playlist and your watching history will appear here.",
"NO_ITEMS_TITLE": "Nothing watched yet",
"NO_ITEMS_BODY": "Start watching anything from your library and it will show up here."
},
"FAVORITES_ONLY": "Favorites only",
"SORT_CUSTOM": "Custom order",
"SORT_DATE_DESC": "Date Added (Latest First)",
"SORT_DATE_ASC": "Date Added (Oldest First)",
"SORT_NAME_ASC": "Name A-Z",
"SORT_NAME_DESC": "Name Z-A",
"SORT_LABEL": "Sort: ",
"DASHBOARD": {
"CONTINUE_WATCHING": "Continue Watching",
"UNTITLED_SOURCE": "Untitled source",
"GLOBAL_FAVORITES": "Global Favorites",
"REMOVE_FROM_HISTORY": "Remove from history",
"RECENT_SOURCES": "Recently Used Sources",
"MANAGE_ALL": "Manage all",
"RECENTLY_WATCHED": "Recently Watched",
"XTREAM_RECENTLY_ADDED": "Recently Added on Xtream",
"NO_HISTORY": "No items found for this filter.",
"NO_HISTORY_HINT": "Your watching history will appear here once you start playing content from your playlists.",
"XTREAM": "Xtream",
"STALKER": "Stalker",
"M3U": "M3U",
"STALKER_PORTAL": "Stalker Portal",
"PROVIDER": "Provider",
"TYPE_LIVE": "Live",
"TYPE_MOVIE": "Movie",
"TYPE_SERIES": "Series",
"NOT_YET_SYNCED": "Not yet synced"
},
"SOURCES": {
"TITLE": "Sources",
"SUBTITLE": "Filter and sort playlists",
"TYPE": "Type",
"ALL": "All",
"M3U_PLAYLISTS": "M3U Playlists",
"XTREAM_PLAYLISTS": "Xtream Playlists",
"STALKER_PLAYLISTS": "Stalker Playlists",
"ALL_PLAYLISTS": "All Playlists",
"PLAYLIST_COUNT_ONE": "1 playlist",
"PLAYLIST_COUNT_OTHER": "{{count}} playlists"
},
"CONTEXT": {
"CATEGORIES": "Categorías",
"MOVIE_CATEGORIES": "Categorías de películas",
"SERIES_CATEGORIES": "Categorías de series",
"LIVE_CATEGORIES": "Categorías en directo",
"XTREAM_SYNCING_MOVIES": "Sincronizando categorías de películas…",
"XTREAM_SYNCING_SERIES": "Sincronizando categorías de series…",
"XTREAM_SYNCING_LIVE": "Sincronizando categorías en directo…",
"XTREAM_SOURCE": "Fuente Xtream",
"STALKER_PORTAL": "Portal Stalker",
"MANAGE_CATEGORIES": "Gestionar categorías",
"LOAD_CATEGORIES_ERROR": "No se pudieron cargar las categorías",
"LOAD_CATEGORIES_ERROR_HINT": "Reintenta o comprueba la configuración del portal.",
"FILTER_BY_TYPE": "Filtrar por tipo",
"ITEM_COUNT_ONE": "1 elemento",
"ITEM_COUNT_OTHER": "{{count}} elementos",
"SEARCH": "Buscar",
"SEARCH_CATEGORIES": "Buscar categorías"
},
"COMMAND_PALETTE": {
"TITLE": "Paleta de comandos",
"SUBTITLE": "Acciones globales y del contexto",
"SEARCH_PLACEHOLDER": "Escribe para filtrar comandos",
"SEARCH_LABEL": "Filtrar comandos",
"EMPTY": "No se encontraron comandos",
"GROUP_GLOBAL": "Acciones globales",
"GROUP_PLAYLIST": "Esta lista",
"GROUP_VIEW": "Vista actual",
"GROUP_SECTION": "Esta sección"
}
},
"CANCEL": "Cancelar",
"CLEAR": "Limpiar",
"SHOW_MORE": "Más",
"SHOW_LESS": "Menos",
"PLAYLISTS": "Listas de reproducción",
"REMOTE_CONTROL": {
"TITLE": "Control remoto",
"SUBTITLE": "Controla el reproductor IPTV a distancia",
"UP_CHANNEL": "Canal siguiente",
"DOWN_CHANNEL": "Canal anterior",
"HEADER": "Control remoto IPTVnator",
"FOOTER": "Control remoto IPTVnator"
}
}
+483
View File
@@ -0,0 +1,483 @@
{
"CLOSE": "Fermer",
"PLAYLISTS": "Listes de lecture",
"HOME": {
"TITLE": "IPTVnator",
"SUBTITLE": "Choisissez une liste de lecture, ou ajoutez en une nouvelle via un transfert de fichier ou via une URL",
"TABS": {
"RECENTLY_ADDED": "Récemment ajoutés",
"FILE_UPLOAD": "Ajouter un fichier",
"URL_UPLOAD": "Ajouter une URL",
"TEXT_IMPORT": "Importer sous forme de texte",
"XTREME_IMPORT": "Ajouter Xtreme Code",
"STALKER_PORTAL_IMPORT": "Ajouter un portail Stalker"
},
"PLAYLISTS": {
"NO_PLAYLISTS": "Aucune liste de lecture n'a été ajoutée",
"ADD_FIRST": "Veuillez ajouter votre première liste de lecture depuis un autre onglet",
"WELCOME_TITLE": "Bienvenue sur IPTVnator",
"WELCOME_DESCRIPTION": "Commencez votre voyage de streaming en ajoutant votre première liste de lecture. Connectez-vous à votre service IPTV préféré et profitez de la télévision en direct, des films et des séries.",
"ADD_YOUR_FIRST": "Ajouter votre première liste",
"FEATURE_M3U": "Fichiers M3U/M3U8",
"FEATURE_XTREAM": "Xtream Codes",
"FEATURE_STALKER": "Portail Stalker",
"NO_RESULTS_TITLE": "Aucune liste trouvée",
"NO_RESULTS_DESCRIPTION": "Aucune liste ne correspond à votre recherche. Essayez d'ajuster vos termes de recherche ou effacez le filtre pour voir toutes les listes.",
"ADDED_VIA_URL": "Ajouté par URL. URL :",
"ADDED_VIA_FILE": "Ajouté par transfert de fichier",
"XTREAM_PLAYLIST": "Liste Xtream",
"STALKER_PORTAL": "Portail Stalker",
"CHANNELS": "Chaînes",
"ADDED": "Ajouté",
"SHOW_DETAILS": "Afficher les détails de la liste de lecture",
"REMOVE": "Retirer la liste de lecture",
"SEARCH_PLAYLISTS": "Rechercher des listes par titre",
"AUTO_REFRESH_ENABLED": "Actualisation automatique activée",
"INFO_DIALOG": {
"PLAYLIST_DETAILS": "Détails de la liste de lecture",
"TITLE": "Titre",
"FROM_URL": "Ajouté par URL",
"IMPORT_DATE": "Date d'importation",
"CHANNELS": "Nombre de chaînes",
"CLOSE": "Fermer",
"SAVE": "Enregistrer",
"USER_AGENT": "Agent utilisateur",
"ORIGINAL_FILENAME": "Nom du fichier d'origine",
"FILE_PATH": "Chemin du fichier",
"UPDATE_FAILED": "Échec de la dernière mise à jour de liste de lecture",
"AUTO_UPDATE": "Mise à jour automatique",
"AUTO_UPDATE_DESCRIPTION": "Si la fonction de mise à jour automatique est activée, la liste de lecture sera mise à jour automatiquement à chaque fois que l'app est lancée.",
"CUSTOM_USER_AGENT": "Certains fournisseurs d'IPTV requièrent un agent utilisateur spécifique afin de lire leur liste de lecture.",
"EXPORT_PLAYLIST": "Exporter la liste de lecture en m3u",
"SERVER_URL": "URL du serveur",
"USERNAME": "Nom d'utilisateur",
"PASSWORD": "Mot de passe",
"MAC_ADDRESS": "Adresse Mac",
"PLAYLIST_EXPORT_SUCCESS": "La liste de lecture a été exportée avec succès.",
"PLAYLIST_EXPORT_ERROR": "Erreur : Échec de l'exportation de la liste de lecture.",
"COPY_URL": "Copier l'URL dans le presse-papiers",
"URL_COPIED": "URL copiée dans le presse-papiers"
},
"REMOVE_DIALOG": {
"TITLE": "Retirer la liste de lecture",
"MESSAGE": "Êtes-vous certain de vouloir complètement retirer cette liste de lecture ?",
"SUCCESS": "La liste de lecture a été supprimée avec succès"
},
"UPDATED": "Mis à jour",
"REFRESH": "Mettre à jour la liste de lecture",
"REFRESH_XTREAM": "Actualiser la liste Xtream depuis le serveur",
"REFRESH_XTREAM_DIALOG": {
"TITLE": "Actualiser la liste Xtream",
"MESSAGE": "Cela supprimera les catégories et flux mis en cache localement et réimportera tout depuis le serveur distant. Vos favoris et éléments récemment consultés seront conservés. Voulez-vous continuer ?",
"STARTED": "Actualisation démarrée. Navigation vers la liste de lecture...",
"ERROR": "Échec de l'actualisation de la liste de lecture. Veuillez réessayer."
},
"GLOBAL_FAVORITES": "Favoris globaux",
"GLOBAL_FAVORITES_DESCRIPTION": "Liste de lecture générée automatiquement avec les favoris agrégés de toutes les listes",
"MY_PLAYLISTS": "Mes listes de lecture",
"MY_PLAYLISTS_SUBTITLE": "toutes les listes disponibles",
"PLAYLIST_UPDATE_SUCCESS": "Succès ! La liste de lecture a été mise à jour avec succès.",
"PLAYLIST_UPDATE_ERROR": "Erreur lors de la mise à jour des détails de la liste.",
"AUTO_REFRESH_UPDATE_SUCCESS": "Succès ! Les listes de lecture ont été mises à jour avec succès",
"FEATURE_M3U_LABEL": "Add an M3U file or URL",
"FEATURE_XTREAM_LABEL": "Connect via Xtream Codes",
"FEATURE_STALKER_LABEL": "Connect to a Stalker portal",
"VALUE_PROPS_LABEL": "What you can do",
"VALUE_PROP_LIVE": "Live TV with EPG",
"VALUE_PROP_VOD": "Movies & Series",
"VALUE_PROP_MULTISOURCE": "Multi-source library",
"VALUE_PROP_OFFLINE": "Offline downloads",
"DASHBOARD_WELCOME_TAGLINE": "Your IPTV library, in one place.",
"FEATURE_LIVE_TITLE": "Live TV",
"FEATURE_LIVE_DESC": "Stream live channels with full schedule.",
"FEATURE_VOD_TITLE": "Movies & Series",
"FEATURE_VOD_DESC": "On-demand library with covers and details.",
"FEATURE_EPG_TITLE": "EPG & Catch-up",
"FEATURE_EPG_DESC": "Program guide and time-shifted playback.",
"FEATURE_OFFLINE_TITLE": "Offline downloads",
"FEATURE_OFFLINE_DESC": "Save movies and episodes for later.",
"SOURCES_WELCOME_TITLE": "Add your first playlist",
"SOURCES_WELCOME_BODY": "Pick a source type below to get started.",
"SOURCE_M3U_NEEDS": "Local file or URL pointing to an M3U/M3U8 playlist.",
"SOURCE_M3U_ADD": "Add M3U",
"SOURCE_XTREAM_NEEDS": "Username, password and server URL from your provider.",
"SOURCE_XTREAM_ADD": "Add Xtream",
"SOURCE_STALKER_NEEDS": "Portal URL and MAC address (Ministra-compatible).",
"SOURCE_STALKER_ADD": "Add Stalker",
"CONTENT_LIVE": "Live",
"CONTENT_VOD": "Movies",
"CONTENT_SERIES": "Series",
"CONTENT_EPG": "EPG",
"DASHBOARD_WELCOME_DESCRIPTION": "Connect M3U files, Xtream Codes, or Stalker portals — then enjoy live TV, movies and series on every screen."
},
"FILE_UPLOAD": {
"DRAG_DROP": "Glissez un fichier ici",
"OR": "ou",
"CHOOSE_PLAYLIST": "Choisir une liste de lecture",
"REJECTED": "Le fichier a été rejeté, format de fichier non pris en charge {{filename}}."
},
"URL_UPLOAD": {
"PLAYLIST_URL": "URL de la liste de lecture (m3u, m3u8)",
"ADD_PLAYLIST": "Ajouter la liste de lecture",
"CORS_NOTE": "Remarque : Pour éviter les problèmes CORS, l'application utilise un service proxy CORS public. Si vous souhaitez télécharger une liste avec des données sensibles, il est plus sûr de l'importer depuis un fichier."
},
"TEXT_IMPORT": {
"LABEL": "Insérer la liste m3u(8) sous forme de texte",
"BUTTON_LABEL": "Importer"
},
"XTREAM_PLAYLIST": {
"TITLE": "Titre de la liste",
"SERVER_URL": "URL du serveur",
"USERNAME": "Nom d'utilisateur",
"PASSWORD": "Mot de passe",
"ADD": "Ajouter",
"TEST_CREDENTIALS": "Tester les identifiants",
"URL_VALIDATION_ERROR": "Doit être une URL valide avec un protocole (par exemple http://example.com ou https://example.com:4324)"
},
"STALKER_PORTAL": {
"TITLE": "Titre",
"MAC_ADDRESS": "Adresse Mac",
"SERVER_URL": "URL du serveur",
"URL_VALIDATION_ERROR": "Doit être une URL valide avec un protocole (par exemple http://example.com/c ou https://example.com/stalker_portal/c)",
"ADD": "Ajouter"
},
"FILTER_BY_NAME": "Filtrer par nom",
"FILTER_BY_TYPE": "Filtrer par type",
"SORT_PLAYLISTS": "Trier les listes",
"SORT_BY": "Trier par",
"SORT_OPTIONS": {
"NAME_ASC": "Nom (A-Z)",
"NAME_DESC": "Nom (Z-A)",
"NEWEST": "Date d'ajout (Plus récent)",
"OLDEST": "Date d'ajout (Plus ancien)"
},
"IMPORTED_AS_TEXT": "Importé sous forme de texte",
"PARSING_ERROR": "Erreur : échec de l'analyse, liste de lecture non valide :"
},
"SETTINGS": {
"TITLE": "Paramètres",
"SUBTITLE": "Modifiez la configuration de l'application",
"DESCRIPTION": "Changez les options de la liste ci-dessous et enregistrez vos modifications.",
"EPG_URL_LABEL": "URL du EPG (*.xml ou *.xml.gz)",
"EPG_URL_PLACEHOLDER": "Saisir une URL",
"REFRESH_EPG": "Mise à jour de l'EPG",
"REFRESH_ALL_EPG": "Tout actualiser",
"REMOVE_EPG_SOURCE": "Supprimer la source EPG",
"EPG_STATUS_FRESH": "À jour",
"EPG_STATUS_STALE": "À actualiser",
"EPG_STATUS_ERROR": "Échec",
"VIDEO_PLAYER_LABEL": "Lecteur vidéo",
"VIDEO_PLAYER_PLACEHOLDER": "Choisir une option",
"VERSION": "Version",
"SAVE_CHANGES": "Enregistrer les modifications",
"BACK_TO_HOME": "Retourner à l'accueil",
"NEW_VERSION_AVAILABLE": "Une nouvelle version est disponible",
"LATEST_VERSION": "Vous utilisez la dernière version",
"STREAM_FORMAT": "Format du flux",
"LANGUAGE": "Langue",
"SETTINGS_SAVED": "La configuration a été enregistrée avec succès.",
"THEME": "Thème",
"SHOW_CAPTIONS": "Afficher les sous-titres",
"ADD_EPG_SOURCE": "Ajouter une source EPG",
"EPG_URL_ERROR": "La valeur n'est pas une URL valide",
"VIDEO_PLAYER_DESCRIPTION": "Sélectionnez le lecteur vidéo par défaut",
"STREAM_FORMAT_DESCRIPTION": "Sélectionnez le format de flux par défaut (xtream)",
"LANGUAGE_DESCRIPTION": "Sélectionnez la langue de l'application",
"THEME_DESCRIPTION": "Sélectionnez le thème visuel de l'application",
"SHOW_CAPTIONS_DESCRIPTION": "Afficher ou masquer les sous-titres par défaut",
"VERSION_DESCRIPTION": "Version actuelle de l'application",
"EPG_NOTE": "Actuellement, l'EPG n'est disponible que dans la version Electron d'IPTVnator.",
"EPG_NOTE_URL_TEXT": "Vérifiez-le ici",
"IMPORT_EXPORT_DATA": "Importer/exporter des listes de lecture",
"IMPORT_EXPORT_DATA_DESCRIPTION": "Exportez ou importez des listes au format JSON utilisé dans l'application.",
"IMPORT_DATA": "Importer",
"EXPORT_DATA": "Exporter",
"REMOVE_ALL": "Delete all playlists and playlist data",
"REMOVE_ALL_BUTTON": "Delete all",
"REMOVE_ALL_DESCRIPTION": "Delete every M3U, Xtream, and Stalker playlist stored in the app.",
"REMOVE_DIALOG": {
"TITLE": "Delete all playlists?",
"MESSAGE": "Delete all {{count}} playlists from the app. This also removes stored playlist data on this device.",
"SUMMARY_TITLE": "Playlist sources",
"CONSEQUENCES_TITLE": "This also removes",
"CONSEQUENCE_FAVORITES": "Favorites saved for these playlists",
"CONSEQUENCE_RECENTLY_VIEWED": "Recently viewed history",
"CONSEQUENCE_PLAYBACK": "Saved playback positions",
"CONSEQUENCE_DOWNLOADS": "Download history entries linked to those playlists",
"CONSEQUENCE_XTREAM_CACHE": "Imported Xtream categories and locally cached content",
"BACKUP_HINT": "Use Export first if you want a restorable backup before deleting.",
"CONFIRM": "Delete everything"
},
"IMPORT_ERROR": "Erreur d'importation, veuillez essayer avec un autre fichier.",
"PLAYLISTS_REMOVED": "All playlists and playlist data were removed.",
"MPV_PLAYER_PATH_LABEL": "Chemin mpv",
"MPV_PLAYER_PATH_DESCRIPTION": "Définissez le chemin d'accès au lecteur mpv dans votre système. Il utilisera le chemin fourni vers un binaire mpv au lieu de celui trouvé dans $PATH.",
"MPV_PLAYER_PATH": "Chemin du lecteur mpv",
"VLC_PLAYER_PATH_LABEL": "Chemin VLC",
"VLC_PLAYER_PATH_DESCRIPTION": "Définissez le chemin d'accès au lecteur VLC dans votre système. Il utilisera le chemin fourni vers un binaire VLC au lieu du chemin par défaut.",
"VLC_PLAYER_PATH": "Chemin du lecteur VLC",
"REMOTE_CONTROL": "Télécommande",
"REMOTE_CONTROL_DESCRIPTION": "Activer la télécommande de l'application.",
"REMOTE_CONTROL_PORT": "Port de télécommande",
"REMOTE_CONTROL_PORT_DESCRIPTION": "Port utilisé pour la télécommande de l'application. Le port 8765 est utilisé par défaut.",
"REMOVE_ALL_IN_PROGRESS": "Deleting playlist data…",
"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.",
"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é",
"LIGHT_THEME": "Thème clair",
"SYSTEM_THEME": "Thème du système"
},
"CHANNELS": {
"SEARCH_CHANNEL": "Rechercher une chaîne",
"UPLOAD_OR_SELECT_OTHER_PLAYLIST": "Transférer ou choisir une autre liste de lecture",
"ALL_CHANNELS": "Toutes les chaînes",
"GROUPS": "Groupes",
"UNGROUPED": "Non-groupé",
"UNNAMED_CHANNEL": "Chaîne sans nom",
"FAVORITES": "Favoris",
"NO_FAVORITES": "Aucun favoris",
"USE_STAR_TO_FAVORITE": "Veuillez utiliser l'icône 'étoile' pour ajouter une chaîne aux favoris.",
"REMOVE_FAVORITE": "Retirer des favoris",
"FAVORITES_UPDATED": "Les favoris ont été mis à jour !",
"SORT_BY": "Trier par",
"SORT_BY_DATE": "Trier par date d'ajout (Plus récent)",
"SORT_BY_RATING": "Trier par note",
"SORT_BY_NAME": "Trier par nom (A-Z)"
},
"TOP_MENU": {
"OPEN_CHANNELS_LIST": "Ouvrir la liste des chaînes",
"TOGGLE_FAVORITE_FLAG": "Basculer le statut de favoris",
"OPEN_EPG_LIST": "Ouvrir la liste EPG",
"OPEN_MULTI_EPG": "Ouvrir la vue Multi-EPG",
"SHOW_INFO": "Afficher les infos du programme (Appuyez sur I)"
},
"EPG": {
"TITLE": "Guide électronique des programmes",
"NEXT_DAY": "Jour suivant",
"PREVIOUS_DAY": "Jour précédent",
"LIVE_NOW": "En direct",
"LIVE_STREAM": "Diffusion en direct",
"TIMESHIFT_AVAILABLE": "Contrôle du direct disponible, cliquez pour lire",
"EPG_NOT_AVAILABLE_DATE": "L'EPG n'est pas disponible pour la date sélectionnée",
"EPG_NOT_AVAILABLE_CHANNEL_TITLE": "L'EPG n'est pas disponible pour cette chaîne.",
"EPG_NOT_AVAILABLE_CHANNEL_DESCRIPTION": "Veuillez ajouter/modifier l'URL de la liste EPG dans les réglages de l'application.",
"FETCH_EPG": "Récupération des données EPG...",
"ERROR": "L'EPG n'a pas pu être chargé.",
"DOWNLOAD_SUCCESS": "L'EPG a été téléchargé avec succès.",
"PROGRAM_DIALOG": {
"PROGRAM_DETAILS": "Détails du programme TV",
"TITLE": "Titre",
"CATEGORY": "Catégorie",
"PARENTAL_RATING_SYSTEM": "Système de classification du contenu télévisé",
"DESCRIPTION": "Description",
"LANGUAGE": "Langue",
"SHOW_PROGRAM_DETAILS": "Afficher les détails de ce programme"
},
"FETCH_SUCCESS": "L'EPG a été récupéré avec succès"
},
"LANGUAGES": {
"ARABIC": "العربية",
"MOROCCAN_ARABIC": "العربية (اللهجة المغربية)",
"ENGLISH": "English",
"KOREAN": "한국어",
"RUSSIAN": "Русский",
"GERMAN": "Deutsch",
"SPANISH": "Español",
"CHINESE": "简体中文",
"TRADITIONAL_CHINESE": "繁體中文",
"FRENCH": "Français",
"ITALIAN": "Italiano",
"TURKISH": "Türkçe",
"JAPANESE": "日本語",
"DUTCH": "Nederlands",
"BELARUSIAN": "Беларуская",
"POLISH": "Polski",
"PORTUGUESE": "Português",
"GREEK": "Ελληνικά"
},
"YES": "Oui",
"NO": "Non",
"MENU": {
"OPEN": "Ouvrir le menu",
"SUPPORT_ARIA": "Soutenir IPTVnator sur GitHub",
"SETTINGS": "Paramètres",
"SETTINGS_ARIA": "Ouvrir les paramètres",
"BUG_REPORT": "Signaler un bug",
"WHAT_IS_NEW": "Nouveautés",
"ABOUT": "À propos",
"ABOUT_ARIA": "À propos de l'application",
"SUPPORT_PROJECT": "Soutenir le projet"
},
"ABOUT": {
"TITLE": "À propos d'IPTVnator",
"DESCRIPTION": "Application lecteur IPTV multiplateforme avec de nombreuses fonctionnalités, comme la prise en charge des listes m3u et m3u8, les favoris, le guide TV, les archives TV/rattrapage et plus encore.",
"VERSION": "Version",
"GITHUB_TOOLTIP": "Dépôt IPTVnator sur GitHub",
"BUY_ME_A_COFFEE_TOOLTIP": "Offrez-moi un café",
"TWITTER_TOOLTIP": "Partager sur Twitter"
},
"UPDATE_AVAILABLE": "Mise à jour disponible",
"REFRESH": "Actualiser",
"XTREAM": {
"PLAY": "Lire",
"NAME": "Nom",
"RELEASE_DATE": "Date de sortie",
"GENRE": "Genre",
"COUNTRY": "Pays",
"ACTORS": "Acteurs",
"DIRECTOR": "Réalisateur",
"DURATION": "Durée",
"CAST": "Distribution",
"EPISODE_RUN_TIME": "Durée de l'épisode",
"RATING": "Note",
"IMDB_RATING": "Note IMDB",
"KINOPOISK_RATING": "Note Kinopoisk",
"DESCRIPTION": "Description",
"YEAR": "Année",
"AGE": "Âge",
"YOUTUBE_TRAILER": "Bande-annonce YouTube",
"EPISODE": "Épisode"
},
"PORTALS": {
"ALL_CATEGORIES": "Toutes les catégories",
"MY_FAVORITES": "Mes favoris",
"ADD_TO_FAVORITES": "Ajouter aux favoris",
"REMOVE_FROM_FAVORITES": "Retirer des favoris",
"REMOVED_FROM_FAVORITES": "Retiré des favoris",
"ADDED_TO_FAVORITES": "Ajouté aux favoris",
"SIDEBAR": {
"MAIN": "Principal",
"MOVIES": "Films",
"LIVE_TV": "TV en direct",
"SERIES": "Séries",
"LIBRARY": "Bibliothèque",
"SEARCH": "Rechercher",
"RECENT": "Récent",
"FAVORITES": "Favoris",
"HOME": "Accueil",
"PLAYLIST_INFO": "Infos de la liste",
"ACCOUNT_INFO": "Infos du compte"
},
"ERROR_VIEW": {
"ACCOUNT_EXPIRED": {
"TITLE": "Compte expiré",
"DESCRIPTION": "Ce compte a expiré. Veuillez vérifier les identifiants dans les paramètres de la liste ou la supprimer."
},
"UNAUTHORIZED": {
"TITLE": "Non autorisé",
"DESCRIPTION": "Veuillez vérifier les identifiants dans les paramètres de la liste ou la supprimer."
},
"NOT_FOUND": {
"TITLE": "Portail non trouvé",
"DESCRIPTION": "Veuillez vérifier les identifiants et l'URL du portail dans les paramètres de la liste ou la supprimer."
},
"EMPTY_CATEGORY": {
"TITLE": "Catégorie vide",
"DESCRIPTION": "Cette catégorie n'a pas de contenu, veuillez sélectionner une autre catégorie ou modifier le type de contenu"
},
"UNKNOWN_ERROR": {
"TITLE": "Une erreur s'est produite",
"DESCRIPTION": "Erreur inconnue, veuillez réessayer plus tard"
},
"NO_CATEGORY_SELECTED": {
"TITLE": "Aucune catégorie sélectionnée",
"DESCRIPTION": "Veuillez sélectionner une catégorie pour voir le contenu"
},
"PLAYLIST_SETTINGS": "Paramètres de la liste",
"HOME": "Accueil",
"DELETE": "Supprimer"
},
"EMPTY_LIST_VIEW": {
"TITLE": "Aucun résultat trouvé",
"NO_SEARCH_RESULTS": "Rien trouvé, essayez de modifier votre recherche"
},
"STREAM_URL_COPIED": "URL du flux copiée dans le presse-papiers",
"COPY_STREAM_URL": "Copier l'URL du flux",
"SELECT_CATEGORY": "Sélectionner une catégorie",
"SEARCH_VIEW": {
"RESULTS_FOUND": "{{count}} résultats trouvés",
"NO_RESULTS_FOR": "Aucun résultat trouvé pour \"{{term}}\""
}
},
"INFORMATION": "Information",
"DOWNLOADS": {
"TITLE": "Téléchargements",
"DOWNLOAD": "Télécharger",
"PLAY_LOCAL": "Lire local",
"EMPTY": "Aucun téléchargement",
"EMPTY_HINT": "Téléchargez des films et épisodes pour les regarder hors ligne",
"NOT_AVAILABLE": "Téléchargements non disponibles",
"DESKTOP_ONLY": "Cette fonctionnalité n'est disponible que dans l'application de bureau",
"NO_FOLDER": "Aucun dossier de téléchargement sélectionné",
"CHANGE_FOLDER": "Changer de dossier",
"CLEAR_COMPLETED": "Effacer terminés",
"CANCEL": "Annuler",
"RETRY": "Réessayer",
"REMOVE": "Supprimer",
"PLAY": "Lire",
"REVEAL": "Afficher dans le dossier",
"STATUS": {
"QUEUED": "En attente",
"DOWNLOADING": "En cours",
"COMPLETED": "Terminé",
"FAILED": "Échec",
"CANCELED": "Annulé"
},
"NO_PLAYLISTS_TITLE": "Add a playlist to start downloading",
"NO_PLAYLISTS_BODY": "Once you add a playlist, you can save movies and episodes here for offline playback.",
"NO_ITEMS_BODY": "Use the download button on any movie or episode to save it for offline playback.",
"NO_FILTER_MATCH": "No downloads match the current filter",
"NO_FILTER_MATCH_HINT": "Try a different search term"
},
"REMOTE_CONTROL": {
"TITLE": "Télécommande",
"UP_CHANNEL": "Chaîne précédente",
"DOWN_CHANNEL": "Chaîne suivante",
"HEADER": "Télécommande IPTVNator",
"FOOTER": "Télécommande IPTVNator"
},
"WORKSPACE": {
"SHELL": {
"GO_TO_DASHBOARD": "Back to dashboard",
"GO_TO_SOURCES": "Go to Sources",
"DROP_OVERLAY_TITLE": "Drop to add playlist",
"DROP_OVERLAY_BODY": "Release an .m3u or .m3u8 file anywhere in the workspace to import it.",
"DROP_OVERLAY_REJECTED_BODY": "Please drop an .m3u or .m3u8 file. Press Esc to dismiss.",
"DROP_OVERLAY_REJECTED_UNSUPPORTED": "Unsupported file type",
"DROP_OVERLAY_REJECTED_EMPTY": "That file is empty",
"DROP_OVERLAY_REJECTED_READ_ERROR": "Could not read that file",
"DROP_IMPORT_SUCCESS": "Importing \"{{title}}\"…",
"COMMANDS": {
"ADD_PLAYLIST_M3U_LABEL": "Add M3U playlist",
"ADD_PLAYLIST_M3U_DESCRIPTION": "Open add dialog on the M3U file or URL tab",
"ADD_PLAYLIST_XTREAM_LABEL": "Add Xtream Codes playlist",
"ADD_PLAYLIST_XTREAM_DESCRIPTION": "Open add dialog on the Xtream Codes tab",
"ADD_PLAYLIST_STALKER_LABEL": "Add Stalker portal",
"ADD_PLAYLIST_STALKER_DESCRIPTION": "Open add dialog on the Stalker Portal tab"
},
"EXTERNAL_PLAYBACK_CLOSE": "Close player"
},
"GLOBAL_FAVORITES": {
"NO_PLAYLISTS_TITLE": "No favorites to show",
"NO_PLAYLISTS_BODY": "Add a playlist to start collecting favorites from live channels, movies, and series.",
"NO_ITEMS_TITLE": "No favorites yet",
"NO_ITEMS_BODY": "Tap the star icon on any channel, movie, or series to save it here."
},
"GLOBAL_RECENT": {
"NO_PLAYLISTS_TITLE": "Nothing watched yet",
"NO_PLAYLISTS_BODY": "Add a playlist and your watching history will appear here.",
"NO_ITEMS_TITLE": "Nothing watched yet",
"NO_ITEMS_BODY": "Start watching anything from your library and it will show up here."
}
}
}
+462
View File
@@ -0,0 +1,462 @@
{
"CLOSE": "Chiudi",
"PLAYLISTS": "Playlist",
"HOME": {
"TITLE": "IPTVnator",
"SUBTITLE": "Seleziona una playlist dall'elenco o aggiungi una nuova playlist tramite caricamento del file o tramite URL",
"TABS": {
"RECENTLY_ADDED": "Playlist aggiunte di recente",
"FILE_UPLOAD": "Aggiungi tramite caricamento file",
"URL_UPLOAD": "Aggiungi tramite URL",
"TEXT_IMPORT": "Importa come testo",
"XTREME_IMPORT": "Aggiungi codice Xtreme",
"STALKER_PORTAL_IMPORT": "Aggiungi portale Stalker"
},
"PLAYLISTS": {
"NO_PLAYLISTS": "Nessuna playlist è stata aggiunta",
"ADD_FIRST": "Aggiungi la tua prima playlist dall'altra scheda",
"ADDED_VIA_URL": "Aggiunto tramite caricamento URL. URL:",
"ADDED_VIA_FILE": "Aggiunto tramite caricamento file",
"XTREAM_PLAYLIST": "Playlist Xtream",
"STALKER_PORTAL": "Portale Stalker",
"CHANNELS": "Canali",
"ADDED": "Aggiunto",
"SHOW_DETAILS": "Visualizza i dettagli della playlist",
"REMOVE": "Rimuovi playlist",
"SEARCH_PLAYLISTS": "Cerca playlist per titolo",
"INFO_DIALOG": {
"PLAYLIST_DETAILS": "Dettagli playlist",
"TITLE": "Titolo",
"FROM_URL": "Aggiunto dall'URL",
"IMPORT_DATE": "Data importazione",
"CHANNELS": "Numero di canali",
"CLOSE": "Chiudi",
"SAVE": "Salva",
"USER_AGENT": "User agent",
"ORIGINAL_FILENAME": "Nome file originale",
"FILE_PATH": "Percorso file",
"UPDATE_FAILED": "L'ultimo aggiornamento della playlist non è riuscito",
"AUTO_UPDATE": "Aggiornamento automatico",
"AUTO_UPDATE_DESCRIPTION": "Se la funzione di aggiornamento automatico è attivata, la playlist verrà aggiornata automaticamente ad ogni avvio dell'app.",
"CUSTOM_USER_AGENT": "Alcuni fornitori IPTV per riprodurre la loro playlist necessitano di uno user agent specifico.",
"EXPORT_PLAYLIST": "Esporta playlist come file m3u",
"SERVER_URL": "URL server",
"USERNAME": "Utente",
"PASSWORD": "Password",
"MAC_ADDRESS": "Indirizzo MAC"
},
"REMOVE_DIALOG": {
"TITLE": "Rimuovi playlist",
"MESSAGE": "Sei sicuro di voler eliminare completamente questa playlist?"
},
"UPDATED": "Aggiornata",
"REFRESH": "Aggiorna playlist",
"GLOBAL_FAVORITES": "Preferiti globali",
"GLOBAL_FAVORITES_DESCRIPTION": "Playlist generata automaticamente con preferiti aggregati da tutte le playlist",
"MY_PLAYLISTS": "Le mie playlist",
"MY_PLAYLISTS_SUBTITLE": "tutte le playlist disponibili",
"PLAYLIST_UPDATE_SUCCESS": "La playlist è stata correttamente aggiornata.",
"FEATURE_M3U_LABEL": "Add an M3U file or URL",
"FEATURE_XTREAM_LABEL": "Connect via Xtream Codes",
"FEATURE_STALKER_LABEL": "Connect to a Stalker portal",
"VALUE_PROPS_LABEL": "What you can do",
"VALUE_PROP_LIVE": "Live TV with EPG",
"VALUE_PROP_VOD": "Movies & Series",
"VALUE_PROP_MULTISOURCE": "Multi-source library",
"VALUE_PROP_OFFLINE": "Offline downloads",
"DASHBOARD_WELCOME_TAGLINE": "Your IPTV library, in one place.",
"FEATURE_LIVE_TITLE": "Live TV",
"FEATURE_LIVE_DESC": "Stream live channels with full schedule.",
"FEATURE_VOD_TITLE": "Movies & Series",
"FEATURE_VOD_DESC": "On-demand library with covers and details.",
"FEATURE_EPG_TITLE": "EPG & Catch-up",
"FEATURE_EPG_DESC": "Program guide and time-shifted playback.",
"FEATURE_OFFLINE_TITLE": "Offline downloads",
"FEATURE_OFFLINE_DESC": "Save movies and episodes for later.",
"SOURCES_WELCOME_TITLE": "Add your first playlist",
"SOURCES_WELCOME_BODY": "Pick a source type below to get started.",
"SOURCE_M3U_NEEDS": "Local file or URL pointing to an M3U/M3U8 playlist.",
"SOURCE_M3U_ADD": "Add M3U",
"SOURCE_XTREAM_NEEDS": "Username, password and server URL from your provider.",
"SOURCE_XTREAM_ADD": "Add Xtream",
"SOURCE_STALKER_NEEDS": "Portal URL and MAC address (Ministra-compatible).",
"SOURCE_STALKER_ADD": "Add Stalker",
"CONTENT_LIVE": "Live",
"CONTENT_VOD": "Movies",
"CONTENT_SERIES": "Series",
"CONTENT_EPG": "EPG",
"DASHBOARD_WELCOME_DESCRIPTION": "Connect M3U files, Xtream Codes, or Stalker portals — then enjoy live TV, movies and series on every screen."
},
"FILE_UPLOAD": {
"DRAG_DROP": "Trascina e rilascia qui i file",
"OR": "o",
"CHOOSE_PLAYLIST": "scegli una playlist",
"REJECTED": "Il file è stato rifiutato, formato di file non supportato {{filename}}."
},
"URL_UPLOAD": {
"PLAYLIST_URL": "URL playlist (m3u, m3u8)",
"ADD_PLAYLIST": "Aggiungi playlist",
"CORS_NOTE": "Nota: per evitare problemi CORS a questo punto, l'applicazione usa un servizio proxy CORS pubblico. Se vuoi caricare una playlist con dati sensibili, è meglio importarla come file nella scheda adiacente."
},
"TEXT_IMPORT": {
"LABEL": "Inserisci playlist m3u(8) come testo",
"BUTTON_LABEL": "Importa"
},
"XTREAM_PLAYLIST": {
"TITLE": "Titolo playlist",
"SERVER_URL": "URL server",
"USERNAME": "Utente",
"PASSWORD": "Password",
"ADD": "Aggiungi",
"TEST_CREDENTIALS": "Testa credenziali",
"URL_VALIDATION_ERROR": "Dovrebbe essere una URL valida con protocollo (es. http://esempio.it o https://esempio.it:4324)"
},
"STALKER_PORTAL": {
"TITLE": "Titolo",
"MAC_ADDRESS": "Indirizzo MAC",
"SERVER_URL": "URL server",
"URL_VALIDATION_ERROR": "Dovrebbe essere una URL valida con protocollo (es. http://esempio.it/c o https://esempio.it/stalker_portal/c)",
"ADD": "Aggiungi"
},
"FILTER_BY_NAME": "Filtra per nome",
"FILTER_BY_TYPE": "Filtra per tipo",
"SORT_PLAYLISTS": "Ordina playlist",
"SORT_BY": "Ordina per",
"SORT_OPTIONS": {
"NAME_ASC": "Nome (A-Z)",
"NAME_DESC": "Nome (Z-A)",
"NEWEST": "Data aggiunta (prima più recenti)",
"OLDEST": "Data aggiunta (prima più vecchi)"
},
"IMPORTED_AS_TEXT": "Importato come testo",
"PARSING_ERROR": "Errore: analisi fallita, non è una playlist valida:"
},
"SETTINGS": {
"TITLE": "Impostazioni IPTVnator",
"GENERAL": "Generale",
"GENERAL_SUBTITLE": "Modifica le impostazioni generali dell'applicazione",
"PLAYBACK": "Riproduzione",
"EPG_SOURCES": "Sorgenti EPG",
"EPG_SOURCES_DESCRIPTION": "Aggiungi uno o piu URL come sorgenti EPG",
"DATA": "Dati",
"ABOUT": "Info",
"NAV_GENERAL": "Generale",
"NAV_PLAYBACK": "Riproduzione",
"NAV_EPG": "EPG",
"NAV_REMOTE": "Remote",
"NAV_DATA": "Dati",
"NAV_ABOUT": "Info",
"APP_PREFERENCES": "Preferenze app",
"HERO_EYEBROW": "Impostazioni area di lavoro",
"HERO_TITLE": "Modella IPTVnator come preferisci",
"HERO_DESCRIPTION": "Regola riproduzione, guida TV, accesso remoto e gestione dati da un unico posto senza perdere lo stile attuale dell'area di lavoro.",
"SUBTITLE": "Modifica la configurazione dell'applicazione",
"DESCRIPTION": "Configura le opzioni nell'elenco sottostante e conferma con 'Salva modifiche'",
"EPG_URL_LABEL": "URL EPG (*.xml o *.xml.gz)",
"EPG_URL_PLACEHOLDER": "Inserisci una URL",
"REFRESH_EPG": "Aggiorna EPG",
"REFRESH_ALL_EPG": "Aggiorna tutto",
"REMOVE_EPG_SOURCE": "Rimuovi sorgente EPG",
"EPG_STATUS_FRESH": "Aggiornato",
"EPG_STATUS_STALE": "Da aggiornare",
"EPG_STATUS_ERROR": "Errore",
"VIDEO_PLAYER_LABEL": "Riproduttore video",
"PLAYER_HTML5": "Lettore HTML5",
"PLAYER_VIDEOJS": "Lettore Video.js",
"PLAYER_ARTPLAYER": "ArtPlayer",
"PLAYER_MPV": "Lettore MPV",
"PLAYER_VLC": "VLC",
"VIDEO_PLAYER_PLACEHOLDER": "Seleziona una opzione",
"VERSION": "Versione",
"SAVE_CHANGES": "Salva modifiche",
"BACK_TO_HOME": "Indietro",
"NEW_VERSION_AVAILABLE": "È disponibile una nuova versione",
"LATEST_VERSION": "Questa versione è aggiornata",
"STREAM_FORMAT": "Formato streaming",
"LANGUAGE": "Lingua",
"SETTINGS_SAVED": "La configurazione è stata salvata.",
"THEME": "Tema visuale",
"SHOW_CAPTIONS": "Visualizza sottotitoli",
"ADD_EPG_SOURCE": "Aggiungi sorgente EPG",
"CLEAR_EPG_DATA": "Cancella dati EPG",
"CLEAR_EPG_DIALOG": {
"TITLE": "Cancella dati EPG",
"MESSAGE": "Vuoi davvero rimuovere tutti i dati EPG dal database? Questo eliminerà tutte le programmazioni memorizzate nella cache."
},
"EPG_DATA_CLEARED": "I dati EPG sono stati cancellati",
"EPG_DATA_CLEAR_FAILED": "Impossibile cancellare i dati EPG. Riprova.",
"CLEARING_EPG_DATA": "Cancellazione…",
"EPG_URL_ERROR": "Il valore non è una URL valida",
"VIDEO_PLAYER_DESCRIPTION": "Seleziona lettore video predefinito",
"STREAM_FORMAT_DESCRIPTION": "Seleziona il formato di streaming predefinito (xtream)",
"LANGUAGE_DESCRIPTION": "Seleziona la lingua dell'applicazione",
"THEME_DESCRIPTION": "Seleziona il tema visivo dell'applicazione",
"SHOW_CAPTIONS_DESCRIPTION": "Visualizza/nascondi i sottotitoli per impostazione predefinita",
"VERSION_DESCRIPTION": "Versione attuale dell'applicazione",
"EPG_NOTE": "Attualmente EPG è disponibile solo nella versione dell'applicazione electron.",
"EPG_NOTE_URL_TEXT": "Maggiori info qui",
"IMPORT_EXPORT_DATA": "Importa/esporta playlist",
"IMPORT_EXPORT_DATA_DESCRIPTION": "Esporta/importa playlist nel formato JSON usato all'interno dell'applicazione.",
"IMPORT_DATA": "Importa",
"EXPORT_DATA": "Esporta",
"REMOVE_ALL": "Delete all playlists and playlist data",
"REMOVE_ALL_BUTTON": "Delete all",
"REMOVE_ALL_DESCRIPTION": "Delete every M3U, Xtream, and Stalker playlist stored in the app.",
"REMOVE_DIALOG": {
"TITLE": "Delete all playlists?",
"MESSAGE": "Delete all {{count}} playlists from the app. This also removes stored playlist data on this device.",
"SUMMARY_TITLE": "Playlist sources",
"CONSEQUENCES_TITLE": "This also removes",
"CONSEQUENCE_FAVORITES": "Favorites saved for these playlists",
"CONSEQUENCE_RECENTLY_VIEWED": "Recently viewed history",
"CONSEQUENCE_PLAYBACK": "Saved playback positions",
"CONSEQUENCE_DOWNLOADS": "Download history entries linked to those playlists",
"CONSEQUENCE_XTREAM_CACHE": "Imported Xtream categories and locally cached content",
"BACKUP_HINT": "Use Export first if you want a restorable backup before deleting.",
"CONFIRM": "Delete everything"
},
"IMPORT_ERROR": "Errore di importazione, prova con un altro file.",
"PLAYLISTS_REMOVED": "All playlists and playlist data were removed.",
"MPV_PLAYER_PATH_LABEL": "percorso mpv",
"MPV_PLAYER_PATH_DESCRIPTION": "Imposta il percorso per il lettore mpv in questo tuo sistema. Verrà usato il percorso fornito per un eseguibile mpv invece di usare quello trovato in $PATH.",
"MPV_PLAYER_PATH": "percorso riproduttore mpv",
"MPV_REUSE_INSTANCE_LABEL": "Riutilizza istanza MPV",
"MPV_REUSE_INSTANCE_DESCRIPTION": "Quando attivo, la stessa finestra MPV viene riutilizzata per riprodurre stream diversi. Quando disattivo, ogni stream viene aperto in una nuova finestra MPV.",
"VLC_PLAYER_PATH_LABEL": "Percorso VLC",
"VLC_PLAYER_PATH_DESCRIPTION": "Imposta il percorso del lettore VLC nel sistema. Verrà usato il percorso fornito per il file exe VLC invece del percorso predefinito per il sistema.",
"VLC_PLAYER_PATH": "Percorso lettore VLC",
"REMOTE_CONTROL": "Telecomando",
"REMOTE_CONTROL_DESCRIPTION": "Abilita controllo remoto nell'applicazione.",
"REMOTE_CONTROL_PORT": "Porta controllo remoto",
"REMOTE_CONTROL_PORT_DESCRIPTION": "Porta usata per il controllo remoto dell'applicazione. Per impostazione predefinita viene usata la porta 8765.",
"REMOTE_CONTROL_URL": "URL telecomando",
"REMOTE_CONTROL_URL_DESCRIPTION": "Accedi al telecomando da un altro dispositivo sulla stessa rete.",
"SHOW_QR_CODE": "Mostra codice QR",
"STATUS_ENABLED": "Attivo",
"STATUS_DISABLED": "Disattivo",
"SOURCE_SINGULAR": "sorgente",
"SOURCE_PLURAL": "sorgenti",
"PORT_RANGE_LABEL": "Porta (1-65535)",
"PORT_REQUIRED": "La porta è obbligatoria",
"PORT_MIN": "La porta deve essere almeno 1",
"PORT_MAX": "La porta deve essere al massimo 65535",
"PORT_PATTERN": "Sono consentite solo cifre",
"REMOVE_ALL_IN_PROGRESS": "Deleting playlist data…",
"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.",
"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",
"LIGHT_THEME": "Tema chiaro",
"SYSTEM_THEME": "Tema di sistema"
},
"CHANNELS": {
"SEARCH_CHANNEL": "Cerca canale",
"UPLOAD_OR_SELECT_OTHER_PLAYLIST": "Carica o seleziona un'altra playlist",
"ALL_CHANNELS": "Tutti i canali",
"GROUPS": "Gruppi",
"UNGROUPED": "Non raggruppati",
"UNNAMED_CHANNEL": "Canale senza nome",
"FAVORITES": "Preferiti",
"NO_FAVORITES": "Ancora nessun preferito",
"USE_STAR_TO_FAVORITE": "Usa l'icona 'stella' per aggiungere canali ai preferiti.",
"REMOVE_FAVORITE": "Rimuovi dai preferiti",
"FAVORITES_UPDATED": "Aggiornamento preferiti completato!",
"SORT_BY": "Ordina per",
"SORT_BY_DATE": "Data inserimento (prima più recenti)",
"SORT_BY_RATING": "Valutazione",
"SORT_BY_NAME": "Nome (A-Z)"
},
"TOP_MENU": {
"OPEN_CHANNELS_LIST": "Apri elenco canali",
"TOGGLE_FAVORITE_FLAG": "Attiva/disattiva flag preferiti",
"OPEN_EPG_LIST": "Apri elenco EPG",
"OPEN_MULTI_EPG": "Apri vista Multi-EPG"
},
"EPG": {
"TITLE": "Guida elettronica programmi",
"NEXT_DAY": "Giorno successivo",
"PREVIOUS_DAY": "Giorno precedente",
"LIVE_NOW": "Live attuale",
"LIVE_STREAM": "Stream live",
"TIMESHIFT_AVAILABLE": "Disponibile il timeshift, fai clic per riprodurre",
"EPG_NOT_AVAILABLE_DATE": "Non è disponibile l'EPG per la data selezionata",
"EPG_NOT_AVAILABLE_CHANNEL_TITLE": "Non è disponibile l'EPG per questo canale.",
"EPG_NOT_AVAILABLE_CHANNEL_DESCRIPTION": "Aggiungi/modifica l'URL dell'elenco EPG nelle impostazioni dell'app.",
"FETCH_EPG": "Recupero dati EPG...",
"ERROR": "Non è stato possibile caricare l'EPG.",
"DOWNLOAD_SUCCESS": "L'EPG è stato correttamente scaricato.",
"PROGRAM_DIALOG": {
"PROGRAM_DETAILS": "Dettagli sul programma TV",
"TITLE": "Titolo",
"CATEGORY": "Categoria",
"PARENTAL_RATING_SYSTEM": "Sistema classificazione contenuti TV",
"DESCRIPTION": "Descrizione",
"LANGUAGE": "Lingua",
"SHOW_PROGRAM_DETAILS": "Visualizza dettagli su questo programma"
},
"FETCH_SUCCESS": "EPG scaricato correttamente"
},
"LANGUAGES": {
"ARABIC": "العربية",
"MOROCCAN_ARABIC": "العربية (اللهجة المغربية)",
"ENGLISH": "English",
"KOREAN": "한국어",
"RUSSIAN": "Русский",
"GERMAN": "Deutsch",
"SPANISH": "Español",
"CHINESE": "简体中文",
"TRADITIONAL_CHINESE": "繁體中文",
"FRENCH": "Français",
"ITALIAN": "Italiano",
"TURKISH": "Türkçe",
"JAPANESE": "日本語",
"DUTCH": "Nederlands",
"BELARUSIAN": "Беларуская",
"POLISH": "Polski",
"PORTUGUESE": "Português",
"GREEK": "Ελληνικά"
},
"YES": "Sì",
"NO": "No",
"MENU": {
"OPEN": "Apri menu",
"SUPPORT_ARIA": "Supporta IPTVnator su GitHub",
"SETTINGS": "Impostazioni",
"SETTINGS_ARIA": "Apri impostazioni",
"BUG_REPORT": "Segnala un bug",
"WHAT_IS_NEW": "Novità del programma",
"ABOUT": "Info sul programma",
"ABOUT_ARIA": "Info sull'applicazione",
"SUPPORT_PROJECT": "Supporta il progetto"
},
"ABOUT": {
"TITLE": "Info su IPTVnator",
"DESCRIPTION": "Applicazione per la riproduzione IPTV multi piattaforma con molteplici funzionalità, come il supporto di playlist m3u e m3u8, preferiti, guida TV, archivio TV/catchup e altro ancora.",
"VERSION": "Versione",
"GITHUB_TOOLTIP": "Repository ITPVnator su GitHub",
"BUY_ME_A_COFFEE_TOOLTIP": "Offrimi un caffè",
"TWITTER_TOOLTIP": "Condividi su Twitter"
},
"UPDATE_AVAILABLE": "Disponibile aggiornamento",
"REFRESH": "Aggiorna",
"XTREAM": {
"PLAY": "Riproduci",
"NAME": "Nome",
"RELEASE_DATE": "Data rilascio",
"GENRE": "Genere",
"COUNTRY": "Nazione",
"ACTORS": "Attori",
"DIRECTOR": "Regista",
"DURATION": "Durata",
"CAST": "Cast",
"EPISODE_RUN_TIME": "Tempo esecuzione episodio",
"RATING": "Classifica",
"IMDB_RATING": "Classifica IMDB",
"KINOPOISK_RATING": "Classifica Kinopoisk",
"DESCRIPTION": "Descrizione",
"YEAR": "Anno",
"AGE": "Età",
"YOUTUBE_TRAILER": "Trailer YouTube",
"EPISODE": "Episodio"
},
"PORTALS": {
"ALL_CATEGORIES": "Tutte le categorie",
"MY_FAVORITES": "Preferiti",
"ADD_TO_FAVORITES": "Aggiungi ai preferiti",
"REMOVE_FROM_FAVORITES": "Rimuovi dai preferiti",
"REMOVED_FROM_FAVORITES": "Rimosso dai preferiti",
"ADDED_TO_FAVORITES": "Aggiunto ai preferiti",
"ERROR_VIEW": {
"ACCOUNT_EXPIRED": {
"TITLE": "Account scaduto",
"DESCRIPTION": "Questo account è scaduto. Controlla le credenziali nelle impostazioni della playlist o rimuovile."
},
"UNAUTHORIZED": {
"TITLE": "Non autorizzato",
"DESCRIPTION": "Controlla le credenziali nelle impostazioni della playlist o rimuovile."
},
"NOT_FOUND": {
"TITLE": "Portale non trovato",
"DESCRIPTION": "Controlla le credenziali e l'URL del portale nelle impostazioni della playlist o rimuovile."
},
"EMPTY_CATEGORY": {
"TITLE": "Categoria vuota",
"DESCRIPTION": "Questa categoria non ha contenuti, seleziona un'altra categoria o modifica il tipo di contenuto"
},
"UNKNOWN_ERROR": {
"TITLE": "Qualcosa è andato storto",
"DESCRIPTION": "Errore sconosciuto, riprova più tardi"
},
"PLAYLIST_SETTINGS": "Impostazioni Playlist",
"HOME": "Home",
"DELETE": "Elimina"
},
"EMPTY_LIST_VIEW": {
"NO_SEARCH_RESULTS": "Nessun risultato, prova a modificare la richiesta di ricerca"
},
"STREAM_URL_COPIED": "URL streaming copiato negli appunti",
"COPY_STREAM_URL": "Copia URL streaming",
"SEARCH_VIEW": {
"RESULTS_FOUND": "Trovati {{count}} risultati",
"NO_RESULTS_FOR": "Nessun risultato trovato per \"{{term}}\""
}
},
"INFORMATION": "Informazioni",
"REMOTE_CONTROL": {
"TITLE": "Controllo remoto",
"UP_CHANNEL": "Canale +",
"DOWN_CHANNEL": "Canale -",
"HEADER": "Controllo remoto IPTVNator",
"FOOTER": "Controllo remoto IPTVNator"
},
"WORKSPACE": {
"SHELL": {
"GO_TO_DASHBOARD": "Back to dashboard",
"GO_TO_SOURCES": "Go to Sources",
"DROP_OVERLAY_TITLE": "Drop to add playlist",
"DROP_OVERLAY_BODY": "Release an .m3u or .m3u8 file anywhere in the workspace to import it.",
"DROP_OVERLAY_REJECTED_BODY": "Please drop an .m3u or .m3u8 file. Press Esc to dismiss.",
"DROP_OVERLAY_REJECTED_UNSUPPORTED": "Unsupported file type",
"DROP_OVERLAY_REJECTED_EMPTY": "That file is empty",
"DROP_OVERLAY_REJECTED_READ_ERROR": "Could not read that file",
"DROP_IMPORT_SUCCESS": "Importing \"{{title}}\"…",
"COMMANDS": {
"ADD_PLAYLIST_M3U_LABEL": "Add M3U playlist",
"ADD_PLAYLIST_M3U_DESCRIPTION": "Open add dialog on the M3U file or URL tab",
"ADD_PLAYLIST_XTREAM_LABEL": "Add Xtream Codes playlist",
"ADD_PLAYLIST_XTREAM_DESCRIPTION": "Open add dialog on the Xtream Codes tab",
"ADD_PLAYLIST_STALKER_LABEL": "Add Stalker portal",
"ADD_PLAYLIST_STALKER_DESCRIPTION": "Open add dialog on the Stalker Portal tab"
},
"EXTERNAL_PLAYBACK_CLOSE": "Close player"
},
"GLOBAL_FAVORITES": {
"NO_PLAYLISTS_TITLE": "No favorites to show",
"NO_PLAYLISTS_BODY": "Add a playlist to start collecting favorites from live channels, movies, and series.",
"NO_ITEMS_TITLE": "No favorites yet",
"NO_ITEMS_BODY": "Tap the star icon on any channel, movie, or series to save it here."
},
"GLOBAL_RECENT": {
"NO_PLAYLISTS_TITLE": "Nothing watched yet",
"NO_PLAYLISTS_BODY": "Add a playlist and your watching history will appear here.",
"NO_ITEMS_TITLE": "Nothing watched yet",
"NO_ITEMS_BODY": "Start watching anything from your library and it will show up here."
}
},
"DOWNLOADS": {
"NO_PLAYLISTS_TITLE": "Add a playlist to start downloading",
"NO_PLAYLISTS_BODY": "Once you add a playlist, you can save movies and episodes here for offline playback.",
"NO_ITEMS_BODY": "Use the download button on any movie or episode to save it for offline playback.",
"NO_FILTER_MATCH": "No downloads match the current filter",
"NO_FILTER_MATCH_HINT": "Try a different search term"
}
}
+408
View File
@@ -0,0 +1,408 @@
{
"CLOSE": "閉じる",
"PLAYLISTS": "プレイリスト",
"HOME": {
"TITLE": "IPTVnator",
"SUBTITLE": "リストからプレイリストを選択するか、新しいプレイリストを追加してください",
"TABS": {
"RECENTLY_ADDED": "最近追加したプレイリスト",
"FILE_UPLOAD": "ファイルアップロード",
"URL_UPLOAD": "URLから追加",
"TEXT_IMPORT": "テキストからインポート",
"XTREME_IMPORT": "Xtremeコードを追加",
"STALKER_PORTAL_IMPORT": "Stalkerポータルを追加"
},
"PLAYLISTS": {
"NO_PLAYLISTS": "プレイリストが追加されていません",
"ADD_FIRST": "最初のプレイリストを追加してください",
"ADDED_VIA_URL": "URLからアップロード。URL:",
"ADDED_VIA_FILE": "ファイルからアップロード",
"XTREAM_PLAYLIST": "Xtremeプレイリスト",
"STALKER_PORTAL": "Stalkerポータル",
"CHANNELS": "チャンネル",
"ADDED": "追加済み",
"SHOW_DETAILS": "プレイリストの詳細を表示",
"REMOVE": "プレイリストを削除",
"SEARCH_PLAYLISTS": "タイトルでプレイリストを検索",
"INFO_DIALOG": {
"PLAYLIST_DETAILS": "プレイリストの詳細",
"TITLE": "タイトル",
"FROM_URL": "URLから追加",
"IMPORT_DATE": "インポート日",
"CHANNELS": "チャンネル数",
"CLOSE": "閉じる",
"SAVE": "保存",
"USER_AGENT": "ユーザーエージェント",
"ORIGINAL_FILENAME": "元のファイル名",
"FILE_PATH": "ファイルパス",
"UPDATE_FAILED": "最後のプレイリスト更新に失敗しました",
"AUTO_UPDATE": "自動更新",
"AUTO_UPDATE_DESCRIPTION": "自動更新機能が有効な場合、アプリ起動時にプレイリストが自動的に更新されます。",
"CUSTOM_USER_AGENT": "一部のIPTVプロバイダーでは、プレイリストを再生するために特定のユーザーエージェントが必要です。",
"EXPORT_PLAYLIST": "プレイリストをm3uとしてエクスポート",
"SERVER_URL": "サーバーURL",
"USERNAME": "ユーザー名",
"PASSWORD": "パスワード",
"MAC_ADDRESS": "MACアドレス"
},
"REMOVE_DIALOG": {
"TITLE": "プレイリストを削除",
"MESSAGE": "このプレイリストを完全に削除してもよろしいですか?"
},
"UPDATED": "更新済み",
"REFRESH": "プレイリストを更新",
"GLOBAL_FAVORITES": "グローバルお気に入り",
"GLOBAL_FAVORITES_DESCRIPTION": "全プレイリストのお気に入りを集約した自動生成プレイリスト",
"MY_PLAYLISTS": "マイプレイリスト",
"MY_PLAYLISTS_SUBTITLE": "利用可能な全プレイリスト",
"PLAYLIST_UPDATE_SUCCESS": "成功!プレイリストが正常に更新されました。",
"FEATURE_M3U_LABEL": "Add an M3U file or URL",
"FEATURE_XTREAM_LABEL": "Connect via Xtream Codes",
"FEATURE_STALKER_LABEL": "Connect to a Stalker portal",
"VALUE_PROPS_LABEL": "What you can do",
"VALUE_PROP_LIVE": "Live TV with EPG",
"VALUE_PROP_VOD": "Movies & Series",
"VALUE_PROP_MULTISOURCE": "Multi-source library",
"VALUE_PROP_OFFLINE": "Offline downloads",
"DASHBOARD_WELCOME_TAGLINE": "Your IPTV library, in one place.",
"FEATURE_LIVE_TITLE": "Live TV",
"FEATURE_LIVE_DESC": "Stream live channels with full schedule.",
"FEATURE_VOD_TITLE": "Movies & Series",
"FEATURE_VOD_DESC": "On-demand library with covers and details.",
"FEATURE_EPG_TITLE": "EPG & Catch-up",
"FEATURE_EPG_DESC": "Program guide and time-shifted playback.",
"FEATURE_OFFLINE_TITLE": "Offline downloads",
"FEATURE_OFFLINE_DESC": "Save movies and episodes for later.",
"SOURCES_WELCOME_TITLE": "Add your first playlist",
"SOURCES_WELCOME_BODY": "Pick a source type below to get started.",
"SOURCE_M3U_NEEDS": "Local file or URL pointing to an M3U/M3U8 playlist.",
"SOURCE_M3U_ADD": "Add M3U",
"SOURCE_XTREAM_NEEDS": "Username, password and server URL from your provider.",
"SOURCE_XTREAM_ADD": "Add Xtream",
"SOURCE_STALKER_NEEDS": "Portal URL and MAC address (Ministra-compatible).",
"SOURCE_STALKER_ADD": "Add Stalker",
"CONTENT_LIVE": "Live",
"CONTENT_VOD": "Movies",
"CONTENT_SERIES": "Series",
"CONTENT_EPG": "EPG",
"DASHBOARD_WELCOME_DESCRIPTION": "Connect M3U files, Xtream Codes, or Stalker portals — then enjoy live TV, movies and series on every screen."
},
"FILE_UPLOAD": {
"DRAG_DROP": "ここにファイルをドラッグ&ドロップ",
"OR": "または",
"CHOOSE_PLAYLIST": "プレイリストを選択",
"REJECTED": "ファイルが拒否されました。サポートされていないファイル形式です:{{filename}}"
},
"URL_UPLOAD": {
"PLAYLIST_URL": "プレイリストURL (m3u, m3u8)",
"ADD_PLAYLIST": "プレイリストを追加",
"CORS_NOTE": "注意:CORSの問題を回避するため、現時点ではパブリックCORSプロキシサービスを使用しています。機密データを含むプレイリストをアップロードする場合は、ファイルからインポートする方が安全です。"
},
"TEXT_IMPORT": {
"LABEL": "m3u(8)プレイリストをテキストとして挿入",
"BUTTON_LABEL": "インポート"
},
"XTREAM_PLAYLIST": {
"TITLE": "プレイリストタイトル",
"SERVER_URL": "サーバーURL",
"USERNAME": "ユーザー名",
"PASSWORD": "パスワード",
"ADD": "追加",
"TEST_CREDENTIALS": "認証情報をテスト",
"URL_VALIDATION_ERROR": "プロトコルを含む有効なURLである必要があります(例:http://example.com または https://example.com:4324)"
},
"STALKER_PORTAL": {
"TITLE": "タイトル",
"MAC_ADDRESS": "MACアドレス",
"SERVER_URL": "サーバーURL",
"URL_VALIDATION_ERROR": "プロトコルを含む有効なURLである必要があります(例:http://example.com/c または https://example.com/stalker_portal/c)",
"ADD": "追加"
},
"FILTER_BY_NAME": "名前でフィルター",
"FILTER_BY_TYPE": "種類でフィルター",
"IMPORTED_AS_TEXT": "テキストとしてインポート",
"PARSING_ERROR": "エラー:解析に失敗しました。有効なプレイリストではありません:"
},
"SETTINGS": {
"TITLE": "設定",
"SUBTITLE": "アプリケーションの設定を変更",
"DESCRIPTION": "以下のオプションを調整し、変更を保存ボタンで確定してください",
"EPG_URL_LABEL": "EPG URL (*.xml または *.xml.gz)",
"EPG_URL_PLACEHOLDER": "URLを入力",
"REFRESH_EPG": "EPGを更新",
"REFRESH_ALL_EPG": "すべて更新",
"REMOVE_EPG_SOURCE": "EPGソースを削除",
"EPG_STATUS_FRESH": "最新",
"EPG_STATUS_STALE": "更新が必要",
"EPG_STATUS_ERROR": "失敗",
"VIDEO_PLAYER_LABEL": "ビデオプレーヤー",
"VIDEO_PLAYER_PLACEHOLDER": "オプションを選択",
"VERSION": "バージョン",
"SAVE_CHANGES": "変更を保存",
"BACK_TO_HOME": "戻る",
"NEW_VERSION_AVAILABLE": "新しいバージョンが利用可能です",
"LATEST_VERSION": "最新バージョンを使用中です",
"LANGUAGE": "言語",
"SETTINGS_SAVED": "成功!設定が保存されました。",
"THEME": "視覚テーマ",
"SHOW_CAPTIONS": "字幕を表示",
"ADD_EPG_SOURCE": "EPGソースを追加",
"EPG_URL_ERROR": "有効なURLではありません",
"VIDEO_PLAYER_DESCRIPTION": "デフォルトのビデオプレーヤーを選択",
"LANGUAGE_DESCRIPTION": "アプリケーションの言語を選択",
"THEME_DESCRIPTION": "アプリケーションの視覚テーマを選択",
"SHOW_CAPTIONS_DESCRIPTION": "デフォルトで字幕を表示/非表示",
"VERSION_DESCRIPTION": "アプリケーションの現在のバージョン",
"EPG_NOTE": "現在、EPGはIPTVnatorのelectronベース版でのみ利用可能です。",
"EPG_NOTE_URL_TEXT": "こちらをチェック",
"IMPORT_EXPORT_DATA": "プレイリストのインポート/エクスポート",
"IMPORT_EXPORT_DATA_DESCRIPTION": "アプリケーション内で使用されているJSONフォーマットでプレイリストをエクスポートまたはインポート。",
"IMPORT_DATA": "インポート",
"EXPORT_DATA": "エクスポート",
"REMOVE_ALL": "Delete all playlists and playlist data",
"REMOVE_ALL_BUTTON": "Delete all",
"REMOVE_ALL_DESCRIPTION": "Delete every M3U, Xtream, and Stalker playlist stored in the app.",
"REMOVE_DIALOG": {
"TITLE": "Delete all playlists?",
"MESSAGE": "Delete all {{count}} playlists from the app. This also removes stored playlist data on this device.",
"SUMMARY_TITLE": "Playlist sources",
"CONSEQUENCES_TITLE": "This also removes",
"CONSEQUENCE_FAVORITES": "Favorites saved for these playlists",
"CONSEQUENCE_RECENTLY_VIEWED": "Recently viewed history",
"CONSEQUENCE_PLAYBACK": "Saved playback positions",
"CONSEQUENCE_DOWNLOADS": "Download history entries linked to those playlists",
"CONSEQUENCE_XTREAM_CACHE": "Imported Xtream categories and locally cached content",
"BACKUP_HINT": "Use Export first if you want a restorable backup before deleting.",
"CONFIRM": "Delete everything"
},
"IMPORT_ERROR": "インポートエラー。別のファイルで試してください。",
"PLAYLISTS_REMOVED": "All playlists and playlist data were removed.",
"MPV_PLAYER_PATH_LABEL": "mpvのパス",
"MPV_PLAYER_PATH_DESCRIPTION": "システム内のmpvプレーヤーのパスを設定します。$PATHで見つかったものの代わりに、指定されたmpvバイナリのパスを使用します。",
"MPV_PLAYER_PATH": "mpvプレーヤーのパス",
"VLC_PLAYER_PATH_LABEL": "VLCのパス",
"VLC_PLAYER_PATH_DESCRIPTION": "システム内のVLCプレーヤーのパスを設定します。システムのデフォルトパスの代わりに、指定されたVLCバイナリのパスを使用します。",
"VLC_PLAYER_PATH": "VLCプレーヤーのパス",
"REMOTE_CONTROL": "リモートコントロール",
"REMOTE_CONTROL_DESCRIPTION": "アプリケーションのリモートコントロールを有効にします。",
"REMOTE_CONTROL_PORT": "リモートコントロールポート",
"REMOTE_CONTROL_PORT_DESCRIPTION": "アプリケーションのリモートコントロールに使用されるポート。デフォルトではポート3000が使用されます。",
"REMOVE_ALL_IN_PROGRESS": "Deleting playlist data…",
"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.",
"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": "ダークテーマ",
"LIGHT_THEME": "ライトテーマ",
"SYSTEM_THEME": "システムテーマ"
},
"CHANNELS": {
"SEARCH_CHANNEL": "チャンネルを検索",
"UPLOAD_OR_SELECT_OTHER_PLAYLIST": "アップロードまたは他のプレイリストを選択",
"ALL_CHANNELS": "すべてのチャンネル",
"GROUPS": "グループ",
"UNGROUPED": "グループなし",
"UNNAMED_CHANNEL": "名前のないチャンネル",
"FAVORITES": "お気に入り",
"NO_FAVORITES": "まだお気に入りがありません",
"USE_STAR_TO_FAVORITE": "'スター'アイコンを使用してチャンネルをお気に入りに追加してください。",
"REMOVE_FAVORITE": "お気に入りから削除",
"FAVORITES_UPDATED": "お気に入りが更新されました!",
"SORT_BY": "並び替え",
"SORT_BY_DATE": "追加日で並び替え(新しい順)",
"SORT_BY_RATING": "評価で並び替え",
"SORT_BY_NAME": "名前で並び替え(A-Z)"
},
"TOP_MENU": {
"OPEN_CHANNELS_LIST": "チャンネルリストを開く",
"TOGGLE_FAVORITE_FLAG": "お気に入りフラグを切り替え",
"OPEN_EPG_LIST": "EPGリストを開く",
"OPEN_MULTI_EPG": "マルチEPGビューを開く"
},
"EPG": {
"TITLE": "電子番組表",
"NEXT_DAY": "翌日",
"PREVIOUS_DAY": "前日",
"LIVE_NOW": "現在放送中",
"LIVE_STREAM": "ライブストリーム",
"TIMESHIFT_AVAILABLE": "タイムシフトが利用可能です。クリックして再生",
"EPG_NOT_AVAILABLE_DATE": "申し訳ありません。選択した日付のEPGは利用できません",
"EPG_NOT_AVAILABLE_CHANNEL_TITLE": "申し訳ありません。このチャンネルのEPGは利用できません。",
"EPG_NOT_AVAILABLE_CHANNEL_DESCRIPTION": "アプリの設定でEPGリストのURLを追加/変更してください。",
"FETCH_EPG": "EPGデータを取得中...",
"ERROR": "申し訳ありません。EPGを読み込めませんでした。",
"DOWNLOAD_SUCCESS": "EPGが正常にダウンロードされました。",
"PROGRAM_DIALOG": {
"PROGRAM_DETAILS": "番組の詳細",
"TITLE": "タイトル",
"CATEGORY": "カテゴリー",
"PARENTAL_RATING_SYSTEM": "テレビ番組レーティングシステム",
"DESCRIPTION": "説明",
"LANGUAGE": "言語",
"SHOW_PROGRAM_DETAILS": "この番組の詳細を表示"
},
"FETCH_SUCCESS": "EPGの取得に成功しました"
},
"LANGUAGES": {
"ARABIC": "العربية",
"MOROCCAN_ARABIC": "العربية (اللهجة المغربية)",
"ENGLISH": "English",
"KOREAN": "한국어",
"RUSSIAN": "Русский",
"GERMAN": "Deutsch",
"SPANISH": "Español",
"CHINESE": "简体中文",
"TRADITIONAL_CHINESE": "繁體中文",
"FRENCH": "Français",
"ITALIAN": "Italiano",
"TURKISH": "Türkçe",
"JAPANESE": "日本語",
"DUTCH": "Nederlands",
"BELARUSIAN": "Беларуская",
"POLISH": "Polski",
"PORTUGUESE": "Português",
"GREEK": "Ελληνικά"
},
"YES": "はい",
"NO": "いいえ",
"MENU": {
"OPEN": "メニューを開く",
"SUPPORT_ARIA": "GitHubでIPTVnatorをサポート",
"SETTINGS": "設定",
"SETTINGS_ARIA": "設定を開く",
"BUG_REPORT": "バグを報告",
"WHAT_IS_NEW": "新着情報",
"ABOUT": "アプリについて",
"ABOUT_ARIA": "アプリケーションについて",
"SUPPORT_PROJECT": "プロジェクトをサポート"
},
"ABOUT": {
"TITLE": "IPTVnatorについて",
"DESCRIPTION": "m3uやm3u8プレイリストのサポート、お気に入り、TV番組表、TVアーカイブ/キャッチアップなど、複数の機能を備えたクロスプラットフォームのIPTVプレーヤーアプリケーション。",
"VERSION": "バージョン",
"GITHUB_TOOLTIP": "GitHub上のITPVnatorリポジトリ",
"BUY_ME_A_COFFEE_TOOLTIP": "コーヒーを奢る",
"TWITTER_TOOLTIP": "Twitterでシェア"
},
"UPDATE_AVAILABLE": "アップデートが利用可能",
"REFRESH": "更新",
"XTREAM": {
"PLAY": "再生",
"NAME": "名前",
"RELEASE_DATE": "公開日",
"GENRE": "ジャンル",
"COUNTRY": "国",
"ACTORS": "出演者",
"DIRECTOR": "監督",
"DURATION": "時間",
"CAST": "キャスト",
"EPISODE_RUN_TIME": "エピソード再生時間",
"RATING": "評価",
"IMDB_RATING": "IMDb評価",
"KINOPOISK_RATING": "Kinopoisk評価",
"DESCRIPTION": "説明",
"YEAR": "年",
"AGE": "年齢",
"YOUTUBE_TRAILER": "YouTubeトレーラー",
"EPISODE": "エピソード"
},
"PORTALS": {
"ALL_CATEGORIES": "すべてのカテゴリー",
"MY_FAVORITES": "お気に入り",
"ADD_TO_FAVORITES": "お気に入りに追加",
"REMOVE_FROM_FAVORITES": "お気に入りから削除",
"REMOVED_FROM_FAVORITES": "お気に入りから削除されました",
"ADDED_TO_FAVORITES": "お気に入りに追加されました",
"ERROR_VIEW": {
"ACCOUNT_EXPIRED": {
"TITLE": "アカウントの有効期限が切れています",
"DESCRIPTION": "このアカウントの有効期限が切れています。プレイリスト設定で認証情報を確認するか、削除してください。"
},
"UNAUTHORIZED": {
"TITLE": "未認証",
"DESCRIPTION": "プレイリスト設定で認証情報を確認するか、削除してください。"
},
"NOT_FOUND": {
"TITLE": "ポータルが見つかりません",
"DESCRIPTION": "プレイリスト設定で認証情報とポータルURLを確認するか、削除してください。"
},
"EMPTY_CATEGORY": {
"TITLE": "空のカテゴリー",
"DESCRIPTION": "このカテゴリーにはコンテンツがありません。別のカテゴリーを選択するかコンテンツタイプを変更してください"
},
"UNKNOWN_ERROR": {
"TITLE": "問題が発生しました",
"DESCRIPTION": "不明なエラー。後でもう一度お試しください"
},
"PLAYLIST_SETTINGS": "プレイリスト設定",
"HOME": "ホーム",
"DELETE": "削除"
},
"EMPTY_LIST_VIEW": {
"NO_SEARCH_RESULTS": "何も見つかりませんでした。検索リクエストを変更してみてください"
},
"STREAM_URL_COPIED": "ストリームURLがクリップボードにコピーされました",
"COPY_STREAM_URL": "ストリームURLをコピー",
"SEARCH_VIEW": {
"RESULTS_FOUND": "{{count}}件の結果が見つかりました",
"NO_RESULTS_FOR": "「{{term}}」に一致する結果は見つかりませんでした"
}
},
"INFORMATION": "情報",
"REMOTE_CONTROL": {
"TITLE": "リモートコントロール",
"UP_CHANNEL": "チャンネルアップ",
"DOWN_CHANNEL": "チャンネルダウン",
"HEADER": "IPTVNatorリモートコントロール",
"FOOTER": "IPTVNatorリモートコントロール"
},
"WORKSPACE": {
"SHELL": {
"GO_TO_DASHBOARD": "Back to dashboard",
"GO_TO_SOURCES": "Go to Sources",
"DROP_OVERLAY_TITLE": "Drop to add playlist",
"DROP_OVERLAY_BODY": "Release an .m3u or .m3u8 file anywhere in the workspace to import it.",
"DROP_OVERLAY_REJECTED_BODY": "Please drop an .m3u or .m3u8 file. Press Esc to dismiss.",
"DROP_OVERLAY_REJECTED_UNSUPPORTED": "Unsupported file type",
"DROP_OVERLAY_REJECTED_EMPTY": "That file is empty",
"DROP_OVERLAY_REJECTED_READ_ERROR": "Could not read that file",
"DROP_IMPORT_SUCCESS": "Importing \"{{title}}\"…",
"COMMANDS": {
"ADD_PLAYLIST_M3U_LABEL": "Add M3U playlist",
"ADD_PLAYLIST_M3U_DESCRIPTION": "Open add dialog on the M3U file or URL tab",
"ADD_PLAYLIST_XTREAM_LABEL": "Add Xtream Codes playlist",
"ADD_PLAYLIST_XTREAM_DESCRIPTION": "Open add dialog on the Xtream Codes tab",
"ADD_PLAYLIST_STALKER_LABEL": "Add Stalker portal",
"ADD_PLAYLIST_STALKER_DESCRIPTION": "Open add dialog on the Stalker Portal tab"
},
"EXTERNAL_PLAYBACK_CLOSE": "Close player"
},
"GLOBAL_FAVORITES": {
"NO_PLAYLISTS_TITLE": "No favorites to show",
"NO_PLAYLISTS_BODY": "Add a playlist to start collecting favorites from live channels, movies, and series.",
"NO_ITEMS_TITLE": "No favorites yet",
"NO_ITEMS_BODY": "Tap the star icon on any channel, movie, or series to save it here."
},
"GLOBAL_RECENT": {
"NO_PLAYLISTS_TITLE": "Nothing watched yet",
"NO_PLAYLISTS_BODY": "Add a playlist and your watching history will appear here.",
"NO_ITEMS_TITLE": "Nothing watched yet",
"NO_ITEMS_BODY": "Start watching anything from your library and it will show up here."
}
},
"DOWNLOADS": {
"NO_PLAYLISTS_TITLE": "Add a playlist to start downloading",
"NO_PLAYLISTS_BODY": "Once you add a playlist, you can save movies and episodes here for offline playback.",
"NO_ITEMS_BODY": "Use the download button on any movie or episode to save it for offline playback.",
"NO_FILTER_MATCH": "No downloads match the current filter",
"NO_FILTER_MATCH_HINT": "Try a different search term"
}
}
+357
View File
@@ -0,0 +1,357 @@
{
"CLOSE": "닫기",
"HOME": {
"TITLE": "IPTVnator",
"SUBTITLE": "목록에서 재생 목록을 선택하거나 파일 업로드 또는 URL을 통해 새 재생 목록을 추가하십시오.",
"TABS": {
"RECENTLY_ADDED": "최근 재생 목록이 추가되었습니다",
"FILE_UPLOAD": "파일 업로드를 통해 추가하십시오",
"URL_UPLOAD": "URL을 통해 추가하십시오",
"TEXT_IMPORT": "Import as text",
"STALKER_PORTAL_IMPORT": "스토커 포털 추가"
},
"PLAYLISTS": {
"NO_PLAYLISTS": "재생 목록이 추가되지 않았습니다",
"ADD_FIRST": "다른 탭에서 첫 번째 재생 목록을 추가하십시오",
"ADDED_VIA_URL": "URL 업로드를 통해 추가되었습니다. URL:",
"ADDED_VIA_FILE": "파일 업로드를 통해 추가되었습니다",
"CHANNELS": "채널",
"ADDED": "추가되었습니다",
"SHOW_DETAILS": "재생 목록 세부 정보 표시",
"REMOVE": "재생 목록이 제거되었습니다",
"INFO_DIALOG": {
"PLAYLIST_DETAILS": "재생 목록 세부 사항",
"TITLE": "제목",
"FROM_URL": "URL에서 추가되었습니다",
"IMPORT_DATE": "데이터 가져 오기",
"CHANNELS": "채널 수",
"CLOSE": "닫기",
"SAVE": "저장",
"USER_AGENT": "User agent",
"ORIGINAL_FILENAME": "원래 파일 이름",
"FILE_PATH": "파일 경로",
"UPDATE_FAILED": "마지막 재생 목록 업데이트가 실패했습니다",
"AUTO_UPDATE": "자동 업데이트",
"AUTO_UPDATE_DESCRIPTION": "자동 새로 고침 기능이 활성화되면 앱이 시작될 때마다 재생 목록이 자동으로 업데이트됩니다.",
"CUSTOM_USER_AGENT": "일부 IPTV 공급자는 재생 목록을 재생하기 위해 특정 사용자 에이전트가 필요합니다.",
"PASSWORD": "비밀번호",
"SERVER_URL": "서버 URL",
"USERNAME": "사용자 이름",
"MAC_ADDRESS": "맥 주소"
},
"REMOVE_DIALOG": {
"TITLE": "재생 목록 제거",
"MESSAGE": "이 재생 목록을 완전히 삭제 하시겠습니까?"
},
"UPDATED": "업데이트 됨",
"REFRESH": "재생 목록 새로 고침",
"GLOBAL_FAVORITES": "Global favorites",
"GLOBAL_FAVORITES_DESCRIPTION": "Auto-generated playlist with aggregated favorites from all playlists",
"MY_PLAYLISTS": "My playlists",
"FEATURE_M3U_LABEL": "Add an M3U file or URL",
"FEATURE_XTREAM_LABEL": "Connect via Xtream Codes",
"FEATURE_STALKER_LABEL": "Connect to a Stalker portal",
"VALUE_PROPS_LABEL": "What you can do",
"VALUE_PROP_LIVE": "Live TV with EPG",
"VALUE_PROP_VOD": "Movies & Series",
"VALUE_PROP_MULTISOURCE": "Multi-source library",
"VALUE_PROP_OFFLINE": "Offline downloads",
"DASHBOARD_WELCOME_TAGLINE": "Your IPTV library, in one place.",
"FEATURE_LIVE_TITLE": "Live TV",
"FEATURE_LIVE_DESC": "Stream live channels with full schedule.",
"FEATURE_VOD_TITLE": "Movies & Series",
"FEATURE_VOD_DESC": "On-demand library with covers and details.",
"FEATURE_EPG_TITLE": "EPG & Catch-up",
"FEATURE_EPG_DESC": "Program guide and time-shifted playback.",
"FEATURE_OFFLINE_TITLE": "Offline downloads",
"FEATURE_OFFLINE_DESC": "Save movies and episodes for later.",
"SOURCES_WELCOME_TITLE": "Add your first playlist",
"SOURCES_WELCOME_BODY": "Pick a source type below to get started.",
"SOURCE_M3U_NEEDS": "Local file or URL pointing to an M3U/M3U8 playlist.",
"SOURCE_M3U_ADD": "Add M3U",
"SOURCE_XTREAM_NEEDS": "Username, password and server URL from your provider.",
"SOURCE_XTREAM_ADD": "Add Xtream",
"SOURCE_STALKER_NEEDS": "Portal URL and MAC address (Ministra-compatible).",
"SOURCE_STALKER_ADD": "Add Stalker",
"CONTENT_LIVE": "Live",
"CONTENT_VOD": "Movies",
"CONTENT_SERIES": "Series",
"CONTENT_EPG": "EPG",
"DASHBOARD_WELCOME_DESCRIPTION": "Connect M3U files, Xtream Codes, or Stalker portals — then enjoy live TV, movies and series on every screen."
},
"FILE_UPLOAD": {
"DRAG_DROP": "파일을 드래그 앤 드롭",
"OR": "또는",
"CHOOSE_PLAYLIST": "재생 목록을 선택"
},
"URL_UPLOAD": {
"PLAYLIST_URL": "재생 목록 URL (m3u, m3u8)",
"ADD_PLAYLIST": "재생 목록을 추가하십시오"
},
"TEXT_IMPORT": {
"LABEL": "Insert m3u(8) playlist as text",
"BUTTON_LABEL": "Import"
},
"STALKER_PORTAL": {
"ADD": "추가하다",
"TITLE": "제목",
"URL_VALIDATION_ERROR": "프로토콜이 포함된 유효한 URL이어야 합니다(예: http://example.com/c 또는 https://example.com/stalker_portal/c)."
},
"XTREAM_PLAYLIST": {
"URL_VALIDATION_ERROR": "프로토콜이 포함된 유효한 URL이어야 합니다(예: http://example.com 또는 https://example.com:4324)."
}
},
"SETTINGS": {
"TITLE": "설정",
"SUBTITLE": "응용 프로그램의 구성을 변경하십시오",
"DESCRIPTION": "아래 목록에서 옵션을 적용하고 저장 버튼으로 확인하십시오.",
"EPG_URL_LABEL": "EPG Url (*.xml or *.xml.gz)",
"EPG_URL_PLACEHOLDER": "URL을 입력하십시오",
"REFRESH_EPG": "EPG 새로 고침",
"REFRESH_ALL_EPG": "모두 새로 고침",
"REMOVE_EPG_SOURCE": "EPG 소스 제거",
"EPG_STATUS_FRESH": "최신",
"EPG_STATUS_STALE": "새로 고침 필요",
"EPG_STATUS_ERROR": "실패",
"VIDEO_PLAYER_LABEL": "비디오 플레이어",
"VIDEO_PLAYER_PLACEHOLDER": "옵션을 선택하세요",
"VERSION": "버전",
"SAVE_CHANGES": "변경 사항 저장",
"BACK_TO_HOME": "홈으로",
"NEW_VERSION_AVAILABLE": "새로운 버전이 있습니다",
"LATEST_VERSION": "최신 버전을 사용하고 있습니다",
"LANGUAGE": "언어",
"SETTINGS_SAVED": "설정이 저장되었습니다.",
"THEME": "테마",
"SHOW_CAPTIONS": "Show subtitles",
"REMOVE_ALL": "Delete all playlists and playlist data",
"REMOVE_ALL_BUTTON": "Delete all",
"REMOVE_DIALOG": {
"TITLE": "Delete all playlists?",
"MESSAGE": "Delete all {{count}} playlists from the app. This also removes stored playlist data on this device.",
"SUMMARY_TITLE": "Playlist sources",
"CONSEQUENCES_TITLE": "This also removes",
"CONSEQUENCE_FAVORITES": "Favorites saved for these playlists",
"CONSEQUENCE_RECENTLY_VIEWED": "Recently viewed history",
"CONSEQUENCE_PLAYBACK": "Saved playback positions",
"CONSEQUENCE_DOWNLOADS": "Download history entries linked to those playlists",
"CONSEQUENCE_XTREAM_CACHE": "Imported Xtream categories and locally cached content",
"BACKUP_HINT": "Use Export first if you want a restorable backup before deleting.",
"CONFIRM": "Delete everything"
},
"LANGUAGE_DESCRIPTION": "애플리케이션 언어 선택",
"PLAYLISTS_REMOVED": "All playlists and playlist data were removed.",
"VERSION_DESCRIPTION": "애플리케이션의 현재 버전",
"IMPORT_DATA": "수입",
"ADD_EPG_SOURCE": "EPG 소스 추가",
"IMPORT_ERROR": "가져오기 오류가 발생했습니다. 다른 파일로 시도해 보세요.",
"EPG_URL_ERROR": "값이 유효한 URL이 아닙니다.",
"EXPORT_DATA": "내보내다",
"VIDEO_PLAYER_DESCRIPTION": "기본 비디오 플레이어 선택",
"IMPORT_EXPORT_DATA": "재생목록 가져오기/내보내기",
"VLC_PLAYER_PATH_LABEL": "VLC 경로",
"VLC_PLAYER_PATH_DESCRIPTION": "시스템에서 VLC 플레이어의 경로를 설정하십시오. \n시스템의 기본 경로 대신 VLC 바이너리에 제공된 경로를 사용합니다.",
"THEME_DESCRIPTION": "애플리케이션의 시각적 테마 선택",
"EPG_NOTE": "현재 EPG는 IPTVnator의 전자 기반 버전에서만 사용할 수 있습니다.",
"VLC_PLAYER_PATH": "VLC 플레이어 경로",
"IMPORT_EXPORT_DATA_DESCRIPTION": "애플리케이션 내에서 사용되는 JSON 형식으로 재생 목록을 내보내거나 가져옵니다.",
"EPG_NOTE_URL_TEXT": "여기에서 확인하세요",
"MPV_PLAYER_PATH_LABEL": "mpv 경로",
"REMOVE_ALL_DESCRIPTION": "Delete every M3U, Xtream, and Stalker playlist stored in the app.",
"REMOVE_ALL_IN_PROGRESS": "Deleting playlist data…",
"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.",
"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": "어두운 테마",
"LIGHT_THEME": "밝은 테마",
"SYSTEM_THEME": "시스템 테마"
},
"CHANNELS": {
"SEARCH_CHANNEL": "검색 채널",
"UPLOAD_OR_SELECT_OTHER_PLAYLIST": "다른 재생 목록을 업로드하거나 선택하십시오",
"ALL_CHANNELS": "모든 채널",
"GROUPS": "그룹",
"UNGROUPED": "그룹 해제",
"UNNAMED_CHANNEL": "이름없는 채널",
"FAVORITES": "즐겨찾기",
"NO_FAVORITES": "즐겨찾기가 아직 없습니다",
"USE_STAR_TO_FAVORITE": "'Star'아이콘을 사용하여 이 목록에 채널을 추가하십시오.",
"REMOVE_FAVORITE": "즐겨찾기에서 삭제하기",
"FAVORITES_UPDATED": "즐겨찾기가 업데이트되었습니다!"
},
"TOP_MENU": {
"OPEN_CHANNELS_LIST": "채널 열기 목록",
"TOGGLE_FAVORITE_FLAG": "즐겨찾기 보이기/숨기기",
"OPEN_EPG_LIST": "EPG 목록 열기",
"OPEN_MULTI_EPG": "Open Multi-EPG view"
},
"EPG": {
"NEXT_DAY": "다음날",
"PREVIOUS_DAY": "전날",
"LIVE_NOW": "Live now",
"LIVE_STREAM": "Live stream",
"TIMESHIFT_AVAILABLE": "Timeshift를 사용할 수 있습니다, 클릭하여 재생합니다",
"EPG_NOT_AVAILABLE_DATE": "선택한 날짜에는 EPG를 사용할 수 없습니다.",
"EPG_NOT_AVAILABLE_CHANNEL_TITLE": "이 채널에는 EPG를 사용할 수 없습니다.",
"EPG_NOT_AVAILABLE_CHANNEL_DESCRIPTION": "설정에서 EPG의 URL을 추가/변경하십시오.",
"FETCH_EPG": "EPG 데이터 가져 오기...",
"ERROR": "Ooops, EPG could not be loaded.",
"DOWNLOAD_SUCCESS": "EPG was successfully downloaded.",
"PROGRAM_DIALOG": {
"PROGRAM_DETAILS": "TV 프로그램에 대한 세부 사항",
"TITLE": "제목",
"CATEGORY": "카테고리",
"PARENTAL_RATING_SYSTEM": "컨텐츠 등급 시스템",
"DESCRIPTION": "설명",
"LANGUAGE": "언어",
"SHOW_PROGRAM_DETAILS": "이 프로그램에 대한 세부 정보 표시"
}
},
"LANGUAGES": {
"ARABIC": "العربية",
"MOROCCAN_ARABIC": "العربية (اللهجة المغربية)",
"ENGLISH": "English",
"KOREAN": "한국어",
"RUSSIAN": "Русский",
"GERMAN": "Deutsch",
"SPANISH": "Español",
"CHINESE": "简体中文",
"TRADITIONAL_CHINESE": "繁體中文",
"FRENCH": "Français",
"ITALIAN": "Italiano",
"TURKISH": "Türkçe",
"JAPANESE": "日本語",
"DUTCH": "Nederlands",
"BELARUSIAN": "Беларуская",
"POLISH": "Polski",
"PORTUGUESE": "Português",
"GREEK": "Ελληνικά"
},
"YES": "Yes",
"NO": "No",
"MENU": {
"OPEN": "Open menu",
"SUPPORT_ARIA": "Support IPTVnator on GitHub",
"SETTINGS": "Settings",
"SETTINGS_ARIA": "Open settings",
"BUG_REPORT": "Report a bug",
"WHAT_IS_NEW": "What is new",
"ABOUT": "About",
"ABOUT_ARIA": "About the application",
"SUPPORT_PROJECT": "지원사업"
},
"XTREAM": {
"RELEASE_DATE": "출시일",
"ACTORS": "배우",
"PLAY": "놀다",
"GENRE": "장르",
"DURATION": "지속",
"COUNTRY": "국가",
"NAME": "이름",
"DIRECTOR": "감독",
"CAST": "깁스",
"RATING": "평가",
"AGE": "나이",
"EPISODE": "삽화",
"YEAR": "년도",
"YOUTUBE_TRAILER": "유튜브 예고편",
"DESCRIPTION": "설명",
"KINOPOISK_RATING": "키노포스크 등급",
"IMDB_RATING": "IMDB 평가",
"EPISODE_RUN_TIME": "에피소드 실행 시간"
},
"PORTALS": {
"ALL_CATEGORIES": "모든 카테고리",
"ADD_TO_FAVORITES": "즐겨 찾기에 추가",
"REMOVE_FROM_FAVORITES": "즐겨 찾기에서 삭제하기",
"MY_FAVORITES": "내가 좋아하는 것들",
"ERROR_VIEW": {
"DELETE": "삭제",
"ACCOUNT_EXPIRED": {
"TITLE": "계정이 만료되었습니다",
"DESCRIPTION": "이 계정은 만료되었습니다. \n재생목록 설정에서 자격 증명을 확인하거나 제거하세요."
},
"EMPTY_CATEGORY": {
"TITLE": "빈 카테고리",
"DESCRIPTION": "이 카테고리에는 콘텐츠가 없습니다. 다른 카테고리를 선택하거나 콘텐츠 유형을 변경하세요."
},
"UNAUTHORIZED": {
"TITLE": "승인되지 않은",
"DESCRIPTION": "재생목록 설정에서 자격 증명을 확인하거나 제거하세요."
},
"UNKNOWN_ERROR": {
"TITLE": "문제가 발생했습니다.",
"DESCRIPTION": "알 수 없는 오류입니다. 나중에 다시 시도해 주세요."
},
"PLAYLIST_SETTINGS": "재생목록 설정"
},
"STREAM_URL_COPIED": "스트림 URL이 클립보드에 복사되었습니다.",
"EMPTY_LIST_VIEW": {
"NO_SEARCH_RESULTS": "아무것도 찾지 못했습니다. 검색 요청을 변경해 보세요."
},
"REMOVED_FROM_FAVORITES": "즐겨찾기에서 삭제됨",
"ADDED_TO_FAVORITES": "즐겨찾기에 추가됨",
"SEARCH_VIEW": {
"RESULTS_FOUND": "{{count}}개의 결과를 찾았습니다",
"NO_RESULTS_FOR": "\"{{term}}\"에 대한 결과를 찾을 수 없습니다"
}
},
"ABOUT": {
"TITLE": "IPTVnator 소개",
"VERSION": "버전",
"TWITTER_TOOLTIP": "트위터에 공유",
"BUY_ME_A_COFFEE_TOOLTIP": "Buy me a coffee"
},
"REFRESH": "새로 고치다",
"UPDATE_AVAILABLE": "업데이트 가능",
"WORKSPACE": {
"SHELL": {
"GO_TO_DASHBOARD": "Back to dashboard",
"GO_TO_SOURCES": "Go to Sources",
"DROP_OVERLAY_TITLE": "Drop to add playlist",
"DROP_OVERLAY_BODY": "Release an .m3u or .m3u8 file anywhere in the workspace to import it.",
"DROP_OVERLAY_REJECTED_BODY": "Please drop an .m3u or .m3u8 file. Press Esc to dismiss.",
"DROP_OVERLAY_REJECTED_UNSUPPORTED": "Unsupported file type",
"DROP_OVERLAY_REJECTED_EMPTY": "That file is empty",
"DROP_OVERLAY_REJECTED_READ_ERROR": "Could not read that file",
"DROP_IMPORT_SUCCESS": "Importing \"{{title}}\"…",
"COMMANDS": {
"ADD_PLAYLIST_M3U_LABEL": "Add M3U playlist",
"ADD_PLAYLIST_M3U_DESCRIPTION": "Open add dialog on the M3U file or URL tab",
"ADD_PLAYLIST_XTREAM_LABEL": "Add Xtream Codes playlist",
"ADD_PLAYLIST_XTREAM_DESCRIPTION": "Open add dialog on the Xtream Codes tab",
"ADD_PLAYLIST_STALKER_LABEL": "Add Stalker portal",
"ADD_PLAYLIST_STALKER_DESCRIPTION": "Open add dialog on the Stalker Portal tab"
},
"EXTERNAL_PLAYBACK_CLOSE": "Close player"
},
"GLOBAL_FAVORITES": {
"NO_PLAYLISTS_TITLE": "No favorites to show",
"NO_PLAYLISTS_BODY": "Add a playlist to start collecting favorites from live channels, movies, and series.",
"NO_ITEMS_TITLE": "No favorites yet",
"NO_ITEMS_BODY": "Tap the star icon on any channel, movie, or series to save it here."
},
"GLOBAL_RECENT": {
"NO_PLAYLISTS_TITLE": "Nothing watched yet",
"NO_PLAYLISTS_BODY": "Add a playlist and your watching history will appear here.",
"NO_ITEMS_TITLE": "Nothing watched yet",
"NO_ITEMS_BODY": "Start watching anything from your library and it will show up here."
}
},
"DOWNLOADS": {
"NO_PLAYLISTS_TITLE": "Add a playlist to start downloading",
"NO_PLAYLISTS_BODY": "Once you add a playlist, you can save movies and episodes here for offline playback.",
"NO_ITEMS_BODY": "Use the download button on any movie or episode to save it for offline playback.",
"NO_FILTER_MATCH": "No downloads match the current filter",
"NO_FILTER_MATCH_HINT": "Try a different search term"
}
}
+420
View File
@@ -0,0 +1,420 @@
{
"CLOSE": "Afsluiten",
"PLAYLISTS": "Afspeellijst",
"HOME": {
"TITLE": "IPTVnator",
"SUBTITLE": "Selecteer een afspeellijst of voeg een nieuwe lijst toe",
"TABS": {
"RECENTLY_ADDED": "Recent toegevoegde afspeellijst",
"FILE_UPLOAD": "Upload een bestand",
"URL_UPLOAD": "Voeg toe via URL",
"TEXT_IMPORT": "Voeg toe via tekst",
"XTREME_IMPORT": "Voeg een Xtreme Code toe",
"STALKER_PORTAL_IMPORT": "Voeg een Stalker Portal toe"
},
"PLAYLISTS": {
"NO_PLAYLISTS": "Geen afspeellijst toegevoegd",
"ADD_FIRST": "Voeg je afspeellijst toe",
"ADDED_VIA_URL": "Toegevoegd via URL: ",
"ADDED_VIA_FILE": "Toegevoegd via bestand",
"XTREAM_PLAYLIST": "Xtream afspeellijst",
"STALKER_PORTAL": "Stalker portal",
"CHANNELS": "Kanalen",
"ADDED": "Toegevoegd",
"SHOW_DETAILS": "Toon afspeellijstdetails",
"REMOVE": "Verwijder afspeellijst",
"SEARCH_PLAYLISTS": "Zoek afspeellijst op titel",
"INFO_DIALOG": {
"PLAYLIST_DETAILS": "Afspeellijstdetails",
"TITLE": "Titel",
"FROM_URL": "Toegevoegd vanuit URL",
"IMPORT_DATE": "Importdatum",
"CHANNELS": "Aantal kanalen",
"CLOSE": "Afsluiten",
"SAVE": "Opslaan",
"USER_AGENT": "User-agent",
"ORIGINAL_FILENAME": "Oorspronkelijke bestandsnaam",
"FILE_PATH": "Bestandspad",
"UPDATE_FAILED": "Laatste afspeellijstupdate mislukt",
"AUTO_UPDATE": "Automatisch bijwerken",
"AUTO_UPDATE_DESCRIPTION": "Als automatisch bijwerken is ingeschakeld, wordt de afspeellijst bij elke start van de app vernieuwd.",
"CUSTOM_USER_AGENT": "Sommige IPTV-providers vereisen een specifieke user-agent om de afspeellijst af te spelen.",
"EXPORT_PLAYLIST": "Exporteer afspeellijst als m3u",
"SERVER_URL": "Server-URL",
"USERNAME": "Gebruikersnaam",
"PASSWORD": "Wachtwoord",
"MAC_ADDRESS": "MAC-adres",
"PLAYLIST_EXPORT_SUCCESS": "Afspeellijst succesvol geëxporteerd.",
"PLAYLIST_EXPORT_ERROR": "Fout: exporteren van afspeellijst mislukt."
},
"REMOVE_DIALOG": {
"TITLE": "Afspeellijst verwijderen",
"MESSAGE": "Weet je zeker dat je deze afspeellijst wilt verwijderen?",
"SUCCESS": "Afspeellijst succesvol verwijderd."
},
"UPDATED": "Bijgewerkt",
"REFRESH": "Afspeellijst vernieuwen",
"GLOBAL_FAVORITES": "Algemene favorieten",
"GLOBAL_FAVORITES_DESCRIPTION": "Automatisch gegenereerde afspeellijst met samengevoegde favorieten uit alle afspeellijsten.",
"MY_PLAYLISTS": "Mijn afspeellijsten",
"MY_PLAYLISTS_SUBTITLE": "Alle beschikbare afspeellijsten",
"PLAYLIST_UPDATE_SUCCESS": "De afspeellijst is succesvol bijgewerkt.",
"PLAYLIST_UPDATE_ERROR": "Fout bij het bijwerken van de afspeellijst.",
"FEATURE_M3U_LABEL": "Add an M3U file or URL",
"FEATURE_XTREAM_LABEL": "Connect via Xtream Codes",
"FEATURE_STALKER_LABEL": "Connect to a Stalker portal",
"VALUE_PROPS_LABEL": "What you can do",
"VALUE_PROP_LIVE": "Live TV with EPG",
"VALUE_PROP_VOD": "Movies & Series",
"VALUE_PROP_MULTISOURCE": "Multi-source library",
"VALUE_PROP_OFFLINE": "Offline downloads",
"DASHBOARD_WELCOME_TAGLINE": "Your IPTV library, in one place.",
"FEATURE_LIVE_TITLE": "Live TV",
"FEATURE_LIVE_DESC": "Stream live channels with full schedule.",
"FEATURE_VOD_TITLE": "Movies & Series",
"FEATURE_VOD_DESC": "On-demand library with covers and details.",
"FEATURE_EPG_TITLE": "EPG & Catch-up",
"FEATURE_EPG_DESC": "Program guide and time-shifted playback.",
"FEATURE_OFFLINE_TITLE": "Offline downloads",
"FEATURE_OFFLINE_DESC": "Save movies and episodes for later.",
"SOURCES_WELCOME_TITLE": "Add your first playlist",
"SOURCES_WELCOME_BODY": "Pick a source type below to get started.",
"SOURCE_M3U_NEEDS": "Local file or URL pointing to an M3U/M3U8 playlist.",
"SOURCE_M3U_ADD": "Add M3U",
"SOURCE_XTREAM_NEEDS": "Username, password and server URL from your provider.",
"SOURCE_XTREAM_ADD": "Add Xtream",
"SOURCE_STALKER_NEEDS": "Portal URL and MAC address (Ministra-compatible).",
"SOURCE_STALKER_ADD": "Add Stalker",
"CONTENT_LIVE": "Live",
"CONTENT_VOD": "Movies",
"CONTENT_SERIES": "Series",
"CONTENT_EPG": "EPG",
"DASHBOARD_WELCOME_DESCRIPTION": "Connect M3U files, Xtream Codes, or Stalker portals — then enjoy live TV, movies and series on every screen."
},
"FILE_UPLOAD": {
"DRAG_DROP": "Sleep bestanden hierheen",
"OR": "of",
"CHOOSE_PLAYLIST": "kies een afspeellijst",
"REJECTED": "Bestand geweigerd, niet-ondersteund bestandsformaat: {{filename}}."
},
"URL_UPLOAD": {
"PLAYLIST_URL": "Afspeellijst-URL (m3u, m3u8)",
"ADD_PLAYLIST": "Afspeellijst toevoegen",
"CORS_NOTE": "Opmerking: om CORS-problemen te voorkomen, gebruikt de app een openbare CORS-proxyservice. Voor gevoelige gegevens is het veiliger om de afspeellijst via een bestand te importeren."
},
"TEXT_IMPORT": {
"LABEL": "Voer een m3u(8)-afspeellijst in als tekst",
"BUTTON_LABEL": "Importeren"
},
"XTREAM_PLAYLIST": {
"TITLE": "Afspeellijst titel",
"SERVER_URL": "Server URL",
"USERNAME": "Gebruikersnaam",
"PASSWORD": "Wachtwoord",
"ADD": "Toevoegen",
"TEST_CREDENTIALS": "Test de inloggegevens",
"URL_VALIDATION_ERROR": "Moet een geldige URL zijn met protocol (bijv. http://example.com of https://example.com:4324)"
},
"STALKER_PORTAL": {
"TITLE": "Titel",
"MAC_ADDRESS": "Mac adres",
"SERVER_URL": "Server URL",
"URL_VALIDATION_ERROR": "Moet een geldige URL zijn met protocol (bijv. http://example.com/c o https://example.com/stalker_portal/c)",
"ADD": "Toevoegen"
},
"FILTER_BY_NAME": "Filter op naam",
"FILTER_BY_TYPE": "Filter op type",
"SORT_PLAYLISTS": "Sorteer afspeellijsten",
"SORT_BY": "Sorteer op",
"SORT_OPTIONS": {
"NAME_ASC": "Naam (A-Z)",
"NAME_DESC": "Naam (Z-A)",
"NEWEST": "Datum toegevoegd (Nieuwste eerst)",
"OLDEST": "Datum toegevoegd (Oudste eerst)"
},
"IMPORTED_AS_TEXT": "Geïmporteerd als tekst",
"PARSING_ERROR": "Fout: parsing mislukt, geen geldige afspeellijst:"
},
"SETTINGS": {
"TITLE": "Instellingen",
"SUBTITLE": "Wijzig de configuratie van de applicatie",
"DESCRIPTION": "Pas de instellingen aan en bevestig met de knop 'Wijzigingen opslaan'.",
"EPG_URL_LABEL": "EPG-URL (*.xml of *.xml.gz)",
"EPG_URL_PLACEHOLDER": "Voer een URL in",
"REFRESH_EPG": "EPG vernieuwen",
"REFRESH_ALL_EPG": "Alles vernieuwen",
"REMOVE_EPG_SOURCE": "EPG-bron verwijderen",
"EPG_STATUS_FRESH": "Up-to-date",
"EPG_STATUS_STALE": "Verouderd",
"EPG_STATUS_ERROR": "Mislukt",
"VIDEO_PLAYER_LABEL": "Videospeler",
"VIDEO_PLAYER_PLACEHOLDER": "Selecteer een optie",
"VERSION": "Versie",
"SAVE_CHANGES": "Wijzigingen opslaan",
"BACK_TO_HOME": "Terug",
"NEW_VERSION_AVAILABLE": "Een nieuwe versie is beschikbaar",
"LATEST_VERSION": "Je gebruikt de nieuwste versie",
"LANGUAGE": "Taal",
"SETTINGS_SAVED": "Succes! De instellingen zijn opgeslagen.",
"THEME": "Visueel thema",
"SHOW_CAPTIONS": "Ondertiteling weergeven",
"ADD_EPG_SOURCE": "EPG-bron toevoegen",
"EPG_URL_ERROR": "De opgegeven waarde is geen geldige URL.",
"VIDEO_PLAYER_DESCRIPTION": "Selecteer de standaard videospeler",
"LANGUAGE_DESCRIPTION": "Selecteer de taal van de applicatie",
"THEME_DESCRIPTION": "Kies het visuele thema van de applicatie",
"SHOW_CAPTIONS_DESCRIPTION": "Standaard ondertiteling weergeven of verbergen",
"VERSION_DESCRIPTION": "Huidige versie van de applicatie",
"EPG_NOTE": "Momenteel is EPG alleen beschikbaar in de op Electron gebaseerde versie van IPTVnator.",
"EPG_NOTE_URL_TEXT": "Bekijk het hier",
"IMPORT_EXPORT_DATA": "Afspeellijsten importeren/exporteren",
"IMPORT_EXPORT_DATA_DESCRIPTION": "Exporteer of importeer afspeellijsten in JSON-formaat.",
"IMPORT_DATA": "Importeren",
"EXPORT_DATA": "Exporteren",
"REMOVE_ALL": "Delete all playlists and playlist data",
"REMOVE_ALL_BUTTON": "Delete all",
"REMOVE_ALL_DESCRIPTION": "Delete every M3U, Xtream, and Stalker playlist stored in the app.",
"REMOVE_DIALOG": {
"TITLE": "Delete all playlists?",
"MESSAGE": "Delete all {{count}} playlists from the app. This also removes stored playlist data on this device.",
"SUMMARY_TITLE": "Playlist sources",
"CONSEQUENCES_TITLE": "This also removes",
"CONSEQUENCE_FAVORITES": "Favorites saved for these playlists",
"CONSEQUENCE_RECENTLY_VIEWED": "Recently viewed history",
"CONSEQUENCE_PLAYBACK": "Saved playback positions",
"CONSEQUENCE_DOWNLOADS": "Download history entries linked to those playlists",
"CONSEQUENCE_XTREAM_CACHE": "Imported Xtream categories and locally cached content",
"BACKUP_HINT": "Use Export first if you want a restorable backup before deleting.",
"CONFIRM": "Delete everything"
},
"IMPORT_ERROR": "Fout bij importeren, probeer een ander bestand.",
"PLAYLISTS_REMOVED": "All playlists and playlist data were removed.",
"MPV_PLAYER_PATH_LABEL": "mpv-bestandspad",
"MPV_PLAYER_PATH_DESCRIPTION": "Stel het bestandspad in naar de mpv-speler op je systeem. Dit bestandspad wordt gebruikt in plaats van de standaard mpv-bestand uit $PATH.",
"MPV_PLAYER_PATH": "mpv-speler bestandspad",
"VLC_PLAYER_PATH_LABEL": "VLC-bestandspad",
"VLC_PLAYER_PATH_DESCRIPTION": "Stel het bestandspad in naar de VLC-speler op je systeem. Dit bestandspad wordt gebruikt in plaats van het standaardpad van het systeem.",
"VLC_PLAYER_PATH": "VLC-speler bestandspad",
"REMOTE_CONTROL": "Afstandsbediening",
"REMOTE_CONTROL_DESCRIPTION": "Schakel de afstandsbediening voor de applicatie in.",
"REMOTE_CONTROL_PORT": "Afstandsbedieningspoort",
"REMOTE_CONTROL_PORT_DESCRIPTION": "Poort voor de afstandsbediening van de applicatie. Standaard wordt poort 3000 gebruikt.",
"REMOVE_ALL_IN_PROGRESS": "Deleting playlist data…",
"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.",
"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",
"LIGHT_THEME": "Licht thema",
"SYSTEM_THEME": "Systeemthema"
},
"CHANNELS": {
"SEARCH_CHANNEL": "Zoek een kanaal",
"UPLOAD_OR_SELECT_OTHER_PLAYLIST": "Upload of selecteer een andere afspeellijst",
"ALL_CHANNELS": "Alle kanalen",
"GROUPS": "Groepen",
"UNGROUPED": "Niet gegroepeerd",
"UNNAMED_CHANNEL": "Naamloos kanaal",
"FAVORITES": "Favorieten",
"NO_FAVORITES": "Nog geen favorieten",
"USE_STAR_TO_FAVORITE": "Gebruik het ster-icoon om kanalen toe te voegen aan je favorieten.",
"REMOVE_FAVORITE": "Verwijder uit favorieten",
"FAVORITES_UPDATED": "Favorieten zijn bijgewerkt!",
"SORT_BY": "Sorteren op",
"SORT_BY_DATE": "Sorteren op datum toegevoegd (Nieuwste eerst)",
"SORT_BY_RATING": "Sorteren op beoordeling",
"SORT_BY_NAME": "Sorteren op naam (A-Z)"
},
"TOP_MENU": {
"OPEN_CHANNELS_LIST": "Open kanalenlijst",
"TOGGLE_FAVORITE_FLAG": "Wissel favorietenstatus",
"OPEN_EPG_LIST": "Open TV-gids lijst",
"OPEN_MULTI_EPG": "Open Multi TV-Gids weergave"
},
"EPG": {
"TITLE": "TV-Gids",
"NEXT_DAY": "Volgende dag",
"PREVIOUS_DAY": "Vorige dag",
"LIVE_NOW": "Nu live",
"LIVE_STREAM": "Live stream",
"TIMESHIFT_AVAILABLE": "Doorspoelen is beschikbaar, klik om af te spelen",
"EPG_NOT_AVAILABLE_DATE": "De TV-Gids is niet beschikbaar voor de geselecteerde datum",
"EPG_NOT_AVAILABLE_CHANNEL_TITLE": "De TV-Gids is niet beschikbaar voor dit kanaal.",
"EPG_NOT_AVAILABLE_CHANNEL_DESCRIPTION": "Voeg een TV-Gids URL toe of wijzig deze in de instellingen van de app.",
"FETCH_EPG": "Ophalen TV-Gids...",
"ERROR": "TV-Gids kan niet geladen worden.",
"DOWNLOAD_SUCCESS": "De TV-Gids is gedownload.",
"PROGRAM_DIALOG": {
"PROGRAM_DETAILS": "Details over het tv-programma",
"TITLE": "Titel",
"CATEGORY": "Categorie",
"PARENTAL_RATING_SYSTEM": "Kijkwijzer",
"DESCRIPTION": "Beschrijving",
"LANGUAGE": "Taal",
"SHOW_PROGRAM_DETAILS": "Toon details over dit programma"
},
"FETCH_SUCCESS": "TV-Gids bijgewerkt"
},
"LANGUAGES": {
"ARABIC": "العربية",
"MOROCCAN_ARABIC": "العربية (اللهجة المغربية)",
"ENGLISH": "English",
"KOREAN": "한국어",
"RUSSIAN": "Русский",
"GERMAN": "Deutsch",
"SPANISH": "Español",
"CHINESE": "简体中文",
"TRADITIONAL_CHINESE": "繁體中文",
"FRENCH": "Français",
"ITALIAN": "Italiano",
"TURKISH": "Türkçe",
"JAPANESE": "日本語",
"DUTCH": "Nederlands",
"BELARUSIAN": "Беларуская",
"POLISH": "Polski",
"PORTUGUESE": "Português",
"GREEK": "Ελληνικά"
},
"YES": "Ja",
"NO": "Nee",
"MENU": {
"OPEN": "Open menu",
"SUPPORT_ARIA": "Ondersteun IPTVnator op GitHub",
"SETTINGS": "Instellingen",
"SETTINGS_ARIA": "Open instellingen",
"BUG_REPORT": "Meld een bug",
"WHAT_IS_NEW": "Wat is er nieuw",
"ABOUT": "Over",
"ABOUT_ARIA": "Over de applicatie",
"SUPPORT_PROJECT": "Ondersteun het project"
},
"ABOUT": {
"TITLE": "Over IPTVnator",
"DESCRIPTION": "Cross-platform IPTV-speler met meerdere features zoals ondersteuning voor m3u en m3u8 afspeellijsten, favorieten, TV-gids, TV-archief en meer.",
"VERSION": "Versie",
"GITHUB_TOOLTIP": "ITPVnator repository op GitHub",
"BUY_ME_A_COFFEE_TOOLTIP": "Koop een kopje koffie",
"TWITTER_TOOLTIP": "Deel op X"
},
"UPDATE_AVAILABLE": "Update beschikbaar",
"REFRESH": "Ververs",
"XTREAM": {
"PLAY": "Afspelen",
"NAME": "Naam",
"RELEASE_DATE": "Verschijningsdatum",
"GENRE": "Genre",
"COUNTRY": "Land",
"ACTORS": "Acteurs",
"DIRECTOR": "Regisseur",
"DURATION": "Lengte",
"CAST": "Cast",
"EPISODE_RUN_TIME": "Aflevering lengte",
"RATING": "Score",
"IMDB_RATING": " Score op IMDB",
"KINOPOISK_RATING": "Score op Kinopoisk",
"DESCRIPTION": "Beschrijving",
"YEAR": "Jaar",
"AGE": "Leeftijd",
"YOUTUBE_TRAILER": "YouTube Trailer",
"EPISODE": "Aflevering"
},
"PORTALS": {
"ALL_CATEGORIES": "Alle categoriën",
"MY_FAVORITES": "Mijn favorieten",
"ADD_TO_FAVORITES": "Voeg toe aan favorieten",
"REMOVE_FROM_FAVORITES": "Verwijder van favorieten",
"REMOVED_FROM_FAVORITES": "Verwijderd van favorieten",
"ADDED_TO_FAVORITES": "Toegevoegd aan favorieten",
"ERROR_VIEW": {
"ACCOUNT_EXPIRED": {
"TITLE": "Account verlopen",
"DESCRIPTION": "Dit account is verlopen. Controleer de gegevens in de afspeellijst instellingen of verwijder de afspeellijst."
},
"UNAUTHORIZED": {
"TITLE": "Niet geautoriseerd",
"DESCRIPTION": "Controleer de inloggegevens in de afspeellijst instellingen of verwijder de afspeellijst."
},
"NOT_FOUND": {
"TITLE": "Portal niet gevonden",
"DESCRIPTION": "Controleer de inloggegevens en de portal url in de afspeellijst instellingen of verwijder de afspeellijst."
},
"EMPTY_CATEGORY": {
"TITLE": "Lege categorie",
"DESCRIPTION": "Deze categorie heeft geen inhoud, selecteer een andere categorie of verander de categorie"
},
"UNKNOWN_ERROR": {
"TITLE": "Fout, er is iets misgegaan",
"DESCRIPTION": "Onbekende fout, probeer het later opnieuw"
},
"PLAYLIST_SETTINGS": "Afspeellijst instellingen",
"HOME": "Home",
"DELETE": "Verwijderen"
},
"EMPTY_LIST_VIEW": {
"NO_SEARCH_RESULTS": "Niks gevonden, verander je zoekopdracht"
},
"STREAM_URL_COPIED": "Stream URL Gekopieërd",
"COPY_STREAM_URL": "Kopieër Stream URL",
"SEARCH_VIEW": {
"RESULTS_FOUND": "{{count}} resultaten gevonden",
"NO_RESULTS_FOR": "Geen resultaten gevonden voor \"{{term}}\""
}
},
"INFORMATION": "Informatie",
"REMOTE_CONTROL": {
"TITLE": "Afstandsbediening",
"UP_CHANNEL": "Kanaal omhoog",
"DOWN_CHANNEL": "Kanaal omlaag",
"HEADER": "IPTVNator Afstandsbediening",
"FOOTER": "IPTVNator Afstandsbediening"
},
"WORKSPACE": {
"SHELL": {
"GO_TO_DASHBOARD": "Back to dashboard",
"GO_TO_SOURCES": "Go to Sources",
"DROP_OVERLAY_TITLE": "Drop to add playlist",
"DROP_OVERLAY_BODY": "Release an .m3u or .m3u8 file anywhere in the workspace to import it.",
"DROP_OVERLAY_REJECTED_BODY": "Please drop an .m3u or .m3u8 file. Press Esc to dismiss.",
"DROP_OVERLAY_REJECTED_UNSUPPORTED": "Unsupported file type",
"DROP_OVERLAY_REJECTED_EMPTY": "That file is empty",
"DROP_OVERLAY_REJECTED_READ_ERROR": "Could not read that file",
"DROP_IMPORT_SUCCESS": "Importing \"{{title}}\"…",
"COMMANDS": {
"ADD_PLAYLIST_M3U_LABEL": "Add M3U playlist",
"ADD_PLAYLIST_M3U_DESCRIPTION": "Open add dialog on the M3U file or URL tab",
"ADD_PLAYLIST_XTREAM_LABEL": "Add Xtream Codes playlist",
"ADD_PLAYLIST_XTREAM_DESCRIPTION": "Open add dialog on the Xtream Codes tab",
"ADD_PLAYLIST_STALKER_LABEL": "Add Stalker portal",
"ADD_PLAYLIST_STALKER_DESCRIPTION": "Open add dialog on the Stalker Portal tab"
},
"EXTERNAL_PLAYBACK_CLOSE": "Close player"
},
"GLOBAL_FAVORITES": {
"NO_PLAYLISTS_TITLE": "No favorites to show",
"NO_PLAYLISTS_BODY": "Add a playlist to start collecting favorites from live channels, movies, and series.",
"NO_ITEMS_TITLE": "No favorites yet",
"NO_ITEMS_BODY": "Tap the star icon on any channel, movie, or series to save it here."
},
"GLOBAL_RECENT": {
"NO_PLAYLISTS_TITLE": "Nothing watched yet",
"NO_PLAYLISTS_BODY": "Add a playlist and your watching history will appear here.",
"NO_ITEMS_TITLE": "Nothing watched yet",
"NO_ITEMS_BODY": "Start watching anything from your library and it will show up here."
}
},
"DOWNLOADS": {
"NO_PLAYLISTS_TITLE": "Add a playlist to start downloading",
"NO_PLAYLISTS_BODY": "Once you add a playlist, you can save movies and episodes here for offline playback.",
"NO_ITEMS_BODY": "Use the download button on any movie or episode to save it for offline playback.",
"NO_FILTER_MATCH": "No downloads match the current filter",
"NO_FILTER_MATCH_HINT": "Try a different search term"
}
}
+420
View File
@@ -0,0 +1,420 @@
{
"CLOSE": "Zamknij",
"PLAYLISTS": "Listy odtwarzania",
"HOME": {
"TITLE": "IPTVnator",
"SUBTITLE": "Wybierz listę odtwarzania z listy lub dodaj nową listę odtwarzania",
"TABS": {
"RECENTLY_ADDED": "Ostatnio dodane listy odtwarzania",
"FILE_UPLOAD": "Dodaj przez przesłanie pliku",
"URL_UPLOAD": "Dodaj przez URL",
"TEXT_IMPORT": "Importuj z tekstu",
"XTREME_IMPORT": "Dodaj kod Xtreme",
"STALKER_PORTAL_IMPORT": "Dodaj portal Stalker"
},
"PLAYLISTS": {
"NO_PLAYLISTS": "Nie dodano żadnych list odtwarzania",
"ADD_FIRST": "Dodaj swoją pierwszą listę odtwarzania",
"ADDED_VIA_URL": "Dodano przez przesłanie URL. URL:",
"ADDED_VIA_FILE": "Dodano przez przesłanie pliku",
"XTREAM_PLAYLIST": "Lista odtwarzania Xtream",
"STALKER_PORTAL": "Portal Stalker",
"CHANNELS": "Kanały",
"ADDED": "Dodano",
"SHOW_DETAILS": "Pokaż szczegóły listy odtwarzania",
"REMOVE": "Usuń listę odtwarzania",
"SEARCH_PLAYLISTS": "Szukaj list odtwarzania według tytułu",
"INFO_DIALOG": {
"PLAYLIST_DETAILS": "Szczegóły listy odtwarzania",
"TITLE": "Tytuł",
"FROM_URL": "Dodano z URL",
"IMPORT_DATE": "Data importu",
"CHANNELS": "Liczba kanałów",
"CLOSE": "Zamknij",
"SAVE": "Zapisz",
"USER_AGENT": "Agent użytkownika",
"ORIGINAL_FILENAME": "Oryginalna nazwa pliku",
"FILE_PATH": "Ścieżka pliku",
"UPDATE_FAILED": "Ostatnia aktualizacja listy odtwarzania nie powiodła się",
"AUTO_UPDATE": "Automatyczna aktualizacja",
"AUTO_UPDATE_DESCRIPTION": "Jeśli funkcja automatycznego odświeżania jest aktywna, lista odtwarzania będzie automatycznie aktualizowana przy każdym uruchomieniu aplikacji.",
"CUSTOM_USER_AGENT": "Niektórzy dostawcy IPTV wymagają określonego agenta użytkownika, aby odtworzyć ich listę odtwarzania.",
"EXPORT_PLAYLIST": "Eksportuj listę odtwarzania jako m3u",
"SERVER_URL": "URL serwera",
"USERNAME": "Nazwa użytkownika",
"PASSWORD": "Hasło",
"MAC_ADDRESS": "Adres Mac",
"PLAYLIST_EXPORT_SUCCESS": "Lista odtwarzania została pomyślnie wyeksportowana.",
"PLAYLIST_EXPORT_ERROR": "Błąd: Eksport listy odtwarzania nie powiódł się."
},
"REMOVE_DIALOG": {
"TITLE": "Usuń listę odtwarzania",
"MESSAGE": "Czy na pewno chcesz całkowicie usunąć tę listę odtwarzania?",
"SUCCESS": "Lista odtwarzania została pomyślnie usunięta"
},
"UPDATED": "Zaktualizowano",
"REFRESH": "Odśwież listę odtwarzania",
"GLOBAL_FAVORITES": "Globalne ulubione",
"GLOBAL_FAVORITES_DESCRIPTION": "Automatycznie wygenerowana lista odtwarzania z zagregowanymi ulubionymi ze wszystkich list odtwarzania",
"MY_PLAYLISTS": "Moje listy odtwarzania",
"MY_PLAYLISTS_SUBTITLE": "wszystkie dostępne listy odtwarzania",
"PLAYLIST_UPDATE_SUCCESS": "Sukces! Lista odtwarzania została pomyślnie zaktualizowana.",
"PLAYLIST_UPDATE_ERROR": "Błąd aktualizacji szczegółów listy odtwarzania.",
"FEATURE_M3U_LABEL": "Add an M3U file or URL",
"FEATURE_XTREAM_LABEL": "Connect via Xtream Codes",
"FEATURE_STALKER_LABEL": "Connect to a Stalker portal",
"VALUE_PROPS_LABEL": "What you can do",
"VALUE_PROP_LIVE": "Live TV with EPG",
"VALUE_PROP_VOD": "Movies & Series",
"VALUE_PROP_MULTISOURCE": "Multi-source library",
"VALUE_PROP_OFFLINE": "Offline downloads",
"DASHBOARD_WELCOME_TAGLINE": "Your IPTV library, in one place.",
"FEATURE_LIVE_TITLE": "Live TV",
"FEATURE_LIVE_DESC": "Stream live channels with full schedule.",
"FEATURE_VOD_TITLE": "Movies & Series",
"FEATURE_VOD_DESC": "On-demand library with covers and details.",
"FEATURE_EPG_TITLE": "EPG & Catch-up",
"FEATURE_EPG_DESC": "Program guide and time-shifted playback.",
"FEATURE_OFFLINE_TITLE": "Offline downloads",
"FEATURE_OFFLINE_DESC": "Save movies and episodes for later.",
"SOURCES_WELCOME_TITLE": "Add your first playlist",
"SOURCES_WELCOME_BODY": "Pick a source type below to get started.",
"SOURCE_M3U_NEEDS": "Local file or URL pointing to an M3U/M3U8 playlist.",
"SOURCE_M3U_ADD": "Add M3U",
"SOURCE_XTREAM_NEEDS": "Username, password and server URL from your provider.",
"SOURCE_XTREAM_ADD": "Add Xtream",
"SOURCE_STALKER_NEEDS": "Portal URL and MAC address (Ministra-compatible).",
"SOURCE_STALKER_ADD": "Add Stalker",
"CONTENT_LIVE": "Live",
"CONTENT_VOD": "Movies",
"CONTENT_SERIES": "Series",
"CONTENT_EPG": "EPG",
"DASHBOARD_WELCOME_DESCRIPTION": "Connect M3U files, Xtream Codes, or Stalker portals — then enjoy live TV, movies and series on every screen."
},
"FILE_UPLOAD": {
"DRAG_DROP": "Przeciągnij i upuść pliki tutaj",
"OR": "lub",
"CHOOSE_PLAYLIST": "wybierz listę odtwarzania",
"REJECTED": "Plik został odrzucony, nieobsługiwany format pliku {{filename}}."
},
"URL_UPLOAD": {
"PLAYLIST_URL": "URL listy odtwarzania (m3u, m3u8)",
"ADD_PLAYLIST": "Dodaj listę odtwarzania",
"CORS_NOTE": "Uwaga: Aby uniknąć problemów z CORS, aplikacja używa publicznej usługi proxy CORS. Jeśli chcesz przesłać listę odtwarzania z wrażliwymi danymi, bezpieczniej jest zaimportować ją z pliku."
},
"TEXT_IMPORT": {
"LABEL": "Wklej listę odtwarzania m3u(8) jako tekst",
"BUTTON_LABEL": "Importuj"
},
"XTREAM_PLAYLIST": {
"TITLE": "Tytuł listy odtwarzania",
"SERVER_URL": "URL serwera",
"USERNAME": "Nazwa użytkownika",
"PASSWORD": "Hasło",
"ADD": "Dodaj",
"TEST_CREDENTIALS": "Testuj dane uwierzytelniające",
"URL_VALIDATION_ERROR": "Powinien to być poprawny URL z protokołem (np. http://example.com lub https://example.com:4324)"
},
"STALKER_PORTAL": {
"TITLE": "Tytuł",
"MAC_ADDRESS": "Adres Mac",
"SERVER_URL": "URL serwera",
"URL_VALIDATION_ERROR": "Powinien to być poprawny URL z protokołem (np. http://example.com/c lub https://example.com/stalker_portal/c)",
"ADD": "Dodaj"
},
"FILTER_BY_NAME": "Filtruj według nazwy",
"FILTER_BY_TYPE": "Filtruj według typu",
"SORT_PLAYLISTS": "Sortuj listy odtwarzania",
"SORT_BY": "Sortuj według",
"SORT_OPTIONS": {
"NAME_ASC": "Nazwa (A-Z)",
"NAME_DESC": "Nazwa (Z-A)",
"NEWEST": "Data dodania (najnowsze pierwsze)",
"OLDEST": "Data dodania (najstarsze pierwsze)"
},
"IMPORTED_AS_TEXT": "Zaimportowano jako tekst",
"PARSING_ERROR": "Błąd: Analiza nie powiodła się, nieprawidłowa lista odtwarzania:"
},
"SETTINGS": {
"TITLE": "Ustawienia",
"SUBTITLE": "Zmień konfigurację aplikacji",
"DESCRIPTION": "Dostosuj opcje z poniższej listy i potwierdź przyciskiem „Zapisz zmiany”",
"EPG_URL_LABEL": "URL EPG (*.xml lub *.xml.gz)",
"EPG_URL_PLACEHOLDER": "Wprowadź URL",
"REFRESH_EPG": "Odśwież EPG",
"REFRESH_ALL_EPG": "Odśwież wszystko",
"REMOVE_EPG_SOURCE": "Usuń źródło EPG",
"EPG_STATUS_FRESH": "Aktualne",
"EPG_STATUS_STALE": "Wymaga odświeżenia",
"EPG_STATUS_ERROR": "Błąd",
"VIDEO_PLAYER_LABEL": "Odtwarzacz wideo",
"VIDEO_PLAYER_PLACEHOLDER": "Wybierz opcję",
"VERSION": "Wersja",
"SAVE_CHANGES": "Zapisz zmiany",
"BACK_TO_HOME": "Wróć",
"NEW_VERSION_AVAILABLE": "Dostępna jest nowa wersja",
"LATEST_VERSION": "Używasz najnowszej wersji",
"LANGUAGE": "Język",
"SETTINGS_SAVED": "Sukces! Konfiguracja została zapisana.",
"THEME": "Motyw wizualny",
"SHOW_CAPTIONS": "Pokaż napisy",
"ADD_EPG_SOURCE": "Dodaj źródło EPG",
"EPG_URL_ERROR": "Wartość nie jest prawidłowym URL",
"VIDEO_PLAYER_DESCRIPTION": "Wybierz domyślny odtwarzacz wideo",
"LANGUAGE_DESCRIPTION": "Wybierz język aplikacji",
"THEME_DESCRIPTION": "Wybierz motyw wizualny aplikacji",
"SHOW_CAPTIONS_DESCRIPTION": "Domyślnie pokaż lub ukryj napisy",
"VERSION_DESCRIPTION": "Aktualna wersja aplikacji",
"EPG_NOTE": "Obecnie EPG jest dostępne tylko w wersji IPTVnator opartej na Electron.",
"EPG_NOTE_URL_TEXT": "Sprawdź tutaj",
"IMPORT_EXPORT_DATA": "Import/eksport list odtwarzania",
"IMPORT_EXPORT_DATA_DESCRIPTION": "Eksportuj lub importuj listy odtwarzania w formacie JSON używanym w aplikacji.",
"IMPORT_DATA": "Importuj",
"EXPORT_DATA": "Eksportuj",
"REMOVE_ALL": "Delete all playlists and playlist data",
"REMOVE_ALL_BUTTON": "Delete all",
"REMOVE_ALL_DESCRIPTION": "Delete every M3U, Xtream, and Stalker playlist stored in the app.",
"REMOVE_DIALOG": {
"TITLE": "Delete all playlists?",
"MESSAGE": "Delete all {{count}} playlists from the app. This also removes stored playlist data on this device.",
"SUMMARY_TITLE": "Playlist sources",
"CONSEQUENCES_TITLE": "This also removes",
"CONSEQUENCE_FAVORITES": "Favorites saved for these playlists",
"CONSEQUENCE_RECENTLY_VIEWED": "Recently viewed history",
"CONSEQUENCE_PLAYBACK": "Saved playback positions",
"CONSEQUENCE_DOWNLOADS": "Download history entries linked to those playlists",
"CONSEQUENCE_XTREAM_CACHE": "Imported Xtream categories and locally cached content",
"BACKUP_HINT": "Use Export first if you want a restorable backup before deleting.",
"CONFIRM": "Delete everything"
},
"IMPORT_ERROR": "Błąd importu, spróbuj z innym plikiem.",
"PLAYLISTS_REMOVED": "All playlists and playlist data were removed.",
"MPV_PLAYER_PATH_LABEL": "Ścieżka mpv",
"MPV_PLAYER_PATH_DESCRIPTION": "Ustaw ścieżkę do odtwarzacza mpv w systemie. Będzie używać podanej ścieżki do pliku binarnego mpv zamiast tego znalezionego w $PATH.",
"MPV_PLAYER_PATH": "Ścieżka odtwarzacza mpv",
"VLC_PLAYER_PATH_LABEL": "Ścieżka VLC",
"VLC_PLAYER_PATH_DESCRIPTION": "Ustaw ścieżkę do odtwarzacza VLC w systemie. Będzie używać podanej ścieżki do pliku binarnego VLC zamiast domyślnej ścieżki dla naszego systemu.",
"VLC_PLAYER_PATH": "Ścieżka odtwarzacza VLC",
"REMOTE_CONTROL": "Zdalne sterowanie",
"REMOTE_CONTROL_DESCRIPTION": "Włącz zdalne sterowanie aplikacją.",
"REMOTE_CONTROL_PORT": "Port zdalnego sterowania",
"REMOTE_CONTROL_PORT_DESCRIPTION": "Port używany do zdalnego sterowania aplikacją. Domyślnie używany jest port 3000.",
"REMOVE_ALL_IN_PROGRESS": "Deleting playlist data…",
"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.",
"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",
"LIGHT_THEME": "Jasny motyw",
"SYSTEM_THEME": "Motyw systemowy"
},
"CHANNELS": {
"SEARCH_CHANNEL": "Szukaj kanału",
"UPLOAD_OR_SELECT_OTHER_PLAYLIST": "Prześlij lub wybierz inną listę odtwarzania",
"ALL_CHANNELS": "Wszystkie kanały",
"GROUPS": "Grupy",
"UNGROUPED": "Niegrupowane",
"UNNAMED_CHANNEL": "Nienazwany kanał",
"FAVORITES": "Ulubione",
"NO_FAVORITES": "Brak ulubionych",
"USE_STAR_TO_FAVORITE": "Użyj ikony „gwiazdki”, aby dodać kanały do ulubionych.",
"REMOVE_FAVORITE": "Usuń z ulubionych",
"FAVORITES_UPDATED": "Ulubione zostały zaktualizowane!",
"SORT_BY": "Sortuj według",
"SORT_BY_DATE": "Sortuj według daty dodania (najnowsze pierwsze)",
"SORT_BY_RATING": "Sortuj według oceny",
"SORT_BY_NAME": "Sortuj według nazwy (A-Z)"
},
"TOP_MENU": {
"OPEN_CHANNELS_LIST": "Otwórz listę kanałów",
"TOGGLE_FAVORITE_FLAG": "Przełącz flagę ulubionych",
"OPEN_EPG_LIST": "Otwórz listę EPG",
"OPEN_MULTI_EPG": "Otwórz widok Multi-EPG"
},
"EPG": {
"TITLE": "Elektroniczny przewodnik po programach",
"NEXT_DAY": "Następny dzień",
"PREVIOUS_DAY": "Poprzedni dzień",
"LIVE_NOW": "Na żywo teraz",
"LIVE_STREAM": "Transmisja na żywo",
"TIMESHIFT_AVAILABLE": "Dostępne jest przesunięcie czasowe, kliknij, aby odtworzyć",
"EPG_NOT_AVAILABLE_DATE": "Ups, EPG nie jest dostępne dla wybranej daty",
"EPG_NOT_AVAILABLE_CHANNEL_TITLE": "Ups, EPG nie jest dostępne dla tego kanału.",
"EPG_NOT_AVAILABLE_CHANNEL_DESCRIPTION": "Dodaj/zmień URL listy EPG w ustawieniach aplikacji.",
"FETCH_EPG": "Pobieranie danych EPG...",
"ERROR": "Ups, nie można załadować EPG.",
"DOWNLOAD_SUCCESS": "EPG zostało pomyślnie pobrane.",
"PROGRAM_DIALOG": {
"PROGRAM_DETAILS": "Szczegóły programu telewizyjnego",
"TITLE": "Tytuł",
"CATEGORY": "Kategoria",
"PARENTAL_RATING_SYSTEM": "System oceny treści telewizyjnych",
"DESCRIPTION": "Opis",
"LANGUAGE": "Język",
"SHOW_PROGRAM_DETAILS": "Pokaż szczegóły programu"
},
"FETCH_SUCCESS": "EPG zostało pomyślnie pobrane"
},
"LANGUAGES": {
"ARABIC": "العربية",
"MOROCCAN_ARABIC": "العربية (اللهجة المغربية)",
"ENGLISH": "English",
"KOREAN": "한국어",
"RUSSIAN": "Русский",
"GERMAN": "Deutsch",
"SPANISH": "Español",
"CHINESE": "简体中文",
"TRADITIONAL_CHINESE": "繁體中文",
"FRENCH": "Français",
"ITALIAN": "Italiano",
"TURKISH": "Türkçe",
"JAPANESE": "日本語",
"DUTCH": "Nederlands",
"BELARUSIAN": "Беларуская",
"POLISH": "Polski",
"PORTUGUESE": "Português",
"GREEK": "Ελληνικά"
},
"YES": "Tak",
"NO": "Nie",
"MENU": {
"OPEN": "Otwórz menu",
"SUPPORT_ARIA": "Wsparcie IPTVnator na GitHubie",
"SETTINGS": "Ustawienia",
"SETTINGS_ARIA": "Otwórz ustawienia",
"BUG_REPORT": "Zgłoś błąd",
"WHAT_IS_NEW": "Co nowego",
"ABOUT": "O aplikacji",
"ABOUT_ARIA": "Informacje o aplikacji",
"SUPPORT_PROJECT": "Wesprzyj projekt"
},
"ABOUT": {
"TITLE": "O IPTVnator",
"DESCRIPTION": "Wieloplatformowa aplikacja do odtwarzania IPTV z wieloma funkcjami, takimi jak obsługa list odtwarzania m3u i m3u8, ulubione, przewodnik TV, archiwum TV/catchup i inne.",
"VERSION": "Wersja",
"GITHUB_TOOLTIP": "Repozytorium ITPVnator na GitHubie",
"BUY_ME_A_COFFEE_TOOLTIP": "Postaw mi kawę",
"TWITTER_TOOLTIP": "Udostępnij na Twitterze"
},
"UPDATE_AVAILABLE": "Dostępna aktualizacja",
"REFRESH": "Odśwież",
"XTREAM": {
"PLAY": "Odtwórz",
"NAME": "Nazwa",
"RELEASE_DATE": "Data wydania",
"GENRE": "Gatunek",
"COUNTRY": "Kraj",
"ACTORS": "Aktorzy",
"DIRECTOR": "Reżyser",
"DURATION": "Czas trwania",
"CAST": "Obsada",
"EPISODE_RUN_TIME": "Czas trwania odcinka",
"RATING": "Ocena",
"IMDB_RATING": "Ocena IMDB",
"KINOPOISK_RATING": "Ocena Kinopoisk",
"DESCRIPTION": "Opis",
"YEAR": "Rok",
"AGE": "Wiek",
"YOUTUBE_TRAILER": "Zwiastun YouTube",
"EPISODE": "Odcinek"
},
"PORTALS": {
"ALL_CATEGORIES": "Wszystkie kategorie",
"MY_FAVORITES": "Moje ulubione",
"ADD_TO_FAVORITES": "Dodaj do ulubionych",
"REMOVE_FROM_FAVORITES": "Usuń z ulubionych",
"REMOVED_FROM_FAVORITES": "Usunięto z ulubionych",
"ADDED_TO_FAVORITES": "Dodano do ulubionych",
"ERROR_VIEW": {
"ACCOUNT_EXPIRED": {
"TITLE": "Konto wygasło",
"DESCRIPTION": "To konto wygasło. Sprawdź dane uwierzytelniające w ustawieniach listy odtwarzania lub usuń ją."
},
"UNAUTHORIZED": {
"TITLE": "Nieautoryzowany",
"DESCRIPTION": "Sprawdź dane uwierzytelniające w ustawieniach listy odtwarzania lub usuń ją."
},
"NOT_FOUND": {
"TITLE": "Nie znaleziono portalu",
"DESCRIPTION": "Sprawdź dane uwierzytelniające i URL portalu w ustawieniach listy odtwarzania lub usuń ją."
},
"EMPTY_CATEGORY": {
"TITLE": "Pusta kategoria",
"DESCRIPTION": "Ta kategoria nie zawiera treści, wybierz inną kategorię lub zmień typ treści"
},
"UNKNOWN_ERROR": {
"TITLE": "Coś poszło nie tak",
"DESCRIPTION": "Nieznany błąd, spróbuj ponownie później"
},
"PLAYLIST_SETTINGS": "Ustawienia listy odtwarzania",
"HOME": "Strona główna",
"DELETE": "Usuń"
},
"EMPTY_LIST_VIEW": {
"NO_SEARCH_RESULTS": "Nic nie znaleziono, spróbuj zmienić zapytanie wyszukiwania"
},
"STREAM_URL_COPIED": "URL strumienia skopiowany do schowka",
"COPY_STREAM_URL": "Kopiuj URL strumienia",
"SEARCH_VIEW": {
"RESULTS_FOUND": "Znaleziono {{count}} wyników",
"NO_RESULTS_FOR": "Brak wyników dla „{{term}}”"
}
},
"INFORMATION": "Informacje",
"REMOTE_CONTROL": {
"TITLE": "Zdalne sterowanie",
"UP_CHANNEL": "Kanał w górę",
"DOWN_CHANNEL": "Kanał w dół",
"HEADER": "Zdalne sterowanie IPTVNator",
"FOOTER": "Zdalne sterowanie IPTVNator"
},
"WORKSPACE": {
"SHELL": {
"GO_TO_DASHBOARD": "Back to dashboard",
"GO_TO_SOURCES": "Go to Sources",
"DROP_OVERLAY_TITLE": "Drop to add playlist",
"DROP_OVERLAY_BODY": "Release an .m3u or .m3u8 file anywhere in the workspace to import it.",
"DROP_OVERLAY_REJECTED_BODY": "Please drop an .m3u or .m3u8 file. Press Esc to dismiss.",
"DROP_OVERLAY_REJECTED_UNSUPPORTED": "Unsupported file type",
"DROP_OVERLAY_REJECTED_EMPTY": "That file is empty",
"DROP_OVERLAY_REJECTED_READ_ERROR": "Could not read that file",
"DROP_IMPORT_SUCCESS": "Importing \"{{title}}\"…",
"COMMANDS": {
"ADD_PLAYLIST_M3U_LABEL": "Add M3U playlist",
"ADD_PLAYLIST_M3U_DESCRIPTION": "Open add dialog on the M3U file or URL tab",
"ADD_PLAYLIST_XTREAM_LABEL": "Add Xtream Codes playlist",
"ADD_PLAYLIST_XTREAM_DESCRIPTION": "Open add dialog on the Xtream Codes tab",
"ADD_PLAYLIST_STALKER_LABEL": "Add Stalker portal",
"ADD_PLAYLIST_STALKER_DESCRIPTION": "Open add dialog on the Stalker Portal tab"
},
"EXTERNAL_PLAYBACK_CLOSE": "Close player"
},
"GLOBAL_FAVORITES": {
"NO_PLAYLISTS_TITLE": "No favorites to show",
"NO_PLAYLISTS_BODY": "Add a playlist to start collecting favorites from live channels, movies, and series.",
"NO_ITEMS_TITLE": "No favorites yet",
"NO_ITEMS_BODY": "Tap the star icon on any channel, movie, or series to save it here."
},
"GLOBAL_RECENT": {
"NO_PLAYLISTS_TITLE": "Nothing watched yet",
"NO_PLAYLISTS_BODY": "Add a playlist and your watching history will appear here.",
"NO_ITEMS_TITLE": "Nothing watched yet",
"NO_ITEMS_BODY": "Start watching anything from your library and it will show up here."
}
},
"DOWNLOADS": {
"NO_PLAYLISTS_TITLE": "Add a playlist to start downloading",
"NO_PLAYLISTS_BODY": "Once you add a playlist, you can save movies and episodes here for offline playback.",
"NO_ITEMS_BODY": "Use the download button on any movie or episode to save it for offline playback.",
"NO_FILTER_MATCH": "No downloads match the current filter",
"NO_FILTER_MATCH_HINT": "Try a different search term"
}
}
+458
View File
@@ -0,0 +1,458 @@
{
"CLOSE": "Fechar",
"PLAYLISTS": "Playlists",
"HOME": {
"TITLE": "IPTVnator",
"SUBTITLE": "Por favor, selecione uma playlist da lista ou adicione uma nova playlist",
"TABS": {
"RECENTLY_ADDED": "Playlists adicionadas recentemente",
"FILE_UPLOAD": "Adicionar via upload de arquivo",
"URL_UPLOAD": "Adicionar via URL",
"TEXT_IMPORT": "Importar do texto",
"XTREME_IMPORT": "Adicionar Código Xtreme",
"STALKER_PORTAL_IMPORT": "Adicionar Portal Stalker"
},
"PLAYLISTS": {
"NO_PLAYLISTS": "Nenhuma playlist foi adicionada",
"ADD_FIRST": "Por favor, adicione sua primeira playlist",
"WELCOME_TITLE": "Bem-vindo ao IPTVnator",
"WELCOME_DESCRIPTION": "Comece sua jornada de streaming adicionando sua primeira playlist. Conecte-se ao seu serviço de IPTV preferido e aproveite TV ao vivo, filmes e séries.",
"ADD_YOUR_FIRST": "Adicionar sua primeira playlist",
"FEATURE_M3U": "Arquivos M3U/M3U8",
"FEATURE_XTREAM": "Xtream Codes",
"FEATURE_STALKER": "Portal Stalker",
"NO_RESULTS_TITLE": "Nenhuma playlist encontrada",
"NO_RESULTS_DESCRIPTION": "Nenhuma playlist corresponde à sua pesquisa. Tente ajustar os termos de pesquisa ou limpe o filtro para ver todas as playlists.",
"ADDED_VIA_URL": "Adicionado via upload de URL. URL:",
"ADDED_VIA_FILE": "Adicionado via upload de arquivo",
"XTREAM_PLAYLIST": "Playlist Xtream",
"STALKER_PORTAL": "Portal Stalker",
"CHANNELS": "Canais",
"ADDED": "Adicionado",
"SHOW_DETAILS": "Mostrar detalhes da playlist",
"REMOVE": "Remover playlist",
"SEARCH_PLAYLISTS": "Pesquisar playlists por título",
"AUTO_REFRESH_ENABLED": "Atualização automática ativada",
"INFO_DIALOG": {
"PLAYLIST_DETAILS": "Detalhes da playlist",
"TITLE": "Título",
"FROM_URL": "Adicionado da URL",
"IMPORT_DATE": "Data de importação",
"CHANNELS": "Número de canais",
"CLOSE": "Fechar",
"SAVE": "Salvar",
"USER_AGENT": "User agent",
"ORIGINAL_FILENAME": "Nome original do arquivo",
"FILE_PATH": "Caminho do arquivo",
"UPDATE_FAILED": "A última atualização da playlist falhou",
"AUTO_UPDATE": "Atualização automática",
"AUTO_UPDATE_DESCRIPTION": "Se a função de atualização automática estiver ativada, a playlist será atualizada automaticamente cada vez que o aplicativo for iniciado.",
"CUSTOM_USER_AGENT": "Alguns provedores de IPTV precisam de um user-agent específico para reproduzir sua playlist.",
"EXPORT_PLAYLIST": "Exportar playlist como m3u",
"SERVER_URL": "URL do servidor",
"USERNAME": "Nome de usuário",
"PASSWORD": "Senha",
"MAC_ADDRESS": "Endereço Mac",
"PLAYLIST_EXPORT_SUCCESS": "Playlist foi exportada com sucesso.",
"PLAYLIST_EXPORT_ERROR": "Erro: Falha ao exportar a playlist."
},
"REMOVE_DIALOG": {
"TITLE": "Remover playlist",
"MESSAGE": "Tem certeza de que deseja excluir esta playlist completamente?",
"SUCCESS": "Playlist foi removida com sucesso"
},
"UPDATED": "Atualizado",
"REFRESH": "Atualizar playlist",
"REFRESH_XTREAM": "Atualizar playlist Xtream do servidor",
"REFRESH_XTREAM_DIALOG": {
"TITLE": "Atualizar playlist Xtream",
"MESSAGE": "Isso excluirá as categorias e streams armazenados localmente e reimportará tudo do servidor remoto. Seus favoritos e itens visualizados recentemente serão preservados. Deseja continuar?",
"STARTED": "Atualização iniciada. Navegando para a playlist...",
"ERROR": "Falha ao atualizar a playlist. Tente novamente."
},
"AUTO_REFRESH_UPDATE_SUCCESS": "Sucesso! As playlists foram atualizadas com sucesso",
"GLOBAL_FAVORITES": "Favoritos globais",
"GLOBAL_FAVORITES_DESCRIPTION": "Playlist gerada automaticamente com favoritos agregados de todas as playlists",
"MY_PLAYLISTS": "Minhas playlists",
"MY_PLAYLISTS_SUBTITLE": "todas as playlists disponíveis",
"PLAYLIST_UPDATE_SUCCESS": "Sucesso! A playlist foi atualizada com sucesso.",
"PLAYLIST_UPDATE_ERROR": "Erro ao atualizar detalhes da playlist.",
"FEATURE_M3U_LABEL": "Add an M3U file or URL",
"FEATURE_XTREAM_LABEL": "Connect via Xtream Codes",
"FEATURE_STALKER_LABEL": "Connect to a Stalker portal",
"VALUE_PROPS_LABEL": "What you can do",
"VALUE_PROP_LIVE": "Live TV with EPG",
"VALUE_PROP_VOD": "Movies & Series",
"VALUE_PROP_MULTISOURCE": "Multi-source library",
"VALUE_PROP_OFFLINE": "Offline downloads",
"DASHBOARD_WELCOME_TAGLINE": "Your IPTV library, in one place.",
"FEATURE_LIVE_TITLE": "Live TV",
"FEATURE_LIVE_DESC": "Stream live channels with full schedule.",
"FEATURE_VOD_TITLE": "Movies & Series",
"FEATURE_VOD_DESC": "On-demand library with covers and details.",
"FEATURE_EPG_TITLE": "EPG & Catch-up",
"FEATURE_EPG_DESC": "Program guide and time-shifted playback.",
"FEATURE_OFFLINE_TITLE": "Offline downloads",
"FEATURE_OFFLINE_DESC": "Save movies and episodes for later.",
"SOURCES_WELCOME_TITLE": "Add your first playlist",
"SOURCES_WELCOME_BODY": "Pick a source type below to get started.",
"SOURCE_M3U_NEEDS": "Local file or URL pointing to an M3U/M3U8 playlist.",
"SOURCE_M3U_ADD": "Add M3U",
"SOURCE_XTREAM_NEEDS": "Username, password and server URL from your provider.",
"SOURCE_XTREAM_ADD": "Add Xtream",
"SOURCE_STALKER_NEEDS": "Portal URL and MAC address (Ministra-compatible).",
"SOURCE_STALKER_ADD": "Add Stalker",
"CONTENT_LIVE": "Live",
"CONTENT_VOD": "Movies",
"CONTENT_SERIES": "Series",
"CONTENT_EPG": "EPG",
"DASHBOARD_WELCOME_DESCRIPTION": "Connect M3U files, Xtream Codes, or Stalker portals — then enjoy live TV, movies and series on every screen."
},
"FILE_UPLOAD": {
"DRAG_DROP": "Arraste e solte os arquivos aqui",
"OR": "ou",
"CHOOSE_PLAYLIST": "escolha uma playlist",
"REJECTED": "O arquivo foi rejeitado, formato de arquivo não suportado {{filename}}."
},
"URL_UPLOAD": {
"PLAYLIST_URL": "URL da playlist (m3u, m3u8)",
"ADD_PLAYLIST": "Adicionar playlist",
"CORS_NOTE": "Nota: Para evitar problemas de CORS neste ponto, o aplicativo usa um serviço de Proxy CORS público. Se você deseja enviar uma playlist com dados confidenciais, é mais seguro importá-la de um arquivo."
},
"TEXT_IMPORT": {
"LABEL": "Inserir playlist m3u(8) como texto",
"BUTTON_LABEL": "Importar"
},
"XTREAM_PLAYLIST": {
"TITLE": "Título da playlist",
"SERVER_URL": "URL do servidor",
"USERNAME": "Nome de usuário",
"PASSWORD": "Senha",
"ADD": "Adicionar",
"TEST_CREDENTIALS": "Testar credenciais",
"URL_VALIDATION_ERROR": "Deve ser uma URL válida com protocolo (por exemplo, http://example.com ou https://example.com:4324)"
},
"STALKER_PORTAL": {
"TITLE": "Título",
"MAC_ADDRESS": "Endereço Mac",
"SERVER_URL": "URL do servidor",
"URL_VALIDATION_ERROR": "Deve ser uma URL válida com protocolo (por exemplo, http://example.com/c ou https://example.com/stalker_portal/c)",
"ADD": "Adicionar"
},
"FILTER_BY_NAME": "Filtrar por nome",
"FILTER_BY_TYPE": "Filtrar por tipo",
"SORT_PLAYLISTS": "Ordenar playlists",
"SORT_BY": "Ordenar por",
"SORT_OPTIONS": {
"NAME_ASC": "Nome (A-Z)",
"NAME_DESC": "Nome (Z-A)",
"NEWEST": "Data de adição (Mais recente primeiro)",
"OLDEST": "Data de adição (Mais antigo primeiro)"
},
"IMPORTED_AS_TEXT": "Importado como texto",
"PARSING_ERROR": "Erro: Falha na análise, não é uma playlist válida:"
},
"SETTINGS": {
"TITLE": "Configurações",
"SUBTITLE": "Altere a configuração do aplicativo",
"DESCRIPTION": "Adapte as opções da lista abaixo e confirme com o botão salvar alterações",
"EPG_URL_LABEL": "URL do EPG (*.xml ou *.xml.gz)",
"EPG_URL_PLACEHOLDER": "Insira uma URL",
"REFRESH_EPG": "Atualizar EPG",
"REFRESH_ALL_EPG": "Atualizar tudo",
"REMOVE_EPG_SOURCE": "Remover fonte EPG",
"EPG_STATUS_FRESH": "Atualizado",
"EPG_STATUS_STALE": "Necessita atualização",
"EPG_STATUS_ERROR": "Falha",
"VIDEO_PLAYER_LABEL": "Reprodutor de vídeo",
"VIDEO_PLAYER_PLACEHOLDER": "Selecione uma opção",
"VERSION": "Versão",
"SAVE_CHANGES": "Salvar alterações",
"BACK_TO_HOME": "Voltar",
"NEW_VERSION_AVAILABLE": "Há uma nova versão disponível",
"LATEST_VERSION": "Você está usando a versão mais recente",
"STREAM_FORMAT": "Formato de stream",
"LANGUAGE": "Idioma",
"SETTINGS_SAVED": "Sucesso! A configuração foi salva.",
"THEME": "Tema visual",
"SHOW_CAPTIONS": "Mostrar legendas",
"ADD_EPG_SOURCE": "Adicionar fonte EPG",
"EPG_URL_ERROR": "O valor não é uma URL válida",
"VIDEO_PLAYER_DESCRIPTION": "Selecionar reprodutor de vídeo padrão",
"STREAM_FORMAT_DESCRIPTION": "Selecionar formato de stream padrão (xtream)",
"LANGUAGE_DESCRIPTION": "Selecionar idioma do aplicativo",
"THEME_DESCRIPTION": "Selecionar tema visual do aplicativo",
"SHOW_CAPTIONS_DESCRIPTION": "Mostrar ou ocultar legendas por padrão",
"VERSION_DESCRIPTION": "Versão atual do aplicativo",
"EPG_NOTE": "Atualmente, o EPG está disponível apenas na versão baseada em electron do IPTVnator.",
"EPG_NOTE_URL_TEXT": "Verifique aqui",
"IMPORT_EXPORT_DATA": "Importar/exportar playlists",
"IMPORT_EXPORT_DATA_DESCRIPTION": "Exportar ou importar playlists no formato JSON usado no aplicativo.",
"IMPORT_DATA": "Importar",
"EXPORT_DATA": "Exportar",
"REMOVE_ALL": "Delete all playlists and playlist data",
"REMOVE_ALL_BUTTON": "Delete all",
"REMOVE_ALL_DESCRIPTION": "Delete every M3U, Xtream, and Stalker playlist stored in the app.",
"REMOVE_DIALOG": {
"TITLE": "Delete all playlists?",
"MESSAGE": "Delete all {{count}} playlists from the app. This also removes stored playlist data on this device.",
"SUMMARY_TITLE": "Playlist sources",
"CONSEQUENCES_TITLE": "This also removes",
"CONSEQUENCE_FAVORITES": "Favorites saved for these playlists",
"CONSEQUENCE_RECENTLY_VIEWED": "Recently viewed history",
"CONSEQUENCE_PLAYBACK": "Saved playback positions",
"CONSEQUENCE_DOWNLOADS": "Download history entries linked to those playlists",
"CONSEQUENCE_XTREAM_CACHE": "Imported Xtream categories and locally cached content",
"BACKUP_HINT": "Use Export first if you want a restorable backup before deleting.",
"CONFIRM": "Delete everything"
},
"IMPORT_ERROR": "Erro de importação, tente com outro arquivo.",
"PLAYLISTS_REMOVED": "All playlists and playlist data were removed.",
"MPV_PLAYER_PATH_LABEL": "Caminho do mpv",
"MPV_PLAYER_PATH_DESCRIPTION": "Defina o caminho para o reprodutor mpv em seu sistema. Ele usará o caminho fornecido para um binário mpv em vez de usar o encontrado em $PATH.",
"MPV_PLAYER_PATH": "Caminho do reprodutor mpv",
"VLC_PLAYER_PATH_LABEL": "Caminho do VLC",
"VLC_PLAYER_PATH_DESCRIPTION": "Defina o caminho para o reprodutor VLC em seu sistema. Ele usará o caminho fornecido para um binário VLC em vez do caminho padrão para o nosso sistema.",
"VLC_PLAYER_PATH": "Caminho do reprodutor VLC",
"REMOTE_CONTROL": "Controle remoto",
"REMOTE_CONTROL_DESCRIPTION": "Ativar controle remoto do aplicativo.",
"REMOTE_CONTROL_PORT": "Porta de controle remoto",
"REMOTE_CONTROL_PORT_DESCRIPTION": "Porta usada para controle remoto do aplicativo. A porta 8765 é usada por padrão.",
"REMOVE_ALL_IN_PROGRESS": "Deleting playlist data…",
"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.",
"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",
"LIGHT_THEME": "Tema claro",
"SYSTEM_THEME": "Tema do sistema"
},
"CHANNELS": {
"SEARCH_CHANNEL": "Pesquisar canal",
"UPLOAD_OR_SELECT_OTHER_PLAYLIST": "Enviar ou selecionar outra playlist",
"ALL_CHANNELS": "Todos os canais",
"GROUPS": "Grupos",
"UNGROUPED": "Não agrupados",
"UNNAMED_CHANNEL": "Canal sem nome",
"FAVORITES": "Favoritos",
"NO_FAVORITES": "Nenhum favorito ainda",
"USE_STAR_TO_FAVORITE": "Use o ícone 'estrela' para adicionar canais aos seus favoritos.",
"REMOVE_FAVORITE": "Remover dos favoritos",
"FAVORITES_UPDATED": "Favoritos foram atualizados!",
"SORT_BY": "Ordenar por",
"SORT_BY_DATE": "Ordenar por Data de Adição (Mais Recente Primeiro)",
"SORT_BY_RATING": "Ordenar por Classificação",
"SORT_BY_NAME": "Ordenar por Nome (A-Z)"
},
"TOP_MENU": {
"OPEN_CHANNELS_LIST": "Abrir lista de canais",
"TOGGLE_FAVORITE_FLAG": "Alternar sinalizador de favorito",
"OPEN_EPG_LIST": "Abrir lista de EPG",
"OPEN_MULTI_EPG": "Abrir visualização Multi-EPG"
},
"EPG": {
"TITLE": "Guia Eletrônico de Programação",
"NEXT_DAY": "Próximo dia",
"PREVIOUS_DAY": "Dia anterior",
"LIVE_NOW": "Ao vivo agora",
"LIVE_STREAM": "Transmissão ao vivo",
"TIMESHIFT_AVAILABLE": "Timeshift está disponível, clique para reproduzir",
"EPG_NOT_AVAILABLE_DATE": "Ooops, EPG não está disponível para a data selecionada",
"EPG_NOT_AVAILABLE_CHANNEL_TITLE": "Ooops, EPG não está disponível para este canal.",
"EPG_NOT_AVAILABLE_CHANNEL_DESCRIPTION": "Adicione/altere a URL da lista de EPG nas configurações do aplicativo.",
"FETCH_EPG": "Buscando dados do EPG...",
"ERROR": "Ooops, EPG não pôde ser carregado.",
"DOWNLOAD_SUCCESS": "EPG foi baixado com sucesso.",
"PROGRAM_DIALOG": {
"PROGRAM_DETAILS": "Detalhes sobre o programa de TV",
"TITLE": "Título",
"CATEGORY": "Categoria",
"PARENTAL_RATING_SYSTEM": "Sistema de classificação de conteúdo televisivo",
"DESCRIPTION": "Descrição",
"LANGUAGE": "Idioma",
"SHOW_PROGRAM_DETAILS": "Mostrar detalhes sobre este programa"
},
"FETCH_SUCCESS": "EPG foi buscado com sucesso"
},
"LANGUAGES": {
"ARABIC": "العربية",
"MOROCCAN_ARABIC": "العربية (اللهجة المغربية)",
"ENGLISH": "English",
"KOREAN": "한국어",
"RUSSIAN": "Русский",
"GERMAN": "Deutsch",
"SPANISH": "Español",
"CHINESE": "简体中文",
"TRADITIONAL_CHINESE": "繁體中文",
"FRENCH": "Français",
"ITALIAN": "Italiano",
"TURKISH": "Türkçe",
"JAPANESE": "日本語",
"DUTCH": "Nederlands",
"BELARUSIAN": "Беларуская",
"POLISH": "Polski",
"PORTUGUESE": "Português",
"GREEK": "Ελληνικά"
},
"YES": "Sim",
"NO": "Não",
"MENU": {
"OPEN": "Abrir menu",
"SUPPORT_ARIA": "Apoie o IPTVnator no GitHub",
"SETTINGS": "Configurações",
"SETTINGS_ARIA": "Abrir configurações",
"BUG_REPORT": "Reportar um bug",
"WHAT_IS_NEW": "O que há de novo",
"ABOUT": "Sobre",
"ABOUT_ARIA": "Sobre o aplicativo",
"SUPPORT_PROJECT": "Apoiar projeto"
},
"ABOUT": {
"TITLE": "Sobre o IPTVnator",
"DESCRIPTION": "Aplicativo reprodutor de IPTV multiplataforma com vários recursos, como suporte a playlists m3u e m3u8, favoritos, guia de TV, arquivo/catchup de TV e muito mais.",
"VERSION": "Versão",
"GITHUB_TOOLTIP": "Repositório ITPVnator no GitHub",
"BUY_ME_A_COFFEE_TOOLTIP": "Compre-me um café",
"TWITTER_TOOLTIP": "Compartilhar no Twitter"
},
"UPDATE_AVAILABLE": "Atualização disponível",
"REFRESH": "Atualizar",
"XTREAM": {
"PLAY": "Reproduzir",
"NAME": "Nome",
"RELEASE_DATE": "Data de lançamento",
"GENRE": "Gênero",
"COUNTRY": "País",
"ACTORS": "Atores",
"DIRECTOR": "Diretor",
"DURATION": "Duração",
"CAST": "Elenco",
"EPISODE_RUN_TIME": "Tempo de execução do episódio",
"RATING": "Classificação",
"IMDB_RATING": " Classificação IMDB",
"KINOPOISK_RATING": "Classificação Kinopoisk",
"DESCRIPTION": "Descrição",
"YEAR": "Ano",
"AGE": "Idade",
"YOUTUBE_TRAILER": "Trailer do YouTube",
"EPISODE": "Episódio"
},
"PORTALS": {
"ALL_CATEGORIES": "Todas as categorias",
"MY_FAVORITES": "Meus favoritos",
"ADD_TO_FAVORITES": "Adicionar aos favoritos",
"REMOVE_FROM_FAVORITES": "Remover dos favoritos",
"REMOVED_FROM_FAVORITES": "Removido dos favoritos",
"ADDED_TO_FAVORITES": "Adicionado aos favoritos",
"SIDEBAR": {
"MAIN": "Principal",
"MOVIES": "Filmes",
"LIVE_TV": "TV ao vivo",
"SERIES": "Séries",
"LIBRARY": "Biblioteca",
"SEARCH": "Pesquisar",
"RECENT": "Recente",
"FAVORITES": "Favoritos",
"HOME": "Início",
"PLAYLIST_INFO": "Informações da playlist",
"ACCOUNT_INFO": "Informações da conta"
},
"ERROR_VIEW": {
"ACCOUNT_EXPIRED": {
"TITLE": "Conta expirada",
"DESCRIPTION": "Esta conta expirou. Verifique as credenciais nas configurações da playlist ou remova-a."
},
"UNAUTHORIZED": {
"TITLE": "Não autorizado",
"DESCRIPTION": "Verifique as credenciais nas configurações da playlist ou remova-a."
},
"NOT_FOUND": {
"TITLE": "Portal não encontrado",
"DESCRIPTION": "Verifique as credenciais e o URL do portal nas configurações da playlist ou remova-o."
},
"EMPTY_CATEGORY": {
"TITLE": "Categoria vazia",
"DESCRIPTION": "Esta categoria não tem conteúdo, selecione outra categoria ou altere o tipo de conteúdo"
},
"UNKNOWN_ERROR": {
"TITLE": "Algo deu errado",
"DESCRIPTION": "Erro desconhecido, tente novamente mais tarde"
},
"NO_CATEGORY_SELECTED": {
"TITLE": "Nenhuma categoria selecionada",
"DESCRIPTION": "Selecione uma categoria para ver o conteúdo"
},
"PLAYLIST_SETTINGS": "Configurações da playlist",
"HOME": "Início",
"DELETE": "Excluir"
},
"EMPTY_LIST_VIEW": {
"TITLE": "Nenhum resultado encontrado",
"NO_SEARCH_RESULTS": "Nada encontrado, tente alterar sua solicitação de pesquisa"
},
"STREAM_URL_COPIED": "URL do stream copiado para a área de transferência",
"COPY_STREAM_URL": "Copiar URL do Stream",
"SELECT_CATEGORY": "Selecione uma categoria",
"SEARCH_VIEW": {
"RESULTS_FOUND": "{{count}} resultados encontrados",
"NO_RESULTS_FOR": "Nenhum resultado encontrado para \"{{term}}\""
}
},
"INFORMATION": "Informação",
"REMOTE_CONTROL": {
"TITLE": "Controle remoto",
"UP_CHANNEL": "Canal acima",
"DOWN_CHANNEL": "Canal abaixo",
"HEADER": "Controle Remoto IPTVNator",
"FOOTER": "Controle Remoto IPTVNator"
},
"WORKSPACE": {
"SHELL": {
"GO_TO_DASHBOARD": "Back to dashboard",
"GO_TO_SOURCES": "Go to Sources",
"DROP_OVERLAY_TITLE": "Drop to add playlist",
"DROP_OVERLAY_BODY": "Release an .m3u or .m3u8 file anywhere in the workspace to import it.",
"DROP_OVERLAY_REJECTED_BODY": "Please drop an .m3u or .m3u8 file. Press Esc to dismiss.",
"DROP_OVERLAY_REJECTED_UNSUPPORTED": "Unsupported file type",
"DROP_OVERLAY_REJECTED_EMPTY": "That file is empty",
"DROP_OVERLAY_REJECTED_READ_ERROR": "Could not read that file",
"DROP_IMPORT_SUCCESS": "Importing \"{{title}}\"…",
"COMMANDS": {
"ADD_PLAYLIST_M3U_LABEL": "Add M3U playlist",
"ADD_PLAYLIST_M3U_DESCRIPTION": "Open add dialog on the M3U file or URL tab",
"ADD_PLAYLIST_XTREAM_LABEL": "Add Xtream Codes playlist",
"ADD_PLAYLIST_XTREAM_DESCRIPTION": "Open add dialog on the Xtream Codes tab",
"ADD_PLAYLIST_STALKER_LABEL": "Add Stalker portal",
"ADD_PLAYLIST_STALKER_DESCRIPTION": "Open add dialog on the Stalker Portal tab"
},
"EXTERNAL_PLAYBACK_CLOSE": "Close player"
},
"GLOBAL_FAVORITES": {
"NO_PLAYLISTS_TITLE": "No favorites to show",
"NO_PLAYLISTS_BODY": "Add a playlist to start collecting favorites from live channels, movies, and series.",
"NO_ITEMS_TITLE": "No favorites yet",
"NO_ITEMS_BODY": "Tap the star icon on any channel, movie, or series to save it here."
},
"GLOBAL_RECENT": {
"NO_PLAYLISTS_TITLE": "Nothing watched yet",
"NO_PLAYLISTS_BODY": "Add a playlist and your watching history will appear here.",
"NO_ITEMS_TITLE": "Nothing watched yet",
"NO_ITEMS_BODY": "Start watching anything from your library and it will show up here."
}
},
"DOWNLOADS": {
"NO_PLAYLISTS_TITLE": "Add a playlist to start downloading",
"NO_PLAYLISTS_BODY": "Once you add a playlist, you can save movies and episodes here for offline playback.",
"NO_ITEMS_BODY": "Use the download button on any movie or episode to save it for offline playback.",
"NO_FILTER_MATCH": "No downloads match the current filter",
"NO_FILTER_MATCH_HINT": "Try a different search term"
}
}
+776
View File
@@ -0,0 +1,776 @@
{
"CLOSE": "Закрыть",
"PLAYLISTS": "Плейлисты",
"HOME": {
"TITLE": "IPTVnator",
"SUBTITLE": "Выберите плейлист из списка, добавьте новый с компьютера или загрузите по ссылке",
"TABS": {
"RECENTLY_ADDED": "Недавно добавленные плейлисты",
"FILE_UPLOAD": "Загрузить с компьютера",
"URL_UPLOAD": "Загрузить по ссылке",
"TEXT_IMPORT": "Импортировать из текста",
"STALKER_PORTAL_IMPORT": "Добавить Stalker портал",
"XTREME_IMPORT": "Добавить Xtreme Code "
},
"PLAYLISTS": {
"NO_PLAYLISTS": "Пока еще не было добавлено ни одного плейлиста",
"ADD_FIRST": "Вы можете добавить плейлисты из соседних вкладок",
"WELCOME_TITLE": "Добро пожаловать в IPTVnator",
"WELCOME_DESCRIPTION": "Начните свое путешествие в мир стриминга, добавив свой первый плейлист. Подключитесь к вашему любимому IPTV-сервису и наслаждайтесь прямыми трансляциями, фильмами и сериалами.",
"ADD_YOUR_FIRST": "Добавить первый плейлист",
"FEATURE_M3U": "Файлы M3U/M3U8",
"FEATURE_XTREAM": "Xtream Codes",
"FEATURE_STALKER": "Stalker портал",
"NO_RESULTS_TITLE": "Плейлисты не найдены",
"NO_RESULTS_DESCRIPTION": "Ни один плейлист не соответствует вашему запросу. Попробуйте изменить поисковый запрос или очистите фильтр, чтобы увидеть все плейлисты.",
"ADDED_VIA_URL": "Был добавлен по ссылке:",
"ADDED_VIA_FILE": "Был загружен с компьютера",
"CHANNELS": "Каналов",
"ADDED": "Добавлен",
"SHOW_DETAILS": "Показать информацию о плейлисте",
"REMOVE": "Удалить плейлист",
"SEARCH_PLAYLISTS": "Поиск по названию плейлиста",
"INFO_DIALOG": {
"PLAYLIST_DETAILS": "Подробная информация о плейлисте",
"TITLE": "Название",
"FROM_URL": "Добавлен по ссылке",
"IMPORT_DATE": "Дата импорта",
"CHANNELS": "Количество каналов",
"CLOSE": "Закрыть",
"SAVE": "Сохранить",
"USER_AGENT": "User agent",
"ORIGINAL_FILENAME": "Имя файла при загрузке",
"FILE_PATH": "Путь к файлу",
"UPDATE_FAILED": "Не удалось обновить плейлист",
"AUTO_UPDATE": "Автообновление",
"AUTO_UPDATE_DESCRIPTION": "Если активирована функция автообновления, список воспроизведения будет обновляться автоматически при каждом запуске приложения.",
"CUSTOM_USER_AGENT": "Некоторые IPTV провайдеры требуют указание определенного пользовательского агента (User Agent) для воспроизведения своего плейлиста.",
"EXPORT_PLAYLIST": "Экспортировать плейлист (m3u)",
"PASSWORD": "Пароль",
"SERVER_URL": "URL-адрес сервера",
"USERNAME": "Имя пользователя",
"MAC_ADDRESS": "MAC-адрес",
"PLAYLIST_EXPORT_SUCCESS": "Плейлист был успешно экспортирован.",
"PLAYLIST_EXPORT_ERROR": "Ошибка: не удалось экспортировать плейлист."
},
"UPDATED": "Обновлен",
"REFRESH": "Обновить плейлист",
"REFRESH_XTREAM": "Обновить Xtream плейлист с сервера",
"REFRESH_XTREAM_DIALOG": {
"TITLE": "Обновить Xtream плейлист",
"MESSAGE": "Это удалит локально кэшированные категории и потоки и повторно импортирует все с удаленного сервера. Ваши избранные и недавно просмотренные элементы будут сохранены. Вы уверены, что хотите продолжить?",
"STARTED": "Обновление начато. Переход к плейлисту...",
"ERROR": "Не удалось обновить плейлист. Пожалуйста, попробуйте снова.",
"IN_PROGRESS": "Плейлист обновляется...",
"COLLECTING_DATA": "Собираются избранные и недавно просмотренные элементы...",
"DELETING_CONTENT": "Удаляется кэшированный контент...",
"DELETING_CATEGORIES": "Удаляются кэшированные категории..."
},
"REMOVE_DIALOG": {
"MESSAGE": "Вы уверены, что хотите удалить этот плейлист?",
"TITLE": "Удалить плейлист",
"SUCCESS": "Плейлист был успешно удален",
"IN_PROGRESS": "Плейлист удаляется...",
"DELETING_FAVORITES": "Удаляется избранное...",
"DELETING_RECENT": "Удаляется недавно просмотренное...",
"DELETING_PROGRESS": "Удаляется прогресс просмотра...",
"DELETING_DOWNLOADS": "Удаляются загрузки...",
"DELETING_CONTENT": "Удаляется кэшированный контент...",
"DELETING_CATEGORIES": "Удаляются категории...",
"DELETING_PLAYLIST": "Удаляется запись плейлиста..."
},
"GLOBAL_FAVORITES": "Все фавориты",
"GLOBAL_FAVORITES_DESCRIPTION": "Автоматически сгенерированный плейлист, включающий в себя фавориты из всех плейлистов",
"MY_PLAYLISTS": "Мои плейлисты",
"MY_PLAYLISTS_SUBTITLE": "Все имеющиеся плейлисты",
"PLAYLIST_UPDATE_SUCCESS": "Плейлист был успешно обновлен!",
"PLAYLIST_UPDATE_ERROR": "Ошибка при обновлении деталей плейлиста.",
"AUTO_REFRESH_UPDATE_SUCCESS": "Успешно! Плейлисты были успешно обновлены",
"AUTO_REFRESH_ENABLED": "Автообновление включено",
"STALKER_PORTAL": "Stalker портал",
"XTREAM_PLAYLIST": "Xtream плейлист",
"FEATURE_M3U_LABEL": "Add an M3U file or URL",
"FEATURE_XTREAM_LABEL": "Connect via Xtream Codes",
"FEATURE_STALKER_LABEL": "Connect to a Stalker portal",
"VALUE_PROPS_LABEL": "What you can do",
"VALUE_PROP_LIVE": "Live TV with EPG",
"VALUE_PROP_VOD": "Movies & Series",
"VALUE_PROP_MULTISOURCE": "Multi-source library",
"VALUE_PROP_OFFLINE": "Offline downloads",
"DASHBOARD_WELCOME_TAGLINE": "Your IPTV library, in one place.",
"FEATURE_LIVE_TITLE": "Live TV",
"FEATURE_LIVE_DESC": "Stream live channels with full schedule.",
"FEATURE_VOD_TITLE": "Movies & Series",
"FEATURE_VOD_DESC": "On-demand library with covers and details.",
"FEATURE_EPG_TITLE": "EPG & Catch-up",
"FEATURE_EPG_DESC": "Program guide and time-shifted playback.",
"FEATURE_OFFLINE_TITLE": "Offline downloads",
"FEATURE_OFFLINE_DESC": "Save movies and episodes for later.",
"SOURCES_WELCOME_TITLE": "Add your first playlist",
"SOURCES_WELCOME_BODY": "Pick a source type below to get started.",
"SOURCE_M3U_NEEDS": "Local file or URL pointing to an M3U/M3U8 playlist.",
"SOURCE_M3U_ADD": "Add M3U",
"SOURCE_XTREAM_NEEDS": "Username, password and server URL from your provider.",
"SOURCE_XTREAM_ADD": "Add Xtream",
"SOURCE_STALKER_NEEDS": "Portal URL and MAC address (Ministra-compatible).",
"SOURCE_STALKER_ADD": "Add Stalker",
"CONTENT_LIVE": "Live",
"CONTENT_VOD": "Movies",
"CONTENT_SERIES": "Series",
"CONTENT_EPG": "EPG",
"DASHBOARD_WELCOME_DESCRIPTION": "Connect M3U files, Xtream Codes, or Stalker portals — then enjoy live TV, movies and series on every screen."
},
"FILE_UPLOAD": {
"DRAG_DROP": "Перетащите файл в эту область",
"OR": "или",
"CHOOSE_PLAYLIST": "выберите плейлист",
"REJECTED": "К сожалению, данный формат файлов не поддерживается {{filename}}."
},
"URL_UPLOAD": {
"PLAYLIST_URL": "Ссылка на плейлист (*.m3u или *.m3u8)",
"ADD_PLAYLIST": "Добавить плейлист",
"CORS_NOTE": "Примечание: Чтобы избежать проблем с CORS, приложение использует публичный CORS-прокси сервис. Если вы хотите загрузить плейлист с конфиденциальными данными, безопаснее импортировать его из файла."
},
"TEXT_IMPORT": {
"LABEL": "Вставьте плейлист формата m3u(8) в данное поле",
"BUTTON_LABEL": "Импортировать"
},
"XTREAM_PLAYLIST": {
"TITLE": "Название плейлиста",
"SERVER_URL": "Сервер URL",
"USERNAME": "Пользователь",
"PASSWORD": "Пароль",
"ADD": "Добавить",
"TEST_CREDENTIALS": "Проверить",
"URL_VALIDATION_ERROR": "Должен быть действительный URL-адрес с протоколом (например, http://example.com или https://example.com:4324)."
},
"STALKER_PORTAL": {
"ADD": "Добавить",
"TITLE": "Название",
"MAC_ADDRESS": "MAC-адрес",
"SERVER_URL": "URL сервера",
"URL_VALIDATION_ERROR": "Должен быть действительный URL-адрес с протоколом (например, http://example.com/c или https://example.com/stalker_portal/c)."
},
"FILTER_BY_TYPE": "Типы плейлистов",
"FILTER_BY_NAME": "Фильтровать по имени",
"FILTER_AND_SORT": "Фильтр и сортировка",
"SORT_PLAYLISTS": "Сортировать плейлисты",
"SORT_BY": "Сортировать по",
"SORT_OPTIONS": {
"NAME_ASC": "Имени (А-Я)",
"NAME_DESC": "Имени (Я-А)",
"NEWEST": "Дате добавления (сначала новые)",
"OLDEST": "Дате добавления (сначала старые)"
},
"PLAYLIST_TYPES": {
"M3U": "M3U (локально, URL, текст)",
"XTREAM": "Xtream",
"STALKER": "Stalker"
},
"IMPORTED_AS_TEXT": "Импортировано как текст",
"PARSING_ERROR": "Ошибка парсинга, недействительный плейлист:"
},
"SETTINGS": {
"TITLE": "Настройки",
"GENERAL": "Общие",
"GENERAL_SUBTITLE": "Изменение основных параметров приложения",
"PLAYBACK": "Воспроизведение",
"EPG_SOURCES": "Источники EPG",
"EPG_SOURCES_DESCRIPTION": "Добавьте один или несколько URL-адресов источников EPG",
"DATA": "Данные",
"ABOUT": "О приложении",
"NAV_GENERAL": "Общие",
"NAV_PLAYBACK": "Плеер",
"NAV_EPG": "EPG",
"NAV_REMOTE": "Пульт",
"NAV_DATA": "Данные",
"NAV_ABOUT": "Инфо",
"APP_PREFERENCES": "Параметры приложения",
"HERO_EYEBROW": "Настройки рабочей области",
"HERO_TITLE": "Настройте IPTVnator под себя",
"HERO_DESCRIPTION": "Настраивайте воспроизведение, телегид, удалённый доступ и работу с данными в одном месте, не теряя стиль текущего рабочего пространства.",
"SUBTITLE": "Здесь можно изменить общие настройки приложения",
"DESCRIPTION": "Закончив настройку, не забудьте подтвердить новые настройки кнопкой 'Сохранить'",
"EPG_URL_LABEL": "Ссылка на программу каналов (EPG) (*.xml или *.xml.gz)",
"EPG_URL_PLACEHOLDER": "Введите ссылку",
"REFRESH_EPG": "Обновить программу каналов (EPG)",
"REFRESH_ALL_EPG": "Обновить все",
"REMOVE_EPG_SOURCE": "Удалить источник EPG",
"EPG_STATUS_FRESH": "Актуально",
"EPG_STATUS_STALE": "Требует обновления",
"EPG_STATUS_ERROR": "Ошибка",
"VIDEO_PLAYER_LABEL": "Видеоплеер",
"PLAYER_HTML5": "HTML5-плеер",
"PLAYER_VIDEOJS": "Video.js-плеер",
"PLAYER_ARTPLAYER": "ArtPlayer",
"PLAYER_MPV": "MPV-плеер",
"PLAYER_VLC": "VLC",
"VIDEO_PLAYER_PLACEHOLDER": "Выберите из списка",
"VERSION": "Версия приложения",
"SAVE_CHANGES": "Сохранить",
"BACK_TO_HOME": "Назад",
"NEW_VERSION_AVAILABLE": "Доступна новая версия приложения",
"LATEST_VERSION": "Вы используете последнюю версию приложения",
"STREAM_FORMAT": "Формат потока",
"LANGUAGE": "Язык",
"SETTINGS_SAVED": "Новые настройки были успешно сохранены!",
"THEME": "Тема оформления",
"SHOW_CAPTIONS": "Отображать субтитры",
"SHOW_DASHBOARD": "Показывать панель",
"SHOW_DASHBOARD_DESCRIPTION": "Оставить Dashboard доступным в боковой панели рабочего пространства. Если отключить, первой страницей будет Источники.",
"ADD_EPG_SOURCE": "Добавить источник EPG",
"CLEAR_EPG_DATA": "Очистить данные EPG",
"CLEAR_EPG_DIALOG": {
"TITLE": "Очистить данные EPG",
"MESSAGE": "Вы уверены, что хотите удалить все данные EPG из базы данных? Это удалит все кэшированные телепрограммы."
},
"EPG_DATA_CLEARED": "Данные EPG очищены",
"EPG_DATA_CLEAR_FAILED": "Не удалось очистить данные EPG. Попробуйте ещё раз.",
"CLEARING_EPG_DATA": "Очистка…",
"EPG_URL_ERROR": "Введенное значение не является URL-адресом.",
"VIDEO_PLAYER_DESCRIPTION": "Выбрать стандартный видео плеер",
"STREAM_FORMAT_DESCRIPTION": "Выбрать формат потока по умолчанию (Xtream)",
"LANGUAGE_DESCRIPTION": "Выбрать язык приложения",
"THEME_DESCRIPTION": "Выбрать визуальную тему оформления",
"STARTUP_BEHAVIOR": "Начальный экран",
"STARTUP_BEHAVIOR_DESCRIPTION": "Выберите, должен ли IPTVnator открывать первый доступный экран рабочего пространства или восстанавливать последний экран уровня раздела. Первый экран означает Dashboard, если он включён, иначе Источники.",
"STARTUP_BEHAVIOR_FIRST_VIEW": "Первый доступный экран",
"STARTUP_BEHAVIOR_RESTORE_LAST_VIEW": "Восстановить последний экран",
"SHOW_CAPTIONS_DESCRIPTION": "Показать или скрыть субтитры по умолчанию.",
"VERSION_DESCRIPTION": "Текущая версия приложения",
"ABOUT_SUBTITLE": "Версия, ссылки на проект и способы поддержать IPTVnator.",
"COMMUNITY": "Проект и сообщество",
"COMMUNITY_DESCRIPTION": "Поставьте звезду репозиторию, читайте блог или присоединяйтесь к Telegram-группе для новостей и поддержки.",
"LINK_BLOG": "Блог",
"LINK_GITHUB_DESCRIPTION": "Звезда, issues и возможность поучаствовать",
"LINK_BLOG_DESCRIPTION": "Новости релизов, советы и обновления проекта",
"LINK_TELEGRAM_DESCRIPTION": "Анонсы, сообщество и поддержка",
"SUPPORT_TITLE": "Поддержать проект",
"SUPPORT_DESCRIPTION": "IPTVnator — бесплатный open source проект, разработка ведётся открыто. Если он стал частью вашего дня, небольшая поддержка помогает продолжать развитие — спасибо!",
"SUPPORT_SPONSORS_HINT": "Регулярно или однократно",
"SUPPORT_KOFI_HINT": "Купить кофе",
"EPG_NOTE": "На данный момент EPG доступен только в нативной версии IPTVnator.",
"EPG_NOTE_URL_TEXT": "Подробнее здесь",
"IMPORT_EXPORT_DATA": "Импорт/экспорт плейлистов",
"IMPORT_EXPORT_DATA_DESCRIPTION": "Экспорт или импорт плейлистов в формате JSON, используемом в приложении.",
"IMPORT_DATA": "Импорт",
"EXPORT_DATA": "Экспорт",
"REMOVE_ALL": "Delete all playlists and playlist data",
"REMOVE_ALL_BUTTON": "Delete all",
"REMOVE_ALL_DESCRIPTION": "Delete every M3U, Xtream, and Stalker playlist stored in the app.",
"REMOVE_DIALOG": {
"TITLE": "Delete all playlists?",
"MESSAGE": "Delete all {{count}} playlists from the app. This also removes stored playlist data on this device.",
"SUMMARY_TITLE": "Playlist sources",
"CONSEQUENCES_TITLE": "This also removes",
"CONSEQUENCE_FAVORITES": "Favorites saved for these playlists",
"CONSEQUENCE_RECENTLY_VIEWED": "Recently viewed history",
"CONSEQUENCE_PLAYBACK": "Saved playback positions",
"CONSEQUENCE_DOWNLOADS": "Download history entries linked to those playlists",
"CONSEQUENCE_XTREAM_CACHE": "Imported Xtream categories and locally cached content",
"BACKUP_HINT": "Use Export first if you want a restorable backup before deleting.",
"CONFIRM": "Delete everything"
},
"IMPORT_ERROR": "Ошибка импорта, пожалуйста попробуйте импортировать другой файл.",
"PLAYLISTS_REMOVED": "All playlists and playlist data were removed.",
"VLC_PLAYER_PATH_LABEL": "Путь к VLC плееру",
"VLC_PLAYER_PATH": "Путь к VLC плееру",
"VLC_PLAYER_PATH_DESCRIPTION": "Установите путь к проигрывателю VLC в вашей системе. \nОн будет использовать предоставленный путь к binary файлу VLC вместо пути по умолчанию.",
"MPV_PLAYER_PATH_LABEL": "Путь к mpv плееру",
"MPV_PLAYER_PATH": "Путь к mpv плееру",
"MPV_PLAYER_PATH_DESCRIPTION": "Установите путь к проигрывателю MPV в вашей системе. Он будет использовать предоставленный путь к бинарному файлу MPV вместо найденного в $PATH.",
"MPV_REUSE_INSTANCE_LABEL": "Переиспользовать экземпляр MPV",
"MPV_REUSE_INSTANCE_DESCRIPTION": "Когда включено, одно и то же окно MPV будет использоваться для воспроизведения разных потоков. Когда отключено, каждый поток открывается в новом окне MPV.",
"REMOTE_CONTROL": "Удалённое управление",
"REMOTE_CONTROL_DESCRIPTION": "Включить удалённое управление приложением.",
"REMOTE_CONTROL_PORT": "Порт удалённого управления",
"REMOTE_CONTROL_PORT_DESCRIPTION": "Порт для удалённого управления приложением. По умолчанию используется порт 8765.",
"REMOTE_CONTROL_URL": "URL удалённого управления",
"REMOTE_CONTROL_URL_DESCRIPTION": "Откройте удалённое управление с другого устройства в той же сети.",
"SHOW_QR_CODE": "Показать QR-код",
"STATUS_ENABLED": "Включено",
"STATUS_DISABLED": "Выключено",
"SOURCE_SINGULAR": "источник",
"SOURCE_PLURAL": "источников",
"PORT_RANGE_LABEL": "Порт (1-65535)",
"PORT_REQUIRED": "Порт обязателен",
"PORT_MIN": "Порт должен быть не менее 1",
"PORT_MAX": "Порт должен быть не более 65535",
"PORT_PATTERN": "Разрешены только цифры",
"REMOVE_ALL_IN_PROGRESS": "Deleting playlist data…",
"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.",
"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": "Тёмная тема",
"LIGHT_THEME": "Светлая тема",
"SYSTEM_THEME": "Системная тема"
},
"CHANNELS": {
"SEARCH_CHANNEL": "Поиск каналов",
"UPLOAD_OR_SELECT_OTHER_PLAYLIST": "Загрузить или выбрать другой плейлист",
"ALL_CHANNELS": "Все каналы",
"GROUPS": "Группы",
"UNGROUPED": "Негруппированные",
"UNNAMED_CHANNEL": "Канал без названия",
"FAVORITES": "Избранные",
"NO_FAVORITES": "Избранных каналов пока нет",
"USE_STAR_TO_FAVORITE": "Используйте иконку звезды, чтобы добавлять каналы в избранное",
"REMOVE_FAVORITE": "Удалить из списка фаворитов",
"FAVORITES_UPDATED": "Список фаворитов был обновлен!",
"SELECT_CHANNEL_PLAYBACK": "Пожалуйста, выберите канал для начала воспроизведения",
"SORT_BY": "Сортировать по",
"SORT_BY_DATE": "Сортировать по дате добавления (сначала новые)",
"SORT_BY_RATING": "Сортировать по рейтингу",
"SORT_BY_NAME": "Сортировать по имени (А-Я)"
},
"TOP_MENU": {
"OPEN_CHANNELS_LIST": "Открыть список каналов",
"TOGGLE_FAVORITE_FLAG": "Избранный",
"OPEN_EPG_LIST": "Открыть программу (EPG)",
"OPEN_MULTI_EPG": "Открыть Multi-EPG вид"
},
"EPG": {
"TITLE": "Электронный программный гид",
"NEXT_DAY": "Следующий день",
"PREVIOUS_DAY": "Предыдущий день",
"LIVE_NOW": "Сейчас",
"LIVE_STREAM": "Прямая трансляция",
"TIMESHIFT_AVAILABLE": "Доступна функция архива (timeshift). Нажмите на передачу для воспроизведения.",
"EPG_NOT_AVAILABLE_DATE": "Ой, программа на этот день, к сожалению, отсутствует.",
"EPG_NOT_AVAILABLE_CHANNEL_TITLE": "Программа для этого канала недоступна.",
"EPG_NOT_AVAILABLE_CHANNEL_DESCRIPTION": "Попробуйте изменить или обновить ссылку на EPG в настройках приложения.",
"FETCH_EPG": "Загружаю программу ТВ-передач (EPG)...",
"ERROR": "Ой, не удалось загрузить программу каналов (EPG)",
"DOWNLOAD_SUCCESS": "Программа каналов (EPG) была успешно загружена.",
"FETCH_SUCCESS": "Программа каналов (EPG) была успешно получена",
"PROGRAM_DIALOG": {
"PROGRAM_DETAILS": "Подробности передачи",
"TITLE": "Название",
"CATEGORY": "Категория",
"PARENTAL_RATING_SYSTEM": "Возрастное ограничение",
"DESCRIPTION": "Описание",
"LANGUAGE": "Язык",
"SHOW_PROGRAM_DETAILS": "Показать подробности"
}
},
"LANGUAGES": {
"ARABIC": "العربية",
"MOROCCAN_ARABIC": "العربية (اللهجة المغربية)",
"ENGLISH": "English",
"KOREAN": "한국어",
"RUSSIAN": "Русский",
"GERMAN": "Deutsch",
"SPANISH": "Español",
"CHINESE": "简体中文",
"TRADITIONAL_CHINESE": "繁體中文",
"FRENCH": "Français",
"ITALIAN": "Italiano",
"TURKISH": "Türkçe",
"JAPANESE": "日本語",
"DUTCH": "Nederlands",
"BELARUSIAN": "Беларуская",
"POLISH": "Polski",
"PORTUGUESE": "Português",
"GREEK": "Ελληνικά"
},
"NO": "Нет",
"YES": "Да",
"MENU": {
"OPEN": "Открыть меню",
"SUPPORT_ARIA": "Поддержать IPTVnator на GitHub",
"SETTINGS": "Настройки",
"SETTINGS_ARIA": "Открыть настройки",
"BUG_REPORT": "Сообщить об ошибке",
"WHAT_IS_NEW": "Что нового?",
"ABOUT": "О приложении",
"ABOUT_ARIA": "О приложении",
"SUPPORT_PROJECT": "Поддержать проект"
},
"ABOUT": {
"TITLE": "О приложении",
"DESCRIPTION": "Кроссплатформенное приложение IPTV-плеера с множеством функций, таких как поддержка плейлистов m3u и m3u8, избранное, телегид, ТВ-архив/catchup и многое другое.",
"VERSION": "Версия",
"GITHUB_TOOLTIP": "Репозиторий приложения на GitHub",
"BUY_ME_A_COFFEE_TOOLTIP": "Поддержать разработчика",
"TWITTER_TOOLTIP": "Поделиться на Twitter"
},
"UPDATE_AVAILABLE": "Доступно обновление",
"REFRESH": "Обновить",
"XTREAM": {
"RATING": "Рейтинг",
"RELEASE_DATE": "Дата выпуска",
"ACTORS": "Актеры",
"PLAY": "Воспроизвести",
"OPENING_PLAYER": "Открытие плеера...",
"GENRE": "Жанр",
"DURATION": "Продолжительность",
"COUNTRY": "Страна",
"NAME": "Название",
"DIRECTOR": "Режиссёр",
"CAST": "Бросать",
"EPISODE_RUN_TIME": "Длительность эпизода",
"AGE": "Возраст",
"EPISODE": "Эпизод",
"RESUME": "Продолжить",
"RESTART": "С начала",
"CONTINUE_WATCHING": "Продолжить просмотр",
"WATCHED": "Просмотрено",
"IN_PROGRESS": "В процессе",
"MARK_WATCHED": "Отметить как просмотренное",
"MARK_UNWATCHED": "Отметить как непросмотренное",
"EPISODES_WATCHED": "Просмотрено {{count}} из {{total}} эпизодов",
"YEAR": "Год",
"YOUTUBE_TRAILER": "YouTube-трейлер",
"DESCRIPTION": "Описание",
"KINOPOISK_RATING": "Рейтинг на Кинопоиск",
"IMDB_RATING": "Рейтинг на IMDB",
"ACCOUNT_INFO": {
"TITLE": "Информация об аккаунте",
"USER_INFO": "Информация о пользователе",
"STATUS": "Статус",
"USERNAME": "Имя пользователя",
"ACTIVE_CONNECTIONS": "Активные подключения",
"CREATED": "Создано",
"EXPIRES": "Истекает",
"TRIAL_ACCOUNT": "Пробный аккаунт",
"YES": "Да",
"NO": "Нет",
"ALLOWED_FORMATS": "Разрешенные форматы",
"SERVER_INFO": "Информация о сервере",
"LIVE_TV": "Прямой эфир",
"MOVIES": "Фильмы",
"TV_SERIES": "Сериалы",
"URL": "URL",
"PROTOCOL": "Протокол",
"TIMEZONE": "Часовой пояс",
"SERVER_TIME": "Время сервера",
"PORTS": "Порты",
"HTTP_PORT": "HTTP",
"HTTPS_PORT": "HTTPS",
"RTMP_PORT": "RTMP"
}
},
"PORTALS": {
"ALL_CATEGORIES": "Все категории",
"ADD_TO_FAVORITES": "Добавить в избранное",
"REMOVE_FROM_FAVORITES": "Удалить из избранного",
"MY_FAVORITES": "Избранное",
"COPY_STREAM_URL": "Копировать URL-адрес потока",
"ERROR_VIEW": {
"DELETE": "Удалить",
"IMPORT_CANCELLED": {
"TITLE": "Импорт отменён",
"DESCRIPTION": "Импорт плейлиста был отменён. Повторите попытку, когда захотите снова загрузить этот источник."
},
"ACCOUNT_EXPIRED": {
"TITLE": "Срок действия учетной записи истек",
"DESCRIPTION": "Срок действия этой учетной записи истек. \nПожалуйста, проверьте учетные данные в настройках плейлиста или удалите его."
},
"ACCOUNT_INACTIVE": {
"TITLE": "Учётная запись неактивна",
"DESCRIPTION": "Эта учётная запись неактивна. Проверьте учётные данные в настройках плейлиста или удалите источник."
},
"HOME": "На главную",
"EMPTY_CATEGORY": {
"TITLE": "Пустая категория",
"DESCRIPTION": "В этой категории нет контента. Выберите другую категорию или измените тип контента."
},
"UNAUTHORIZED": {
"TITLE": "Несанкционированный",
"DESCRIPTION": "Пожалуйста, проверьте учетные данные в настройках плейлиста или удалите их."
},
"NOT_FOUND": {
"TITLE": "Портал не найден",
"DESCRIPTION": "Пожалуйста, проверьте учетные данные и URL портала в настройках плейлиста или удалите его."
},
"PORTAL_UNAVAILABLE": {
"TITLE": "Портал недоступен",
"DESCRIPTION": "Не удалось подключиться к порталу. Проверьте URL сервера или повторите попытку позже."
},
"NO_CATEGORY_SELECTED": {
"TITLE": "Категория не выбрана",
"DESCRIPTION": "Пожалуйста, выберите категорию для просмотра содержимого"
},
"UNKNOWN_ERROR": {
"TITLE": "Что-то пошло не так",
"DESCRIPTION": "Неизвестная ошибка. Повторите попытку позже."
},
"PLAYLIST_SETTINGS": "Настройки плейлиста"
},
"STREAM_URL_COPIED": "URL-адрес потока был скопирован в буфер обмена.",
"EMPTY_LIST_VIEW": {
"TITLE": "Результаты не найдены",
"NO_SEARCH_RESULTS": "Ничего не найдено, попробуйте изменить поисковый запрос"
},
"SIDEBAR": {
"MAIN": "Главная",
"MOVIES": "Фильмы",
"LIVE_TV": "Прямой эфир",
"SERIES": "Сериалы",
"LIBRARY": "Библиотека",
"SEARCH": "Поиск",
"RECENT": "Недавние",
"FAVORITES": "Избранное",
"HOME": "Домой",
"PLAYLIST_INFO": "Информация о плейлисте",
"ACCOUNT_INFO": "Информация об аккаунте"
},
"REMOVED_FROM_FAVORITES": "Удалено из избранного",
"ADDED_TO_FAVORITES": "Добавлено в избранное",
"SELECT_CATEGORY": "Выберите категорию",
"PAGE": "Страница",
"SEARCH_VIEW": {
"RESULTS_FOUND": "Найдено {{count}} результатов",
"NO_RESULTS_FOR": "Нет результатов по запросу \"{{term}}\""
}
},
"INFORMATION": "Инфо",
"DOWNLOADS": {
"CLEAR_COMPLETED": "Очистить завершенные",
"CLEAR_COMPLETED_DIALOG": {
"TITLE": "Очистить завершенные загрузки",
"MESSAGE": "Это удалит завершенные, неудачные и отмененные записи из текущего списка загрузок. Уже загруженные на диск файлы удалены не будут."
},
"SOURCE_PLAYLIST_MISSING": "Эту загрузку больше нельзя открыть в библиотеке, потому что исходный плейлист был удален.",
"FILE_NOT_FOUND": "Этот загруженный файл больше недоступен на диске.",
"FILE_ACTION_ERROR": "Не удалось выполнить действие с файлом.",
"COPY_URL": "Копировать URL загрузки",
"URL_COPIED": "URL загрузки скопирован в буфер обмена",
"URL_COPY_FAILED": "Не удалось скопировать URL",
"NO_PLAYLISTS_TITLE": "Add a playlist to start downloading",
"NO_PLAYLISTS_BODY": "Once you add a playlist, you can save movies and episodes here for offline playback.",
"NO_ITEMS_BODY": "Use the download button on any movie or episode to save it for offline playback.",
"NO_FILTER_MATCH": "No downloads match the current filter",
"NO_FILTER_MATCH_HINT": "Try a different search term"
},
"REMOTE_CONTROL": {
"TITLE": "Дистанционное управление",
"UP_CHANNEL": "Канал вверх",
"DOWN_CHANNEL": "Канал вниз",
"HEADER": "IPTVNator Дистанционное управление",
"FOOTER": "IPTVNator Дистанционное управление"
},
"WORKSPACE": {
"FAVORITES_ONLY": "Только избранное",
"SORT_CUSTOM": "Пользовательский порядок",
"SORT_DATE_DESC": "Дата добавления (Сначала новые)",
"SORT_DATE_ASC": "Дата добавления (Сначала старые)",
"SORT_NAME_ASC": "Имя (А-Я)",
"SORT_NAME_DESC": "Имя (Я-А)",
"SORT_LABEL": "Сортировка: ",
"DASHBOARD": {
"CONTINUE_WATCHING": "Продолжить просмотр",
"UNTITLED_SOURCE": "Источник без названия",
"GLOBAL_FAVORITES": "Глобальные избранные",
"REMOVE_FROM_HISTORY": "Удалить из истории",
"RECENT_SOURCES": "Недавно использованные источники",
"MANAGE_ALL": "Управлять всем",
"RECENTLY_WATCHED": "Недавно просмотренные",
"XTREAM_RECENTLY_ADDED": "Недавно добавленные на Xtream",
"NO_HISTORY": "Для этого фильтра элементы не найдены.",
"NO_HISTORY_HINT": "История просмотра появится здесь, как только вы начнете воспроизводить контент из своих плейлистов.",
"XTREAM": "Xtream",
"STALKER": "Stalker",
"M3U": "M3U",
"STALKER_PORTAL": "Портал Stalker",
"PROVIDER": "Провайдер",
"TYPE_LIVE": "ТВ",
"TYPE_MOVIE": "Фильм",
"TYPE_SERIES": "Сериал",
"NOT_YET_SYNCED": "Еще не синхронизировано"
},
"SHELL": {
"BRAND_ALT": "IPTVnator",
"RAIL_DASHBOARD": "Панель",
"OPEN_DASHBOARD": "Открыть панель",
"RAIL_SOURCES": "Источники",
"OPEN_SOURCES": "Открыть источники",
"RAIL_SETTINGS": "Настройки",
"OPEN_SETTINGS": "Открыть настройки",
"RAIL_LIBRARY": "Библиотека",
"RAIL_MOVIES": "Фильмы",
"RAIL_LIVE": "ТВ",
"RAIL_SERIES": "Сериалы",
"RAIL_RECENTLY_ADDED": "Недавно добавленные",
"RAIL_SEARCH": "Расширенный поиск",
"RAIL_RECENT": "Недавно просмотренные",
"RAIL_FAVORITES": "Избранное",
"RAIL_DOWNLOADS": "Загрузки",
"RAIL_ALL_CHANNELS": "Все каналы",
"RAIL_GROUPS": "Группы",
"RAIL_CONTEXT_ACTIONS": "Действия раздела",
"SEARCH_LABEL": "Поиск",
"SEARCH_SOURCES_PLACEHOLDER": "Искать источники (все плейлисты)...",
"SEARCH_PLAYLIST_PLACEHOLDER": "Искать в этом плейлисте...",
"SEARCH_SECTION_PLACEHOLDER": "Искать в этом разделе...",
"FILTER_SECTION_PLACEHOLDER": "Фильтровать этот раздел...",
"SEARCH_STATUS_LOADED_ONLY": "Только загруженные каналы",
"COMMAND_PALETTE_SHORTCUT": "Палитра команд (Ctrl/Cmd+K)",
"OPEN_COMMAND_PALETTE": "Открыть палитру команд",
"ADD_PLAYLIST_ALL": "Добавить плейлист (все плейлисты)",
"ADD_PLAYLIST": "Добавить плейлист",
"OPEN_DOWNLOADS": "Открыть загрузки",
"OPEN_CONTEXT_ACTIONS": "Открыть действия раздела",
"NO_SECTION_ACTIONS": "Для этого раздела нет действий",
"PLAYLIST_INFO": "Информация о плейлисте",
"ACCOUNT_INFO": "Информация об аккаунте",
"REFRESH_PLAYLIST": "Обновить плейлист",
"CLEAR_COMPLETED_DOWNLOADS_ALL": "Очистить завершенные загрузки (все плейлисты)",
"CLEAR_COMPLETED_DOWNLOADS_ALL_ARIA": "Очистить завершенные загрузки для всех плейлистов",
"CLEAR_COMPLETED_DOWNLOADS_THIS_PLAYLIST": "Очистить завершенные загрузки (этот плейлист)",
"CLEAR_COMPLETED_DOWNLOADS_THIS_PLAYLIST_ARIA": "Очистить завершенные загрузки для этого плейлиста",
"CLEAR_RECENTLY_VIEWED_SECTION": "Очистить недавно просмотренное",
"CLEAR_RECENTLY_VIEWED_SECTION_ARIA": "Очистить недавно просмотренное для этого раздела",
"CLEAR_RECENTLY_VIEWED_TYPE": "Очистить недавно просмотренное ({{type}})",
"CLEAR_RECENTLY_VIEWED_DIALOG_TITLE": "Очистить недавно просмотренное ({{type}})?",
"CLEAR_RECENTLY_VIEWED_DIALOG_MESSAGE_PLAYLIST": "Все элементы «{{type}}» из этого плейлиста будут удалены из истории просмотров. Это действие нельзя отменить.",
"CLEAR_RECENTLY_VIEWED_DIALOG_MESSAGE_ALL": "Все элементы «{{type}}» из всех плейлистов будут удалены из истории просмотров. Это действие нельзя отменить.",
"CLEAR_FAVORITES_TYPE": "Удалить избранное ({{type}})",
"CLEAR_FAVORITES_DIALOG_TITLE": "Удалить все избранное «{{type}}»?",
"CLEAR_FAVORITES_DIALOG_MESSAGE_PLAYLIST": "Все избранное «{{type}}» из этого плейлиста будет удалено. Это действие нельзя отменить.",
"CLEAR_FAVORITES_DIALOG_MESSAGE_ALL": "Все избранное «{{type}}» из всех плейлистов будет удалено. Это действие нельзя отменить.",
"XTREAM_CODE": "Xtream Code",
"STALKER_PORTAL": "Портал Stalker",
"CHANNELS_COUNT": "{{count}} каналов",
"NO_SOURCES_AVAILABLE": "Нет доступных источников",
"ONE_SOURCE_AVAILABLE": "Доступен 1 источник",
"SOURCES_AVAILABLE": "Доступно источников: {{count}}",
"XTREAM_IMPORT_TITLE": "Синхронизация плейлиста",
"XTREAM_IMPORT_REMOTE_BADGE": "Удалённый источник",
"XTREAM_IMPORT_LOCAL_BADGE": "Локальная библиотека",
"XTREAM_IMPORT_DETAIL_REMOTE": "Ожидание ответа от провайдера.",
"XTREAM_IMPORT_DETAIL_LOCAL": "Подготавливает более быстрые переключения плейлиста при следующем открытии.",
"XTREAM_IMPORT_PREPARING": "Подготовка локальной библиотеки...",
"XTREAM_IMPORT_LOADING": "Получение данных плейлиста из источника...",
"XTREAM_IMPORT_SAVING": "Сохранение данных плейлиста локально...",
"XTREAM_IMPORT_RESTORING_FAVORITES": "Восстановление избранного из локальной библиотеки...",
"XTREAM_IMPORT_RESTORING_RECENT": "Восстановление недавно просмотренного из локальной библиотеки...",
"XTREAM_IMPORT_PROGRESS": "Импорт {{type}}: {{current}} / {{total}}",
"XTREAM_IMPORT_CANCEL": "Остановить синхронизацию",
"XTREAM_IMPORT_CANCELLING": "Остановка синхронизации...",
"COMMANDS": {
"GLOBAL_SEARCH_LABEL": "Искать во всех плейлистах Xtream",
"GLOBAL_SEARCH_DESCRIPTION": "Открыть глобальный поиск",
"PLAYLIST_SEARCH_LABEL": "Расширенный поиск в этом плейлисте",
"PLAYLIST_SEARCH_DESCRIPTION": "Открыть расширенный поиск плейлиста",
"OPEN_GLOBAL_FAVORITES_LABEL": "Открыть глобальные избранные",
"OPEN_GLOBAL_FAVORITES_DESCRIPTION": "Перейти к объединенному избранному",
"OPEN_DOWNLOADS_LABEL": "Открыть загрузки",
"OPEN_DOWNLOADS_DESCRIPTION": "Перейти к представлению загрузок",
"OPEN_GLOBAL_RECENT_LABEL": "Открыть недавно просмотренные",
"OPEN_GLOBAL_RECENT_DESCRIPTION": "Открыть глобальную страницу недавно просмотренного",
"OPEN_SETTINGS_LABEL": "Открыть настройки",
"OPEN_SETTINGS_DESCRIPTION": "Перейти к настройкам приложения",
"OPEN_SOURCES_LABEL": "Управление источниками",
"OPEN_SOURCES_DESCRIPTION": "Перейти к управлению источниками",
"OPEN_DASHBOARD_LABEL": "Открыть панель",
"OPEN_DASHBOARD_DESCRIPTION": "Перейти к панели управления",
"ADD_PLAYLIST_LABEL": "Добавить источник",
"ADD_PLAYLIST_DESCRIPTION": "Открыть диалог добавления плейлиста",
"REFRESH_PLAYLIST_LABEL": "Обновить плейлист",
"REFRESH_PLAYLIST_DESCRIPTION": "Синхронизировать данные с источника",
"PLAYLIST_INFO_LABEL": "Сведения о плейлисте",
"PLAYLIST_INFO_DESCRIPTION": "Показать информацию о текущем плейлисте",
"ACCOUNT_INFO_LABEL": "Информация об аккаунте",
"ACCOUNT_INFO_DESCRIPTION": "Показать данные аккаунта Xtream",
"OPEN_VIEW_DESCRIPTION": "Перейти к разделу {{view}}",
"CLEAR_CURRENT_VIEW_DESCRIPTION": "Очистить все видимые элементы «{{type}}» в этом представлении",
"OPEN_MULTI_EPG_DESCRIPTION": "Открыть представление Multi-EPG",
"GO_TO_VOD_LABEL": "Фильмы",
"GO_TO_VOD_DESCRIPTION": "Перейти к разделу фильмов",
"GO_TO_LIVE_LABEL": "Прямой эфир",
"GO_TO_LIVE_DESCRIPTION": "Перейти к разделу ТВ",
"GO_TO_SERIES_LABEL": "Сериалы",
"GO_TO_SERIES_DESCRIPTION": "Перейти к разделу сериалов",
"ADD_PLAYLIST_M3U_LABEL": "Add M3U playlist",
"ADD_PLAYLIST_M3U_DESCRIPTION": "Open add dialog on the M3U file or URL tab",
"ADD_PLAYLIST_XTREAM_LABEL": "Add Xtream Codes playlist",
"ADD_PLAYLIST_XTREAM_DESCRIPTION": "Open add dialog on the Xtream Codes tab",
"ADD_PLAYLIST_STALKER_LABEL": "Add Stalker portal",
"ADD_PLAYLIST_STALKER_DESCRIPTION": "Open add dialog on the Stalker Portal tab"
},
"GO_TO_DASHBOARD": "Back to dashboard",
"GO_TO_SOURCES": "Go to Sources",
"DROP_OVERLAY_TITLE": "Drop to add playlist",
"DROP_OVERLAY_BODY": "Release an .m3u or .m3u8 file anywhere in the workspace to import it.",
"DROP_OVERLAY_REJECTED_BODY": "Please drop an .m3u or .m3u8 file. Press Esc to dismiss.",
"DROP_OVERLAY_REJECTED_UNSUPPORTED": "Unsupported file type",
"DROP_OVERLAY_REJECTED_EMPTY": "That file is empty",
"DROP_OVERLAY_REJECTED_READ_ERROR": "Could not read that file",
"DROP_IMPORT_SUCCESS": "Importing \"{{title}}\"…",
"EXTERNAL_PLAYBACK_CLOSE": "Close player"
},
"SOURCES": {
"TITLE": "Источники",
"SUBTITLE": "Фильтрация и сортировка плейлистов",
"TYPE": "Тип",
"ALL": "Все",
"M3U_PLAYLISTS": "M3U плейлисты",
"XTREAM_PLAYLISTS": "Xtream плейлисты",
"STALKER_PLAYLISTS": "Stalker плейлисты",
"ALL_PLAYLISTS": "Все плейлисты",
"PLAYLIST_COUNT_ONE": "1 плейлист",
"PLAYLIST_COUNT_OTHER": "{{count}} плейлистов"
},
"CONTEXT": {
"CATEGORIES": "Категории",
"MOVIE_CATEGORIES": "Категории фильмов",
"SERIES_CATEGORIES": "Категории сериалов",
"LIVE_CATEGORIES": "Категории ТВ",
"XTREAM_SYNCING_MOVIES": "Синхронизация категорий фильмов...",
"XTREAM_SYNCING_SERIES": "Синхронизация категорий сериалов...",
"XTREAM_SYNCING_LIVE": "Синхронизация категорий ТВ...",
"XTREAM_SOURCE": "Xtream источник",
"STALKER_PORTAL": "Портал Stalker",
"MANAGE_CATEGORIES": "Управлять категориями",
"LOAD_CATEGORIES_ERROR": "Не удалось загрузить категории",
"LOAD_CATEGORIES_ERROR_HINT": "Повторите попытку или проверьте настройки портала.",
"FILTER_BY_TYPE": "Фильтр по типу",
"ITEM_COUNT_ONE": "1 элемент",
"ITEM_COUNT_OTHER": "{{count}} элементов",
"SEARCH": "Поиск",
"SEARCH_CATEGORIES": "Поиск категорий"
},
"COMMAND_PALETTE": {
"TITLE": "Палитра команд",
"SUBTITLE": "Глобальные и контекстные действия",
"SEARCH_PLACEHOLDER": "Введите текст для фильтрации команд",
"SEARCH_LABEL": "Фильтровать команды",
"EMPTY": "Команды не найдены",
"GROUP_GLOBAL": "Глобальные действия",
"GROUP_PLAYLIST": "Этот плейлист",
"GROUP_VIEW": "Текущее представление",
"GROUP_SECTION": "Этот раздел"
},
"GLOBAL_FAVORITES": {
"TITLE": "Глобальные избранные",
"SUBTITLE": "Live TV из всех плейлистов",
"SEARCH_PLACEHOLDER": "Поиск в избранном...",
"NO_RESULTS": "Ничего не найдено",
"NO_RESULTS_HINT": "Попробуйте другой поисковый запрос",
"EMPTY_TITLE": "Пока нет избранных телеканалов",
"EMPTY_HINT": "Добавляйте в избранное live-каналы из плейлистов M3U, Xtream или Stalker, чтобы они появились здесь.",
"EMPTY_PLAYER": "Выберите канал, чтобы начать просмотр",
"UNKNOWN_CHANNEL": "Неизвестно",
"NO_PLAYLISTS_TITLE": "No favorites to show",
"NO_PLAYLISTS_BODY": "Add a playlist to start collecting favorites from live channels, movies, and series.",
"NO_ITEMS_TITLE": "No favorites yet",
"NO_ITEMS_BODY": "Tap the star icon on any channel, movie, or series to save it here."
},
"GLOBAL_RECENT": {
"NO_PLAYLISTS_TITLE": "Nothing watched yet",
"NO_PLAYLISTS_BODY": "Add a playlist and your watching history will appear here.",
"NO_ITEMS_TITLE": "Nothing watched yet",
"NO_ITEMS_BODY": "Start watching anything from your library and it will show up here."
}
}
}
+592
View File
@@ -0,0 +1,592 @@
{
"CLOSE": "Kapat",
"PLAYLISTS": "Oynatma Listeleri",
"HOME": {
"TITLE": "IPTVnator",
"SUBTITLE": "Lütfen listeden bir oynatma listesi seçin veya yeni bir liste ekleyin",
"TABS": {
"RECENTLY_ADDED": "Son Eklenen Listeler",
"FILE_UPLOAD": "Dosya Yükle",
"URL_UPLOAD": "URL ile Ekle",
"TEXT_IMPORT": "Metinden İçe Aktar",
"XTREME_IMPORT": "Xtreme Kodu Ekle",
"STALKER_PORTAL_IMPORT": "Stalker Portalı Ekle"
},
"PLAYLISTS": {
"NO_PLAYLISTS": "Oynatma listesi eklenmedi",
"ADD_FIRST": "Lütfen ilk oynatma listenizi ekleyin",
"WELCOME_TITLE": "IPTVnator'a Hoş Geldiniz",
"WELCOME_DESCRIPTION": "İlk oynatma listenizi ekleyerek yayın yolculuğunuza başlayın. Favori IPTV hizmetinize bağlanın ve canlı TV, film ve dizilerin keyfini çıkarın.",
"ADD_YOUR_FIRST": "İlk Oynatma Listenizi Ekleyin",
"FEATURE_M3U": "M3U/M3U8 Dosyaları",
"FEATURE_XTREAM": "Xtream Kodları",
"FEATURE_STALKER": "Stalker Portalı",
"NO_RESULTS_TITLE": "Oynatma listesi bulunamadı",
"NO_RESULTS_DESCRIPTION": "Aramanızla eşleşen oynatma listesi yok. Arama terimlerinizi değiştirmeyi deneyin veya tüm oynatma listelerini görmek için filtreyi temizleyin.",
"ADDED_VIA_URL": "URL yüklemesi ile eklendi. URL:",
"ADDED_VIA_FILE": "Dosya yüklemesi ile eklendi",
"XTREAM_PLAYLIST": "Xtream oynatma listesi",
"STALKER_PORTAL": "Stalker portalı",
"CHANNELS": "Kanallar",
"ADDED": "Eklendi",
"SHOW_DETAILS": "Oynatma listesi ayrıntılarını göster",
"REMOVE": "Oynatma listesini kaldır",
"SEARCH_PLAYLISTS": "Oynatma listelerini başlığa göre ara",
"INFO_DIALOG": {
"PLAYLIST_DETAILS": "Oynatma Listesi Ayrıntıları",
"TITLE": "Başlık",
"FROM_URL": "URL'den Eklendi",
"IMPORT_DATE": "İçe Aktarma Tarihi",
"CHANNELS": "Kanal Sayısı",
"CLOSE": "Kapat",
"SAVE": "Kaydet",
"USER_AGENT": "Kullanıcı Aracısı",
"ORIGINAL_FILENAME": "Orijinal Dosya Adı",
"FILE_PATH": "Dosya Yolu",
"UPDATE_FAILED": "Son oynatma listesi güncellemesi başarısız oldu",
"AUTO_UPDATE": "Otomatik Güncelleme",
"AUTO_UPDATE_DESCRIPTION": "Otomatik yenileme işlevi etkinleştirilirse, uygulama her başlatıldığında oynatma listesi otomatik olarak güncellenecektir.",
"CUSTOM_USER_AGENT": "Bazı IPTV sağlayıcıları, oynatma listelerini oynatmak için belirli bir kullanıcı aracısına ihtiyaç duyar.",
"EXPORT_PLAYLIST": "Oynatma listesini m3u olarak dışa aktar",
"SERVER_URL": "Sunucu URL'si",
"USERNAME": "Kullanıcı Adı",
"PASSWORD": "Parola",
"MAC_ADDRESS": "MAC Adresi",
"PLAYLIST_EXPORT_SUCCESS": "Oynatma listesi başarıyla dışa aktarıldı.",
"PLAYLIST_EXPORT_ERROR": "Hata: Oynatma listesi dışa aktarılamadı.",
"COPY_URL": "URL'yi panoya kopyala",
"URL_COPIED": "URL panoya kopyalandı"
},
"REMOVE_DIALOG": {
"TITLE": "Oynatma Listesini Kaldır",
"MESSAGE": "Bu oynatma listesini tamamen silmek istediğinizden emin misiniz?",
"SUCCESS": "Oynatma listesi başarıyla kaldırıldı"
},
"UPDATED": "Güncellendi",
"REFRESH": "Oynatma listesini yenile",
"REFRESH_XTREAM": "Xtream oynatma listesini uzaktan yenile",
"REFRESH_XTREAM_DIALOG": {
"TITLE": "Xtream Oynatma Listesini Yenile",
"MESSAGE": "Bu işlem yerel olarak önbelleğe alınmış kategorileri ve yayınları silecek ve her şeyi uzaktan sunucudan yeniden içe aktaracaktır. Favorileriniz ve son izlenen öğeleriniz korunacaktır. Devam etmek istediğinizden emin misiniz?",
"STARTED": "Yenileme başladı. Oynatma listesine gidiliyor...",
"ERROR": "Oynatma listesi yenilenemedi. Lütfen tekrar deneyin."
},
"GLOBAL_FAVORITES": "Tüm Favoriler",
"GLOBAL_FAVORITES_DESCRIPTION": "Tüm oynatma listelerinden oluşan otomatik favori liste",
"MY_PLAYLISTS": "Oynatma Listelerim",
"MY_PLAYLISTS_SUBTITLE": "tüm oynatma listeleri",
"PLAYLIST_UPDATE_SUCCESS": "Başarılı! Oynatma listesi başarıyla güncellendi.",
"PLAYLIST_UPDATE_ERROR": "Oynatma listesi ayrıntıları güncellenirken hata oluştu.",
"AUTO_REFRESH_UPDATE_SUCCESS": "Başarılı! Oynatma listeleri başarıyla güncellendi",
"AUTO_REFRESH_ENABLED": "Otomatik yenileme etkin",
"FEATURE_M3U_LABEL": "Add an M3U file or URL",
"FEATURE_XTREAM_LABEL": "Connect via Xtream Codes",
"FEATURE_STALKER_LABEL": "Connect to a Stalker portal",
"VALUE_PROPS_LABEL": "What you can do",
"VALUE_PROP_LIVE": "Live TV with EPG",
"VALUE_PROP_VOD": "Movies & Series",
"VALUE_PROP_MULTISOURCE": "Multi-source library",
"VALUE_PROP_OFFLINE": "Offline downloads",
"DASHBOARD_WELCOME_TAGLINE": "Your IPTV library, in one place.",
"FEATURE_LIVE_TITLE": "Live TV",
"FEATURE_LIVE_DESC": "Stream live channels with full schedule.",
"FEATURE_VOD_TITLE": "Movies & Series",
"FEATURE_VOD_DESC": "On-demand library with covers and details.",
"FEATURE_EPG_TITLE": "EPG & Catch-up",
"FEATURE_EPG_DESC": "Program guide and time-shifted playback.",
"FEATURE_OFFLINE_TITLE": "Offline downloads",
"FEATURE_OFFLINE_DESC": "Save movies and episodes for later.",
"SOURCES_WELCOME_TITLE": "Add your first playlist",
"SOURCES_WELCOME_BODY": "Pick a source type below to get started.",
"SOURCE_M3U_NEEDS": "Local file or URL pointing to an M3U/M3U8 playlist.",
"SOURCE_M3U_ADD": "Add M3U",
"SOURCE_XTREAM_NEEDS": "Username, password and server URL from your provider.",
"SOURCE_XTREAM_ADD": "Add Xtream",
"SOURCE_STALKER_NEEDS": "Portal URL and MAC address (Ministra-compatible).",
"SOURCE_STALKER_ADD": "Add Stalker",
"CONTENT_LIVE": "Live",
"CONTENT_VOD": "Movies",
"CONTENT_SERIES": "Series",
"CONTENT_EPG": "EPG",
"DASHBOARD_WELCOME_DESCRIPTION": "Connect M3U files, Xtream Codes, or Stalker portals — then enjoy live TV, movies and series on every screen."
},
"FILE_UPLOAD": {
"DRAG_DROP": "Dosyaları buraya sürükleyip bırakın",
"OR": "veya",
"CHOOSE_PLAYLIST": "oynatma listesi seçin",
"REJECTED": "Dosya reddedildi, desteklenmeyen dosya formatı {{filename}}."
},
"URL_UPLOAD": {
"PLAYLIST_URL": "Oynatma listesi URL'si (m3u, m3u8)",
"ADD_PLAYLIST": "Oynatma listesi ekle",
"CORS_NOTE": "Not: CORS sorunlarını önlemek için bu aşamada uygulama, halka açık bir CORS Proxy hizmeti kullanır. Güvenlik nedeniyle hassas verileri içeren bir oynatma listesini yüklemek istiyorsanız, daha güvenli bir seçenek olarak dosyadan içe aktarmayı deneyin."
},
"TEXT_IMPORT": {
"LABEL": "m3u(8) oynatma listesini metin olarak girin",
"BUTTON_LABEL": "İçe Aktar"
},
"XTREAM_PLAYLIST": {
"TITLE": "Oynatma listesi başlığı",
"SERVER_URL": "Sunucu URL'si",
"USERNAME": "Kullanıcı Adı",
"PASSWORD": "Parola",
"ADD": "Ekle",
"TEST_CREDENTIALS": "Kimlik bilgilerini test et",
"URL_VALIDATION_ERROR": "Geçerli bir URL olmalıdır (örn. http://example.com veya https://example.com:4324)"
},
"STALKER_PORTAL": {
"TITLE": "Başlık",
"MAC_ADDRESS": "MAC Adresi",
"SERIAL_NUMBER": "Seri Numarası (İsteğe Bağlı)",
"SERIAL_NUMBER_HINT": "Sağlayıcıya zaten kayıtlıysa kullanın",
"DEVICE_ID_1": "Cihaz Kimliği 1 (İsteğe Bağlı)",
"DEVICE_ID_2": "Cihaz Kimliği 2 (İsteğe Bağlı)",
"DEVICE_ID_HINT": "64 onaltılık karakter - sağlayıcı belirli bir cihaz kimliği gerektiriyorsa kullanın",
"SIGNATURE_1": "İmza 1 (İsteğe Bağlı)",
"SIGNATURE_2": "İmza 2 (İsteğe Bağlı)",
"SIGNATURE_HINT": "64 onaltılık karakter - sağlayıcı cihaz doğrulama imzaları gerektiriyorsa kullanın",
"SERVER_URL": "Sunucu URL'si",
"URL_VALIDATION_ERROR": "Geçerli bir URL olmalıdır (örn. http://example.com/c veya https://example.com/stalker_portal/c)",
"ADD": "Ekle",
"VALIDATING": "Portal doğrulanıyor..."
},
"FILTER_BY_NAME": "İsime göre filtrele",
"FILTER_BY_TYPE": "Türe göre filtrele",
"FILTER_AND_SORT": "Filtrele ve Sırala",
"SORT_PLAYLISTS": "Oynatma listelerini sırala",
"SORT_BY": "Sıralama ölçütü",
"SORT_OPTIONS": {
"NAME_ASC": "İsim (A-Z)",
"NAME_DESC": "İsim (Z-A)",
"NEWEST": "Eklenme tarihi (En yeni önce)",
"OLDEST": "Eklenme tarihi (En eski önce)",
"CUSTOM_ORDER": "Özel sıralama (Sürükle ve Bırak)"
},
"PLAYLIST_TYPES": {
"M3U": "M3U (yerel, url, metin)",
"XTREAM": "Xtream",
"STALKER": "Stalker"
},
"IMPORTED_AS_TEXT": "Metin olarak içe aktarıldı",
"PARSING_ERROR": "Hata: Ayrıştırma başarısız, geçerli bir oynatma listesi değil:"
},
"SETTINGS": {
"TITLE": "Ayarlar",
"SUBTITLE": "Uygulamanın yapılandırmasını değiştir",
"DESCRIPTION": "Lütfen aşağıdaki seçenekleri düzenleyin ve değişiklikleri kaydet düğmesiyle onaylayın",
"EPG_URL_LABEL": "EPG Url (*.xml veya *.xml.gz)",
"EPG_URL_PLACEHOLDER": "URL girin",
"REFRESH_EPG": "EPG'yi yenile",
"REFRESH_ALL_EPG": "Tümünü yenile",
"REMOVE_EPG_SOURCE": "EPG kaynağını kaldır",
"EPG_STATUS_FRESH": "Güncel",
"EPG_STATUS_STALE": "Yenilenmeli",
"EPG_STATUS_ERROR": "Başarısız",
"VIDEO_PLAYER_LABEL": "Video oynatıcı",
"VIDEO_PLAYER_PLACEHOLDER": "Bir seçenek belirleyin",
"VERSION": "Sürüm",
"SAVE_CHANGES": "Değişiklikleri kaydet",
"BACK_TO_HOME": "Ana sayfaya dön",
"NEW_VERSION_AVAILABLE": "Yeni bir sürüm mevcut",
"LATEST_VERSION": "En son sürümü kullanıyorsunuz",
"STREAM_FORMAT": "Yayın Formatı",
"LANGUAGE": "Dil",
"SETTINGS_SAVED": "Başarılı! Yapılandırma kaydedildi.",
"THEME": "Görünüm teması",
"SHOW_CAPTIONS": "Altyazıları göster",
"ADD_EPG_SOURCE": "EPG kaynağı ekle",
"CLEAR_EPG_DATA": "EPG verilerini temizle",
"CLEAR_EPG_DIALOG": {
"TITLE": "EPG verilerini temizle",
"MESSAGE": "Tüm EPG (Elektronik Program Rehberi) verilerini veritabanından silmek istediğinizden emin misiniz? Bu işlem, önbelleğe alınmış tüm program çizelgelerini silecektir."
},
"EPG_DATA_CLEARED": "EPG verileri temizlendi",
"EPG_DATA_CLEAR_FAILED": "EPG verileri temizlenemedi. Lütfen tekrar deneyin.",
"CLEARING_EPG_DATA": "Temizleniyor…",
"EPG_URL_ERROR": "Girilen değer geçerli bir URL değildir",
"VIDEO_PLAYER_DESCRIPTION": "Varsayılan video oynatıcıyı seçin",
"STREAM_FORMAT_DESCRIPTION": "Varsayılan yayın formatını seçin (xtream)",
"LANGUAGE_DESCRIPTION": "Uygulamanın dilini seçin",
"THEME_DESCRIPTION": "Uygulamanın görünüm temasını seçin",
"SHOW_CAPTIONS_DESCRIPTION": "Varsayılan olarak altyazıları göster veya gizle",
"VERSION_DESCRIPTION": "Uygulamanın geçerli sürümü",
"EPG_NOTE": "Şu anda EPG, yalnızca Electron tabanlı IPTVnator sürümünde kullanılabilir.",
"EPG_NOTE_URL_TEXT": "Buradan kontrol edin",
"IMPORT_EXPORT_DATA": "Oynatma listelerini içe/dışa aktar",
"IMPORT_EXPORT_DATA_DESCRIPTION": "Uygulama içi kullanılan JSON formatında oynatma listelerini dışa aktar veya içe aktar.",
"IMPORT_DATA": "İçe Aktar",
"EXPORT_DATA": "Dışa Aktar",
"REMOVE_ALL": "Delete all playlists and playlist data",
"REMOVE_ALL_BUTTON": "Delete all",
"REMOVE_ALL_DESCRIPTION": "Delete every M3U, Xtream, and Stalker playlist stored in the app.",
"REMOVE_DIALOG": {
"TITLE": "Delete all playlists?",
"MESSAGE": "Delete all {{count}} playlists from the app. This also removes stored playlist data on this device.",
"SUMMARY_TITLE": "Playlist sources",
"CONSEQUENCES_TITLE": "This also removes",
"CONSEQUENCE_FAVORITES": "Favorites saved for these playlists",
"CONSEQUENCE_RECENTLY_VIEWED": "Recently viewed history",
"CONSEQUENCE_PLAYBACK": "Saved playback positions",
"CONSEQUENCE_DOWNLOADS": "Download history entries linked to those playlists",
"CONSEQUENCE_XTREAM_CACHE": "Imported Xtream categories and locally cached content",
"BACKUP_HINT": "Use Export first if you want a restorable backup before deleting.",
"CONFIRM": "Delete everything"
},
"IMPORT_ERROR": "İçe aktarma hatası, lütfen başka bir dosyayla deneyin.",
"PLAYLISTS_REMOVED": "All playlists and playlist data were removed.",
"MPV_PLAYER_PATH_LABEL": "mpv yolu",
"MPV_PLAYER_PATH_DESCRIPTION": "Sisteminizdeki mpv oynatıcı yolunu ayarlayın. $PATH'de bulunanı kullanmak yerine, sağlanan mpv ikili dosyası yolunu kullanacaktır.",
"MPV_PLAYER_PATH": "mpv oynatıcı yolu",
"MPV_REUSE_INSTANCE_LABEL": "MPV örneğini yeniden kullan",
"MPV_REUSE_INSTANCE_DESCRIPTION": "Etkinleştirildiğinde, farklı yayınları oynatmak için aynı MPV penceresi yeniden kullanılır. Devre dışı bırakıldığında, her yayın yeni bir MPV penceresinde açılır.",
"VLC_PLAYER_PATH_LABEL": "VLC yolu",
"VLC_PLAYER_PATH_DESCRIPTION": "Sisteminizdeki VLC oynatıcı yolunu ayarlayın. Sistemimiz için varsayılan yolu kullanmak yerine, sağlanan VLC ikili dosyası yolunu kullanacaktır.",
"VLC_PLAYER_PATH": "VLC oynatıcı yolu",
"REMOTE_CONTROL": "Uzaktan kontrol",
"REMOTE_CONTROL_DESCRIPTION": "Uygulamanın uzaktan kontrolünü etkinleştirin.",
"REMOTE_CONTROL_PORT": "Uzaktan kontrol portu",
"REMOTE_CONTROL_PORT_DESCRIPTION": "Uygulamanın uzaktan kontrolü için kullanılan port. Varsayılan olarak port 8765 kullanılır.",
"REMOTE_CONTROL_URL": "Uzaktan kontrol URL'si",
"REMOTE_CONTROL_URL_DESCRIPTION": "Aynı ağdaki başka bir cihazdan uzaktan kontrole erişin.",
"SHOW_QR_CODE": "QR kodunu göster",
"PORT_REQUIRED": "Port gereklidir",
"PORT_MIN": "Port en az 1 olmalıdır",
"PORT_MAX": "Port en fazla 65535 olmalıdır",
"PORT_PATTERN": "Sadece rakamlara izin verilir",
"REMOVE_ALL_IN_PROGRESS": "Deleting playlist data…",
"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.",
"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",
"LIGHT_THEME": "Açık tema",
"SYSTEM_THEME": "Sistem teması"
},
"CHANNELS": {
"SEARCH_CHANNEL": "Kanal ara",
"UPLOAD_OR_SELECT_OTHER_PLAYLIST": "Dosya yükle veya başka bir oynatma listesi seçin",
"ALL_CHANNELS": "Tüm kanallar",
"GROUPS": "Gruplar",
"UNGROUPED": "Grupsuz",
"UNNAMED_CHANNEL": "İsimsiz kanal",
"FAVORITES": "Favoriler",
"NO_FAVORITES": "Henüz favori yok",
"USE_STAR_TO_FAVORITE": "Lütfen favorilere kanal eklemek için 'yıldız' simgesini kullanın.",
"REMOVE_FAVORITE": "Favorilerden kaldır",
"ADD_FAVORITE": "Favorilere ekle",
"FAVORITES_UPDATED": "Favoriler güncellendi!",
"SORT_BY": "Sırala",
"SORT_BY_DATE": "Eklenme tarihine göre sırala (Önce En Yeni)",
"SORT_BY_RATING": "Puana göre sırala",
"SORT_BY_NAME": "İsme göre sırala (A-Z)",
"LOAD_MORE": "Daha fazla yükle",
"REMAINING": "kalan",
"LOADING": "Kanallar yükleniyor...",
"LOADING_MORE": "Daha fazla yükleniyor...",
"NO_SEARCH_RESULTS": "Kanal bulunamadı",
"TRY_DIFFERENT_SEARCH": "Farklı bir arama terimi deneyin"
},
"TOP_MENU": {
"OPEN_CHANNELS_LIST": "Kanal listesini aç",
"TOGGLE_FAVORITE_FLAG": "Favori işaretini değiştir",
"OPEN_EPG_LIST": "EPG listesini aç",
"OPEN_MULTI_EPG": "Çoklu EPG görünümünü aç",
"SHOW_INFO": "Program bilgisini göster (I tuşuna basın)"
},
"EPG": {
"TITLE": "Elektronik Program Rehberi",
"NEXT_DAY": "Sonraki gün",
"PREVIOUS_DAY": "Önceki gün",
"LIVE_NOW": "Şu an canlı",
"LIVE_STREAM": "Canlı yayın",
"TIMESHIFT_AVAILABLE": "Zaman kaydırma mevcut, tıklayarak oynat",
"EPG_NOT_AVAILABLE_DATE": "Üzgünüz, seçilen tarih için EPG mevcut değil",
"EPG_NOT_AVAILABLE_CHANNEL_TITLE": "Üzgünüz, bu kanal için EPG mevcut değil.",
"EPG_NOT_AVAILABLE_CHANNEL_DESCRIPTION": "Lütfen uygulamanın ayarlarında EPG listesi URL'sini ekleyin veya değiştirin.",
"FETCH_EPG": "EPG verileri alınıyor...",
"ERROR": "Üzgünüz, EPG yüklenemedi.",
"DOWNLOAD_SUCCESS": "EPG başarıyla indirildi.",
"NO_PROGRAM_INFO": "Program bilgisi mevcut değil",
"PROGRAM_DIALOG": {
"PROGRAM_DETAILS": "TV programı hakkında",
"TITLE": "Başlık",
"CATEGORY": "Kategori",
"PARENTAL_RATING_SYSTEM": "Televizyon içeriği derecelendirme sistemi",
"DESCRIPTION": "Açıklama",
"LANGUAGE": "Dil",
"SHOW_PROGRAM_DETAILS": "Bu program hakkında detayları göster",
"EPISODE": "Bölüm",
"DURATION": "Süre"
},
"FETCH_SUCCESS": "EPG verileri başarıyla alındı",
"IMPORT_PROGRESS": "EPG İçe Aktarımı",
"CHANNELS": "kanallar",
"PROGRAMS": "programlar",
"LOADING": "Yükleniyor",
"QUEUED": "Sırada",
"TOTAL_CHANNELS": "Toplam kanal",
"TOTAL_PROGRAMS": "Toplam program",
"UP_TO_DATE": "EPG güncel, senkronizasyona gerek yok",
"RETRY": "Tekrar Dene"
},
"LANGUAGES": {
"ARABIC": "العربية",
"MOROCCAN_ARABIC": "العربية (اللهجة المغربية)",
"ENGLISH": "English",
"KOREAN": "한국어",
"RUSSIAN": "Русский",
"GERMAN": "Deutsch",
"SPANISH": "Español",
"CHINESE": "简体中文",
"TRADITIONAL_CHINESE": "繁體中文",
"FRENCH": "Français",
"ITALIAN": "Italiano",
"TURKISH": "Türkçe",
"JAPANESE": "日本語",
"DUTCH": "Nederlands",
"BELARUSIAN": "Беларуская",
"POLISH": "Polski",
"PORTUGUESE": "Português",
"GREEK": "Ελληνικά"
},
"YES": "Evet",
"NO": "Hayır",
"MENU": {
"OPEN": "Menüyü aç",
"SUPPORT_ARIA": "IPTVnator'u GitHub'da destekleyin",
"SETTINGS": "Ayarlar",
"SETTINGS_ARIA": "Ayarları aç",
"BUG_REPORT": "Hata bildir",
"WHAT_IS_NEW": "Yeni ne var?",
"ABOUT": "Hakkında",
"ABOUT_ARIA": "Uygulama hakkında",
"SUPPORT_PROJECT": "Projeyi destekleyin"
},
"ABOUT": {
"TITLE": "IPTVnator Hakkında",
"DESCRIPTION": "Çoklu özellikler sunan, m3u ve m3u8 oynatma listeleri, favoriler, TV rehberi, TV arşivi/geri dönük izleme ve daha fazlasını destekleyen çok platformlu IPTV oynatıcı uygulaması.",
"VERSION": "Sürüm",
"GITHUB_TOOLTIP": "IPTVnator GitHub deposu",
"BUY_ME_A_COFFEE_TOOLTIP": "Bana bir kahve alın",
"TWITTER_TOOLTIP": "Twitter'da paylaş"
},
"UPDATE_AVAILABLE": "Güncelleme mevcut",
"REFRESH": "Yenile",
"XTREAM": {
"PLAY": "Oynat",
"OPENING_PLAYER": "Oynatıcı açılıyor...",
"NAME": "İsim",
"RELEASE_DATE": "Çıkış tarihi",
"GENRE": "Tür",
"COUNTRY": "Ülke",
"ACTORS": "Oyuncular",
"DIRECTOR": "Yönetmen",
"DURATION": "Süre",
"CAST": "Oyuncular",
"EPISODE_RUN_TIME": "Bölüm süresi",
"RATING": "Değerlendirme",
"IMDB_RATING": "IMDB derecelendirmesi",
"KINOPOISK_RATING": "Kinopoisk derecelendirmesi",
"DESCRIPTION": "Açıklama",
"YEAR": "Yıl",
"AGE": "Yaş",
"YOUTUBE_TRAILER": "YouTube fragmanı",
"EPISODE": "Bölüm",
"RESUME": "Devam Et",
"RESTART": "Baştan Başla",
"CONTINUE_WATCHING": "İzlemeye Devam Et",
"WATCHED": "İzlendi",
"IN_PROGRESS": "Devam Ediyor",
"MARK_WATCHED": "İzlendi Olarak İşaretle",
"MARK_UNWATCHED": "İzlenmedi Olarak İşaretle",
"EPISODES_WATCHED": "{{total}} bölümden {{count}} tanesi izlendi",
"ACCOUNT_INFO": {
"TITLE": "Hesap Bilgileri",
"USER_INFO": "Kullanıcı Bilgileri",
"STATUS": "Durum",
"USERNAME": "Kullanıcı Adı",
"ACTIVE_CONNECTIONS": "Aktif Bağlantılar",
"CREATED": "Oluşturuldu",
"EXPIRES": "Sona Eriyor",
"TRIAL_ACCOUNT": "Deneme Hesabı",
"YES": "Evet",
"NO": "Hayır",
"ALLOWED_FORMATS": "İzin Verilen Formatlar",
"SERVER_INFO": "Sunucu Bilgileri",
"LIVE_TV": "Canlı TV",
"MOVIES": "Filmler",
"TV_SERIES": "TV Dizileri",
"URL": "URL",
"PROTOCOL": "Protokol",
"TIMEZONE": "Saat Dilimi",
"SERVER_TIME": "Sunucu Saati",
"PORTS": "Portlar",
"HTTP_PORT": "HTTP",
"HTTPS_PORT": "HTTPS",
"RTMP_PORT": "RTMP"
},
"CATEGORY_MANAGEMENT": {
"TITLE": "Kategorileri Yönet",
"LOADING": "Kategoriler yükleniyor...",
"SELECTED": "Seçildi",
"SELECT_ALL": "Tümünü Seç",
"DESELECT_ALL": "Tümünü Kaldır",
"SEARCH_PLACEHOLDER": "Kategorileri ara...",
"NO_RESULTS": "Eşleşen kategori bulunamadı",
"NO_CATEGORIES": "Kategori mevcut değil",
"SAVE": "Kaydet"
}
},
"PORTALS": {
"ALL_CATEGORIES": "Tüm kategoriler",
"MY_FAVORITES": "Favorilerim",
"ADD_TO_FAVORITES": "Favorilere ekle",
"REMOVE_FROM_FAVORITES": "Favorilerden kaldır",
"REMOVED_FROM_FAVORITES": "Favorilerden kaldırıldı",
"ADDED_TO_FAVORITES": "Favorilere eklendi",
"SIDEBAR": {
"MAIN": "Ana Menü",
"MOVIES": "Filmler",
"LIVE_TV": "Canlı TV",
"SERIES": "Diziler",
"LIBRARY": "Kütüphane",
"SEARCH": "Ara",
"RECENT": "Son İzlenenler",
"RECENTLY_ADDED": "Yeni Eklenenler",
"FAVORITES": "Favoriler",
"HOME": "Ana Sayfa",
"PLAYLIST_INFO": "Oynatma Listesi Bilgisi",
"ACCOUNT_INFO": "Hesap Bilgisi"
},
"ERROR_VIEW": {
"ACCOUNT_EXPIRED": {
"TITLE": "Hesap süresi doldu",
"DESCRIPTION": "Bu hesabın süresi doldu. Lütfen oynatma listesi ayarlarındaki kimlik bilgilerini kontrol edin veya kaldırın."
},
"UNAUTHORIZED": {
"TITLE": "Yetkisiz",
"DESCRIPTION": "Lütfen oynatma listesi ayarlarındaki kimlik bilgilerini kontrol edin veya kaldırın."
},
"NOT_FOUND": {
"TITLE": "Portal bulunamadı",
"DESCRIPTION": "Lütfen oynatma listesi ayarlarındaki kimlik bilgilerini ve portal url'sini kontrol edin veya kaldırın."
},
"EMPTY_CATEGORY": {
"TITLE": "Boş kategori",
"DESCRIPTION": "Bu kategoride içerik yok, lütfen başka bir kategori seçin veya içerik türünü değiştirin"
},
"UNKNOWN_ERROR": {
"TITLE": "Bir şeyler ters gitti",
"DESCRIPTION": "Bilinmeyen hata, lütfen daha sonra tekrar deneyin"
},
"NO_CATEGORY_SELECTED": {
"TITLE": "Kategori seçilmedi",
"DESCRIPTION": "İçeriği görmek için lütfen bir kategori seçin"
},
"PLAYLIST_SETTINGS": "Oynatma Listesi Ayarları",
"HOME": "Ana Sayfa",
"DELETE": "Sil"
},
"EMPTY_LIST_VIEW": {
"TITLE": "Sonuç bulunamadı",
"NO_SEARCH_RESULTS": "Arama sonuçları yok, lütfen arama talebinizi değiştirin"
},
"SEARCH_VIEW": {
"INITIAL_TITLE": "İçerik ara",
"INITIAL_DESCRIPTION": "Canlı TV, filmler ve diziler arasında arama yapmak için en az 3 karakter girin.",
"RESULTS_FOUND": "{{count}} sonuç bulundu",
"NO_RESULTS_FOR": "\"{{term}}\" için sonuç bulunamadı",
"GROUP_BY_PLAYLIST": "Sonuçları oynatma listesine göre grupla",
"XTREAM_ONLY_NOTE": "Küresel arama şu anda sadece Xtream oynatma listeleri için mevcuttur.",
"VISIBLE_CATEGORIES_ONLY": "Sadece görünür kategoriler"
},
"STREAM_URL_COPIED": "Yayın URL'si panoya kopyalandı",
"COPY_STREAM_URL": "Yayın URL'sini kopyala",
"SELECT_CATEGORY": "Bir kategori seçin",
"PAGE": "Sayfa",
"CONTENT_NOT_AVAILABLE": "Bu içerik bu sunucuda mevcut değil",
"PLAYBACK_ERROR": "Oynatma URL'si alınamadı",
"LOADING_SEASONS": "Sezonlar yükleniyor...",
"NO_EPISODES": "Bölüm mevcut değil"
},
"INFORMATION": "Bilgi",
"DOWNLOADS": {
"TITLE": "İndirilenler",
"DOWNLOAD": "İndir",
"PLAY_LOCAL": "Yerel Oynat",
"EMPTY": "Henüz indirme yok",
"EMPTY_HINT": "Çevrimdışı izlemek için film ve dizileri indirin",
"NOT_AVAILABLE": "İndirme mevcut değil",
"DESKTOP_ONLY": "Bu özellik sadece masaüstü uygulamasında mevcuttur",
"NO_FOLDER": "İndirme klasörü seçilmedi",
"CHANGE_FOLDER": "Klasörü Değiştir",
"CLEAR_COMPLETED": "Tamamlananları Temizle",
"CANCEL": "İptal",
"RETRY": "Tekrar Dene",
"REMOVE": "Kaldır",
"PLAY": "Oynat",
"REVEAL": "Klasörde Göster",
"STATUS": {
"QUEUED": "Sırada",
"DOWNLOADING": "İndiriliyor",
"COMPLETED": "Tamamlandı",
"FAILED": "Başarısız",
"CANCELED": "İptal Edildi"
},
"NO_PLAYLISTS_TITLE": "Add a playlist to start downloading",
"NO_PLAYLISTS_BODY": "Once you add a playlist, you can save movies and episodes here for offline playback.",
"NO_ITEMS_BODY": "Use the download button on any movie or episode to save it for offline playback.",
"NO_FILTER_MATCH": "No downloads match the current filter",
"NO_FILTER_MATCH_HINT": "Try a different search term"
},
"REMOTE_CONTROL": {
"TITLE": "Uzaktan kontrol",
"SUBTITLE": "IPTV oynatıcınızı uzaktan kontrol edin",
"UP_CHANNEL": "Kanal yukarı",
"DOWN_CHANNEL": "Kanal aşağı",
"HEADER": "IPTVNator Uzaktan Kontrol",
"FOOTER": "IPTVNator Uzaktan Kontrol"
},
"WORKSPACE": {
"SHELL": {
"GO_TO_DASHBOARD": "Back to dashboard",
"GO_TO_SOURCES": "Go to Sources",
"DROP_OVERLAY_TITLE": "Drop to add playlist",
"DROP_OVERLAY_BODY": "Release an .m3u or .m3u8 file anywhere in the workspace to import it.",
"DROP_OVERLAY_REJECTED_BODY": "Please drop an .m3u or .m3u8 file. Press Esc to dismiss.",
"DROP_OVERLAY_REJECTED_UNSUPPORTED": "Unsupported file type",
"DROP_OVERLAY_REJECTED_EMPTY": "That file is empty",
"DROP_OVERLAY_REJECTED_READ_ERROR": "Could not read that file",
"DROP_IMPORT_SUCCESS": "Importing \"{{title}}\"…",
"COMMANDS": {
"ADD_PLAYLIST_M3U_LABEL": "Add M3U playlist",
"ADD_PLAYLIST_M3U_DESCRIPTION": "Open add dialog on the M3U file or URL tab",
"ADD_PLAYLIST_XTREAM_LABEL": "Add Xtream Codes playlist",
"ADD_PLAYLIST_XTREAM_DESCRIPTION": "Open add dialog on the Xtream Codes tab",
"ADD_PLAYLIST_STALKER_LABEL": "Add Stalker portal",
"ADD_PLAYLIST_STALKER_DESCRIPTION": "Open add dialog on the Stalker Portal tab"
},
"EXTERNAL_PLAYBACK_CLOSE": "Close player"
},
"GLOBAL_FAVORITES": {
"NO_PLAYLISTS_TITLE": "No favorites to show",
"NO_PLAYLISTS_BODY": "Add a playlist to start collecting favorites from live channels, movies, and series.",
"NO_ITEMS_TITLE": "No favorites yet",
"NO_ITEMS_BODY": "Tap the star icon on any channel, movie, or series to save it here."
},
"GLOBAL_RECENT": {
"NO_PLAYLISTS_TITLE": "Nothing watched yet",
"NO_PLAYLISTS_BODY": "Add a playlist and your watching history will appear here.",
"NO_ITEMS_TITLE": "Nothing watched yet",
"NO_ITEMS_BODY": "Start watching anything from your library and it will show up here."
}
}
}
+356
View File
@@ -0,0 +1,356 @@
{
"CLOSE": "关闭",
"HOME": {
"TITLE": "IPTVnator",
"SUBTITLE": "选择一个播放列表或者从URL/文件中添加一个新的播放列表",
"TABS": {
"RECENTLY_ADDED": "最近添加的播放列表",
"FILE_UPLOAD": "从文件添加",
"URL_UPLOAD": "从URL链接添加",
"TEXT_IMPORT": "从文本添加",
"STALKER_PORTAL_IMPORT": "添加跟踪者门户"
},
"PLAYLISTS": {
"NO_PLAYLISTS": "未添加播放列表",
"ADD_FIRST": "从其他标签页添加你的第一个播放列表",
"ADDED_VIA_URL": "添加自URL链接:",
"ADDED_VIA_FILE": "添加自文件",
"CHANNELS": "频道",
"ADDED": "已添加的",
"SHOW_DETAILS": "显示播放列表详情",
"REMOVE": "移除播放列表",
"INFO_DIALOG": {
"PLAYLIST_DETAILS": "播放列表详情",
"TITLE": "标题",
"FROM_URL": "添加自URL链接",
"IMPORT_DATE": "导入日期",
"CHANNELS": "频道数",
"CLOSE": "关闭",
"SAVE": "保存",
"USER_AGENT": "User agent",
"ORIGINAL_FILENAME": "原始文件名",
"FILE_PATH": "文件路径",
"UPDATE_FAILED": "上次播放列表更新失败",
"AUTO_UPDATE": "自动更新",
"AUTO_UPDATE_DESCRIPTION": "如果启用了自动刷新功能,则每次启动应用程序时都会自动更新播放列表。",
"CUSTOM_USER_AGENT": "一些 IPTV 提供商需要特定的用户代理才能播放他们的播放列表。",
"PASSWORD": "密码",
"SERVER_URL": "服务器地址",
"USERNAME": "用户名",
"MAC_ADDRESS": "MAC地址"
},
"REMOVE_DIALOG": {
"TITLE": "移除播放列表",
"MESSAGE": "您确定要完全删除此播放列表吗?"
},
"UPDATED": "更新",
"REFRESH": "刷新播放列表",
"GLOBAL_FAVORITES": "我的收藏",
"GLOBAL_FAVORITES_DESCRIPTION": "由所有播放列表自动生成的聚合收藏列表",
"MY_PLAYLISTS": "我的播放列表",
"FEATURE_M3U_LABEL": "Add an M3U file or URL",
"FEATURE_XTREAM_LABEL": "Connect via Xtream Codes",
"FEATURE_STALKER_LABEL": "Connect to a Stalker portal",
"VALUE_PROPS_LABEL": "What you can do",
"VALUE_PROP_LIVE": "Live TV with EPG",
"VALUE_PROP_VOD": "Movies & Series",
"VALUE_PROP_MULTISOURCE": "Multi-source library",
"VALUE_PROP_OFFLINE": "Offline downloads",
"DASHBOARD_WELCOME_TAGLINE": "Your IPTV library, in one place.",
"FEATURE_LIVE_TITLE": "Live TV",
"FEATURE_LIVE_DESC": "Stream live channels with full schedule.",
"FEATURE_VOD_TITLE": "Movies & Series",
"FEATURE_VOD_DESC": "On-demand library with covers and details.",
"FEATURE_EPG_TITLE": "EPG & Catch-up",
"FEATURE_EPG_DESC": "Program guide and time-shifted playback.",
"FEATURE_OFFLINE_TITLE": "Offline downloads",
"FEATURE_OFFLINE_DESC": "Save movies and episodes for later.",
"SOURCES_WELCOME_TITLE": "Add your first playlist",
"SOURCES_WELCOME_BODY": "Pick a source type below to get started.",
"SOURCE_M3U_NEEDS": "Local file or URL pointing to an M3U/M3U8 playlist.",
"SOURCE_M3U_ADD": "Add M3U",
"SOURCE_XTREAM_NEEDS": "Username, password and server URL from your provider.",
"SOURCE_XTREAM_ADD": "Add Xtream",
"SOURCE_STALKER_NEEDS": "Portal URL and MAC address (Ministra-compatible).",
"SOURCE_STALKER_ADD": "Add Stalker",
"CONTENT_LIVE": "Live",
"CONTENT_VOD": "Movies",
"CONTENT_SERIES": "Series",
"CONTENT_EPG": "EPG",
"DASHBOARD_WELCOME_DESCRIPTION": "Connect M3U files, Xtream Codes, or Stalker portals — then enjoy live TV, movies and series on every screen."
},
"FILE_UPLOAD": {
"DRAG_DROP": "将文件拖放到此处",
"OR": "或",
"CHOOSE_PLAYLIST": "选择一个播放列表"
},
"URL_UPLOAD": {
"PLAYLIST_URL": "播放一个播放列表(m3u, m3u8)",
"ADD_PLAYLIST": "添加播放列表"
},
"TEXT_IMPORT": {
"LABEL": "从文本导入播放列表(m3u, m3u8)",
"BUTTON_LABEL": "导入"
},
"STALKER_PORTAL": {
"ADD": "添加",
"TITLE": "标题",
"URL_VALIDATION_ERROR": "应该是带有协议的有效网址(例如 http://example.com/c 或 https://example.com/stalker_portal/c)"
},
"XTREAM_PLAYLIST": {
"URL_VALIDATION_ERROR": "应该是带有协议的有效 url(例如 http://example.com 或 https://example.com:4324)"
}
},
"SETTINGS": {
"TITLE": "设置",
"SUBTITLE": "更改应用程序的配置 ",
"DESCRIPTION": "请调整以下列表中的选项并使用保存按钮确认",
"EPG_URL_LABEL": "电子节目单EPG Url (*.xml 或 *.xml.gz)",
"EPG_URL_PLACEHOLDER": "输入一个 URL",
"REFRESH_EPG": "刷新电子节目单EPG",
"REFRESH_ALL_EPG": "全部刷新",
"REMOVE_EPG_SOURCE": "移除 EPG 源",
"EPG_STATUS_FRESH": "已更新",
"EPG_STATUS_STALE": "需要刷新",
"EPG_STATUS_ERROR": "失败",
"VIDEO_PLAYER_LABEL": "视频播放器",
"VIDEO_PLAYER_PLACEHOLDER": "选择一个选项",
"VERSION": "版本",
"SAVE_CHANGES": "保存更改",
"BACK_TO_HOME": "回到主页",
"NEW_VERSION_AVAILABLE": "有新版本可用 ",
"LATEST_VERSION": "您使用的是最新版本",
"LANGUAGE": "语言",
"SETTINGS_SAVED": "配置已成功保存",
"THEME": "主题",
"SHOW_CAPTIONS": "显示字幕",
"REMOVE_ALL": "Delete all playlists and playlist data",
"REMOVE_ALL_BUTTON": "Delete all",
"REMOVE_DIALOG": {
"TITLE": "Delete all playlists?",
"MESSAGE": "Delete all {{count}} playlists from the app. This also removes stored playlist data on this device.",
"SUMMARY_TITLE": "Playlist sources",
"CONSEQUENCES_TITLE": "This also removes",
"CONSEQUENCE_FAVORITES": "Favorites saved for these playlists",
"CONSEQUENCE_RECENTLY_VIEWED": "Recently viewed history",
"CONSEQUENCE_PLAYBACK": "Saved playback positions",
"CONSEQUENCE_DOWNLOADS": "Download history entries linked to those playlists",
"CONSEQUENCE_XTREAM_CACHE": "Imported Xtream categories and locally cached content",
"BACKUP_HINT": "Use Export first if you want a restorable backup before deleting.",
"CONFIRM": "Delete everything"
},
"LANGUAGE_DESCRIPTION": "选择应用程序的语言",
"PLAYLISTS_REMOVED": "All playlists and playlist data were removed.",
"VERSION_DESCRIPTION": "应用程序的当前版本",
"IMPORT_DATA": "进口",
"ADD_EPG_SOURCE": "添加EPG源",
"IMPORT_ERROR": "导入错误,请尝试使用其他文件。",
"EPG_URL_ERROR": "该值不是有效的 URL",
"EXPORT_DATA": "出口",
"VIDEO_PLAYER_DESCRIPTION": "选择默认视频播放器",
"IMPORT_EXPORT_DATA": "导入/导出播放列表",
"VLC_PLAYER_PATH_LABEL": "VLC路径",
"VLC_PLAYER_PATH_DESCRIPTION": "设置系统中 VLC 播放器的路径。\n它将使用提供的 VLC 二进制文件路径,而不是我们系统的默认路径。",
"THEME_DESCRIPTION": "选择应用程序的视觉主题",
"EPG_NOTE": "目前 EPG 仅在基于电子的 IPTVnator 版本中可用。",
"VLC_PLAYER_PATH": "VLC播放器路径",
"IMPORT_EXPORT_DATA_DESCRIPTION": "以应用程序中使用的 JSON 格式导出或导入播放列表。",
"EPG_NOTE_URL_TEXT": "在这里检查一下",
"MPV_PLAYER_PATH_LABEL": "多用途车路径",
"REMOVE_ALL_DESCRIPTION": "Delete every M3U, Xtream, and Stalker playlist stored in the app.",
"REMOVE_ALL_IN_PROGRESS": "Deleting playlist data…",
"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.",
"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": "暗黑模式",
"LIGHT_THEME": "明亮模式",
"SYSTEM_THEME": "跟随系统"
},
"CHANNELS": {
"SEARCH_CHANNEL": "搜索频道",
"UPLOAD_OR_SELECT_OTHER_PLAYLIST": "上传或选择其他播放列表",
"ALL_CHANNELS": "所有频道",
"GROUPS": "分组",
"UNGROUPED": "未分组",
"UNNAMED_CHANNEL": "未命名频道",
"FAVORITES": "收藏",
"NO_FAVORITES": "还没有收藏夹",
"USE_STAR_TO_FAVORITE": "使用“☆”图标将频道添加到此列表中",
"REMOVE_FAVORITE": "从收藏夹中删除",
"FAVORITES_UPDATED": "收藏夹已更新!"
},
"TOP_MENU": {
"OPEN_CHANNELS_LIST": "打开频道列表",
"TOGGLE_FAVORITE_FLAG": "切换收藏夹标志",
"OPEN_EPG_LIST": "打开电子节目单EPG列表",
"OPEN_MULTI_EPG": "打开多EPG显示"
},
"EPG": {
"NEXT_DAY": "明天",
"PREVIOUS_DAY": "昨天",
"LIVE_NOW": "正在播放",
"LIVE_STREAM": "正在直播",
"TIMESHIFT_AVAILABLE": "时移功能可用,点击播放",
"EPG_NOT_AVAILABLE_DATE": "错误:电子节目单EPG在所选日期不可用",
"EPG_NOT_AVAILABLE_CHANNEL_TITLE": "错误:电子节目单EPG不适用于此频道",
"EPG_NOT_AVAILABLE_CHANNEL_DESCRIPTION": "请添加/更改设置项中电子节目单的URL",
"FETCH_EPG": "获取 EPG 数据...",
"ERROR": "错误: 获取 EPG 数据失败",
"DOWNLOAD_SUCCESS": "EPG 数据下载成功",
"PROGRAM_DIALOG": {
"PROGRAM_DETAILS": "电视节目详情",
"TITLE": "标题",
"CATEGORY": "类别",
"PARENTAL_RATING_SYSTEM": "电视内容分级系统",
"DESCRIPTION": "描述",
"LANGUAGE": "语言",
"SHOW_PROGRAM_DETAILS": "显示有关此程序的详细信息"
}
},
"LANGUAGES": {
"ARABIC": "العربية",
"MOROCCAN_ARABIC": "العربية (اللهجة المغربية)",
"ENGLISH": "English",
"KOREAN": "한국어",
"RUSSIAN": "Русский",
"GERMAN": "Deutsch",
"SPANISH": "Español",
"CHINESE": "简体中文",
"TRADITIONAL_CHINESE": "繁體中文",
"FRENCH": "Français",
"ITALIAN": "Italiano",
"TURKISH": "Türkçe",
"JAPANESE": "日本語",
"DUTCH": "Nederlands",
"BELARUSIAN": "Беларуская",
"POLISH": "Polski",
"PORTUGUESE": "Português",
"GREEK": "Ελληνικά"
},
"YES": "是",
"NO": "否",
"MENU": {
"OPEN": "打开菜单",
"SUPPORT_ARIA": "在 GitHub 上支持 IPTVnator",
"SETTINGS": "设置",
"SETTINGS_ARIA": "打开设置",
"BUG_REPORT": "问题反馈",
"WHAT_IS_NEW": "更新日志",
"ABOUT": "关于",
"ABOUT_ARIA": "关于应用",
"SUPPORT_PROJECT": "支持项目"
},
"XTREAM": {
"RELEASE_DATE": "发布日期",
"ACTORS": "演员",
"PLAY": "玩",
"GENRE": "类型",
"DURATION": "期间",
"COUNTRY": "国家",
"NAME": "姓名",
"DIRECTOR": "导演",
"CAST": "投掷",
"RATING": "评分",
"AGE": "年龄",
"EPISODE": "插曲",
"YEAR": "年",
"YOUTUBE_TRAILER": "YouTube 预告片",
"DESCRIPTION": "描述",
"KINOPOISK_RATING": "评级动力学",
"IMDB_RATING": "评级IMDB",
"EPISODE_RUN_TIME": "剧集运行时间"
},
"PORTALS": {
"ALL_CATEGORIES": "所有类别",
"ADD_TO_FAVORITES": "添加到收藏夹",
"REMOVE_FROM_FAVORITES": "从收藏夹中删除",
"MY_FAVORITES": "我最喜欢的",
"ERROR_VIEW": {
"DELETE": "删除",
"ACCOUNT_EXPIRED": {
"TITLE": "帐户已过期",
"DESCRIPTION": "该帐户已过期。\n请检查播放列表设置中的凭据或将其删除。"
},
"EMPTY_CATEGORY": {
"TITLE": "空类别",
"DESCRIPTION": "该类别没有内容,请选择其他类别或更改内容类型"
},
"UNAUTHORIZED": {
"TITLE": "未经授权",
"DESCRIPTION": "请检查播放列表设置中的凭据或将其删除。"
},
"UNKNOWN_ERROR": {
"TITLE": "出了点问题",
"DESCRIPTION": "未知错误,请稍后重试"
},
"PLAYLIST_SETTINGS": "播放列表设置"
},
"EMPTY_LIST_VIEW": {
"NO_SEARCH_RESULTS": "未找到任何内容,请尝试更改您的搜索请求"
},
"REMOVED_FROM_FAVORITES": "已从收藏夹中删除",
"ADDED_TO_FAVORITES": "已添加至收藏夹",
"SEARCH_VIEW": {
"RESULTS_FOUND": "找到 {{count}} 条结果",
"NO_RESULTS_FOR": "未找到与“{{term}}”匹配的结果"
}
},
"ABOUT": {
"TITLE": "关于 IPTVnator",
"VERSION": "版本",
"TWITTER_TOOLTIP": "分享到Twitter",
"BUY_ME_A_COFFEE_TOOLTIP": "Buy me a coffee"
},
"REFRESH": "刷新",
"UPDATE_AVAILABLE": "可用更新",
"WORKSPACE": {
"SHELL": {
"GO_TO_DASHBOARD": "Back to dashboard",
"GO_TO_SOURCES": "Go to Sources",
"DROP_OVERLAY_TITLE": "Drop to add playlist",
"DROP_OVERLAY_BODY": "Release an .m3u or .m3u8 file anywhere in the workspace to import it.",
"DROP_OVERLAY_REJECTED_BODY": "Please drop an .m3u or .m3u8 file. Press Esc to dismiss.",
"DROP_OVERLAY_REJECTED_UNSUPPORTED": "Unsupported file type",
"DROP_OVERLAY_REJECTED_EMPTY": "That file is empty",
"DROP_OVERLAY_REJECTED_READ_ERROR": "Could not read that file",
"DROP_IMPORT_SUCCESS": "Importing \"{{title}}\"…",
"COMMANDS": {
"ADD_PLAYLIST_M3U_LABEL": "Add M3U playlist",
"ADD_PLAYLIST_M3U_DESCRIPTION": "Open add dialog on the M3U file or URL tab",
"ADD_PLAYLIST_XTREAM_LABEL": "Add Xtream Codes playlist",
"ADD_PLAYLIST_XTREAM_DESCRIPTION": "Open add dialog on the Xtream Codes tab",
"ADD_PLAYLIST_STALKER_LABEL": "Add Stalker portal",
"ADD_PLAYLIST_STALKER_DESCRIPTION": "Open add dialog on the Stalker Portal tab"
},
"EXTERNAL_PLAYBACK_CLOSE": "Close player"
},
"GLOBAL_FAVORITES": {
"NO_PLAYLISTS_TITLE": "No favorites to show",
"NO_PLAYLISTS_BODY": "Add a playlist to start collecting favorites from live channels, movies, and series.",
"NO_ITEMS_TITLE": "No favorites yet",
"NO_ITEMS_BODY": "Tap the star icon on any channel, movie, or series to save it here."
},
"GLOBAL_RECENT": {
"NO_PLAYLISTS_TITLE": "Nothing watched yet",
"NO_PLAYLISTS_BODY": "Add a playlist and your watching history will appear here.",
"NO_ITEMS_TITLE": "Nothing watched yet",
"NO_ITEMS_BODY": "Start watching anything from your library and it will show up here."
}
},
"DOWNLOADS": {
"NO_PLAYLISTS_TITLE": "Add a playlist to start downloading",
"NO_PLAYLISTS_BODY": "Once you add a playlist, you can save movies and episodes here for offline playback.",
"NO_ITEMS_BODY": "Use the download button on any movie or episode to save it for offline playback.",
"NO_FILTER_MATCH": "No downloads match the current filter",
"NO_FILTER_MATCH_HINT": "Try a different search term"
}
}
+438
View File
@@ -0,0 +1,438 @@
{
"CLOSE": "關閉",
"PLAYLISTS": "播放清單",
"HOME": {
"TITLE": "IPTVnator",
"SUBTITLE": "請從列表中選擇一個播放清單,或透過檔案上傳或網址新增新播放清單",
"TABS": {
"RECENTLY_ADDED": "最近新增的播放清單",
"FILE_UPLOAD": "透過檔案上傳新增",
"URL_UPLOAD": "透過網址新增",
"TEXT_IMPORT": "以文字匯入",
"XTREME_IMPORT": "新增 Xtreme Code",
"STALKER_PORTAL_IMPORT": "新增 Stalker Portal"
},
"PLAYLISTS": {
"NO_PLAYLISTS": "尚未新增播放清單",
"ADD_FIRST": "請從其他分頁新增您的第一個播放清單",
"WELCOME_TITLE": "歡迎使用 IPTVnator",
"WELCOME_DESCRIPTION": "透過新增您的第一個播放清單開始串流之旅。連接您喜愛的 IPTV 服務,享受直播電視、電影和影集。",
"ADD_YOUR_FIRST": "新增您的第一個播放清單",
"FEATURE_M3U": "M3U/M3U8 檔案",
"FEATURE_XTREAM": "Xtream Codes",
"FEATURE_STALKER": "Stalker Portal",
"NO_RESULTS_TITLE": "找不到播放清單",
"NO_RESULTS_DESCRIPTION": "沒有符合您搜尋條件的播放清單。請嘗試調整搜尋詞或清除篩選條件以查看所有播放清單。",
"XTREAM_PLAYLIST": "Xtream 播放清單",
"STALKER_PORTAL": "Stalker Portal",
"ADDED_VIA_URL": "透過網址上傳。網址:",
"ADDED_VIA_FILE": "透過檔案上傳",
"CHANNELS": "頻道",
"ADDED": "已新增",
"SHOW_DETAILS": "顯示播放清單詳細資訊",
"REMOVE": "移除播放清單",
"INFO_DIALOG": {
"PLAYLIST_DETAILS": "播放清單詳細資訊",
"TITLE": "標題",
"FROM_URL": "來自網址",
"IMPORT_DATE": "匯入日期",
"CHANNELS": "頻道數量",
"CLOSE": "關閉",
"SAVE": "儲存",
"USER_AGENT": "User Agent",
"ORIGINAL_FILENAME": "原始檔名",
"FILE_PATH": "檔案路徑",
"UPDATE_FAILED": "上次播放清單更新失敗",
"AUTO_UPDATE": "自動更新",
"AUTO_UPDATE_DESCRIPTION": "如果啟動自動重新整理功能,則每次啟動應用程式時都將自動更新播放清單。",
"CUSTOM_USER_AGENT": "部分 IPTV 服務提供者需要特定的 User-Agent 才能播放他們的播放清單。",
"EXPORT_PLAYLIST": "以 m3u 格式匯出播放清單",
"PASSWORD": "密碼",
"SERVER_URL": "伺服器網址",
"USERNAME": "使用者名稱",
"MAC_ADDRESS": "Mac 位址",
"PLAYLIST_EXPORT_SUCCESS": "播放清單已成功匯出。",
"PLAYLIST_EXPORT_ERROR": "錯誤:播放清單匯出失敗。"
},
"REMOVE_DIALOG": {
"TITLE": "移除播放清單",
"MESSAGE": "您確定要完全刪除此播放清單嗎?",
"SUCCESS": "播放清單已成功移除"
},
"UPDATED": "已更新",
"REFRESH": "重新整理播放清單",
"AUTO_REFRESH_ENABLED": "已啟用自動重新整理",
"REFRESH_XTREAM": "從遠端重新整理 Xtream 播放清單",
"REFRESH_XTREAM_DIALOG": {
"TITLE": "重新整理 Xtream 播放清單",
"MESSAGE": "這將刪除本機快取的類別和串流,並從遠端伺服器重新匯入所有內容。您的最愛和最近觀看的項目將會保留。確定要繼續嗎?",
"STARTED": "已開始重新整理。正在導向播放清單...",
"ERROR": "重新整理播放清單失敗。請重試。"
},
"GLOBAL_FAVORITES": "全域我的最愛",
"GLOBAL_FAVORITES_DESCRIPTION": "從所有播放清單中自動產生的匯總我的最愛清單",
"MY_PLAYLISTS": "我的播放清單",
"MY_PLAYLISTS_SUBTITLE": "所有可用清單",
"PLAYLIST_UPDATE_SUCCESS": "成功!播放清單已成功更新。",
"PLAYLIST_UPDATE_ERROR": "更新播放清單詳細資訊時發生錯誤。",
"AUTO_REFRESH_UPDATE_SUCCESS": "成功!播放清單已成功更新",
"SEARCH_PLAYLISTS": "依標題搜尋播放清單",
"FEATURE_M3U_LABEL": "Add an M3U file or URL",
"FEATURE_XTREAM_LABEL": "Connect via Xtream Codes",
"FEATURE_STALKER_LABEL": "Connect to a Stalker portal",
"VALUE_PROPS_LABEL": "What you can do",
"VALUE_PROP_LIVE": "Live TV with EPG",
"VALUE_PROP_VOD": "Movies & Series",
"VALUE_PROP_MULTISOURCE": "Multi-source library",
"VALUE_PROP_OFFLINE": "Offline downloads",
"DASHBOARD_WELCOME_TAGLINE": "Your IPTV library, in one place.",
"FEATURE_LIVE_TITLE": "Live TV",
"FEATURE_LIVE_DESC": "Stream live channels with full schedule.",
"FEATURE_VOD_TITLE": "Movies & Series",
"FEATURE_VOD_DESC": "On-demand library with covers and details.",
"FEATURE_EPG_TITLE": "EPG & Catch-up",
"FEATURE_EPG_DESC": "Program guide and time-shifted playback.",
"FEATURE_OFFLINE_TITLE": "Offline downloads",
"FEATURE_OFFLINE_DESC": "Save movies and episodes for later.",
"SOURCES_WELCOME_TITLE": "Add your first playlist",
"SOURCES_WELCOME_BODY": "Pick a source type below to get started.",
"SOURCE_M3U_NEEDS": "Local file or URL pointing to an M3U/M3U8 playlist.",
"SOURCE_M3U_ADD": "Add M3U",
"SOURCE_XTREAM_NEEDS": "Username, password and server URL from your provider.",
"SOURCE_XTREAM_ADD": "Add Xtream",
"SOURCE_STALKER_NEEDS": "Portal URL and MAC address (Ministra-compatible).",
"SOURCE_STALKER_ADD": "Add Stalker",
"CONTENT_LIVE": "Live",
"CONTENT_VOD": "Movies",
"CONTENT_SERIES": "Series",
"CONTENT_EPG": "EPG",
"DASHBOARD_WELCOME_DESCRIPTION": "Connect M3U files, Xtream Codes, or Stalker portals — then enjoy live TV, movies and series on every screen."
},
"FILE_UPLOAD": {
"DRAG_DROP": "在此處拖放檔案",
"OR": "或者",
"CHOOSE_PLAYLIST": "選擇播放清單",
"REJECTED": "檔案被拒絕,不支援的檔案格式 {{filename}}。"
},
"URL_UPLOAD": {
"PLAYLIST_URL": "播放清單網址(m3u,m3u8)",
"ADD_PLAYLIST": "新增播放清單",
"CORS_NOTE": "為了避免 CORS 問題,此應用程式目前使用了一個公開的 CORS 代理服務。如果您要上傳包含敏感資料的播放清單,建議在相鄰的分頁中將其作為檔案匯入。"
},
"TEXT_IMPORT": {
"LABEL": "將 m3u(8)播放清單以純文字的方式插入",
"BUTTON_LABEL": "匯入"
},
"STALKER_PORTAL": {
"ADD": "新增",
"TITLE": "標題",
"MAC_ADDRESS": "Mac 位址",
"SERVER_URL": "伺服器網址",
"URL_VALIDATION_ERROR": "必須是有效的網址並包含協定(例如 http://example.com/c 或 https://example.com/stalker_portal/c)"
},
"XTREAM_PLAYLIST": {
"TITLE": "播放清單標題",
"SERVER_URL": "伺服器網址",
"USERNAME": "使用者名稱",
"PASSWORD": "密碼",
"ADD": "新增",
"TEST_CREDENTIALS": "測試憑證",
"URL_VALIDATION_ERROR": "必須是有效的網址並包含協定(例如 http://example.com 或 https://example.com:4324)"
}
},
"SETTINGS": {
"TITLE": "設定",
"SUBTITLE": "更改應用程式的配置",
"DESCRIPTION": "請調整下面的選項列表,並使用儲存變更按鈕確認",
"EPG_URL_LABEL": "EPG 網址(*.xml 或 *.xml.gz)",
"EPG_URL_PLACEHOLDER": "輸入網址",
"REFRESH_EPG": "重新整理 EPG",
"REFRESH_ALL_EPG": "全部重新整理",
"REMOVE_EPG_SOURCE": "移除 EPG 來源",
"EPG_STATUS_FRESH": "已更新",
"EPG_STATUS_STALE": "需要重新整理",
"EPG_STATUS_ERROR": "失敗",
"VIDEO_PLAYER_LABEL": "影片播放器",
"VIDEO_PLAYER_PLACEHOLDER": "選擇一個選項",
"VERSION": "版本",
"SAVE_CHANGES": "儲存變更",
"BACK_TO_HOME": "返回主頁",
"NEW_VERSION_AVAILABLE": "有新版本可用",
"LATEST_VERSION": "您正在使用最新版本",
"LANGUAGE": "語言",
"SETTINGS_SAVED": "成功!設定已儲存。",
"THEME": "視覺主題",
"SHOW_CAPTIONS": "顯示字幕",
"ADD_EPG_SOURCE": "新增 EPG 來源",
"EPG_URL_ERROR": "該值不是有效的網址",
"VIDEO_PLAYER_DESCRIPTION": "選擇預設影片播放器",
"LANGUAGE_DESCRIPTION": "選擇應用程式語言",
"THEME_DESCRIPTION": "選擇應用程式視覺主題",
"SHOW_CAPTIONS_DESCRIPTION": "預設顯示或隱藏字幕",
"VERSION_DESCRIPTION": "應用程式目前版本",
"EPG_NOTE": "目前僅在 Electron 版的 IPTVnator 中提供 EPG。",
"EPG_NOTE_URL_TEXT": "在此處查看",
"IMPORT_EXPORT_DATA": "匯入/匯出播放清單",
"IMPORT_EXPORT_DATA_DESCRIPTION": "以應用程式內使用的 JSON 格式匯出或匯入播放清單。",
"IMPORT_DATA": "匯入",
"EXPORT_DATA": "匯出",
"REMOVE_ALL": "Delete all playlists and playlist data",
"REMOVE_ALL_BUTTON": "Delete all",
"REMOVE_ALL_DESCRIPTION": "Delete every M3U, Xtream, and Stalker playlist stored in the app.",
"REMOVE_DIALOG": {
"TITLE": "Delete all playlists?",
"MESSAGE": "Delete all {{count}} playlists from the app. This also removes stored playlist data on this device.",
"SUMMARY_TITLE": "Playlist sources",
"CONSEQUENCES_TITLE": "This also removes",
"CONSEQUENCE_FAVORITES": "Favorites saved for these playlists",
"CONSEQUENCE_RECENTLY_VIEWED": "Recently viewed history",
"CONSEQUENCE_PLAYBACK": "Saved playback positions",
"CONSEQUENCE_DOWNLOADS": "Download history entries linked to those playlists",
"CONSEQUENCE_XTREAM_CACHE": "Imported Xtream categories and locally cached content",
"BACKUP_HINT": "Use Export first if you want a restorable backup before deleting.",
"CONFIRM": "Delete everything"
},
"IMPORT_ERROR": "匯入錯誤,請嘗試另外一個檔案。",
"PLAYLISTS_REMOVED": "All playlists and playlist data were removed.",
"MPV_PLAYER_PATH_LABEL": "mpv 路徑",
"MPV_PLAYER_PATH_DESCRIPTION": "設定您系統中 mpv 播放器的路徑。將使用提供的 mpv 二進位檔路徑,而非 $PATH 中的預設路徑。",
"MPV_PLAYER_PATH": "mpv 播放器路徑",
"VLC_PLAYER_PATH_LABEL": "VLC 路徑",
"VLC_PLAYER_PATH_DESCRIPTION": "設定您系統中 VLC 播放器的路徑。將使用提供的 VLC 二進位檔路徑,而非系統預設路徑。",
"VLC_PLAYER_PATH": "VLC 播放器路徑",
"REMOTE_CONTROL": "遠端控制",
"REMOTE_CONTROL_DESCRIPTION": "啟用應用程式遠端控制功能。",
"REMOTE_CONTROL_PORT": "遠端控制連接埠",
"REMOTE_CONTROL_PORT_DESCRIPTION": "用於遠端控制應用程式的連接埠。預設使用連接埠 8765。",
"REMOVE_ALL_IN_PROGRESS": "Deleting playlist data…",
"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.",
"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": "深色主題",
"LIGHT_THEME": "亮色主題",
"SYSTEM_THEME": "跟隨系統"
},
"CHANNELS": {
"SEARCH_CHANNEL": "搜尋頻道",
"UPLOAD_OR_SELECT_OTHER_PLAYLIST": "上傳或選擇其他播放清單",
"ALL_CHANNELS": "所有頻道",
"GROUPS": "群組",
"UNGROUPED": "未分組",
"UNNAMED_CHANNEL": "未命名頻道",
"FAVORITES": "我的最愛",
"NO_FAVORITES": "尚無最愛",
"USE_STAR_TO_FAVORITE": "請使用“星星”圖示將頻道新增至此列表。",
"REMOVE_FAVORITE": "從我的最愛中移除",
"FAVORITES_UPDATED": "我的最愛已更新!"
},
"TOP_MENU": {
"OPEN_CHANNELS_LIST": "打開頻道列表",
"TOGGLE_FAVORITE_FLAG": "切換我的最愛標記",
"OPEN_EPG_LIST": "開啟 EPG 列表",
"OPEN_MULTI_EPG": "開啟多 EPG 視圖"
},
"EPG": {
"NEXT_DAY": "下一天",
"PREVIOUS_DAY": "上一天",
"LIVE_NOW": "現在播放",
"LIVE_STREAM": "現場直播",
"TIMESHIFT_AVAILABLE": "時間平移功能可用,點選以播放",
"EPG_NOT_AVAILABLE_DATE": "抱歉,選擇的日期上 EPG 無法使用",
"EPG_NOT_AVAILABLE_CHANNEL_TITLE": "抱歉,此頻道上的 EPG 無法使用。",
"EPG_NOT_AVAILABLE_CHANNEL_DESCRIPTION": "請在應用程式設定中增加/更改 EPG 列表的URL。",
"FETCH_EPG": "取得 EPG 資料...",
"ERROR": "抱歉,無法載入 EPG。",
"DOWNLOAD_SUCCESS": "EPG 已成功下載。",
"PROGRAM_DIALOG": {
"PROGRAM_DETAILS": "關於電視節目的詳細資訊",
"TITLE": "標題",
"CATEGORY": "類別",
"PARENTAL_RATING_SYSTEM": "電視內容分級制度",
"DESCRIPTION": "說明",
"LANGUAGE": "語言",
"SHOW_PROGRAM_DETAILS": "顯示關於該節目的詳細資訊"
}
},
"LANGUAGES": {
"ARABIC": "العربية",
"MOROCCAN_ARABIC": "العربية (اللهجة المغربية)",
"ENGLISH": "English",
"KOREAN": "한국어",
"RUSSIAN": "Русский",
"GERMAN": "Deutsch",
"SPANISH": "Español",
"CHINESE": "简体中文",
"TRADITIONAL_CHINESE": "繁體中文",
"FRENCH": "Français",
"ITALIAN": "Italiano",
"TURKISH": "Türkçe",
"JAPANESE": "日本語",
"DUTCH": "Nederlands",
"BELARUSIAN": "Беларуская",
"POLISH": "Polski",
"PORTUGUESE": "Português",
"GREEK": "Ελληνικά"
},
"YES": "是",
"NO": "否",
"MENU": {
"OPEN": "開啟選單",
"SUPPORT_ARIA": "在 GitHub 上支持 IPTVnator",
"SETTINGS": "設定",
"SETTINGS_ARIA": "開啟設定",
"BUG_REPORT": "回報問題",
"WHAT_IS_NEW": "更新內容",
"ABOUT": "關於",
"ABOUT_ARIA": "關於本應用程式",
"SUPPORT_PROJECT": "支持專案"
},
"ABOUT": {
"TITLE": "關於 IPTVnator",
"DESCRIPTION": "跨平台 IPTV 播放器,具有多種功能,如支援 m3u 和 m3u8 播放清單、我的最愛、電視指南、電視節目存檔/回看等。",
"VERSION": "版本",
"GITHUB_TOOLTIP": "ITPVnator 的 GitHub 專案",
"BUY_ME_A_COFFEE_TOOLTIP": "請我喝杯咖啡",
"TWITTER_TOOLTIP": "在 Twitter 上分享"
},
"UPDATE_AVAILABLE": "有可用的更新",
"REFRESH": "重新整理",
"XTREAM": {
"PLAY": "播放",
"NAME": "名稱",
"RELEASE_DATE": "發行日期",
"GENRE": "類型",
"COUNTRY": "國家",
"ACTORS": "演員",
"DIRECTOR": "導演",
"DURATION": "片長",
"CAST": "演員陣容",
"EPISODE_RUN_TIME": "集數時長",
"RATING": "評分",
"IMDB_RATING": "IMDB 評分",
"KINOPOISK_RATING": "Kinopoisk 評分",
"DESCRIPTION": "描述",
"YEAR": "年份",
"AGE": "年齡",
"YOUTUBE_TRAILER": "YouTube 預告片",
"EPISODE": "集數"
},
"PORTALS": {
"ALL_CATEGORIES": "所有類別",
"MY_FAVORITES": "我的最愛",
"ADD_TO_FAVORITES": "新增至最愛",
"REMOVE_FROM_FAVORITES": "從最愛中移除",
"REMOVED_FROM_FAVORITES": "已從最愛中移除",
"ADDED_TO_FAVORITES": "已新增至最愛",
"SIDEBAR": {
"MAIN": "主頁",
"MOVIES": "電影",
"LIVE_TV": "直播電視",
"SERIES": "影集",
"LIBRARY": "媒體庫",
"SEARCH": "搜尋",
"RECENT": "最近觀看",
"FAVORITES": "我的最愛",
"HOME": "首頁",
"PLAYLIST_INFO": "播放清單資訊",
"ACCOUNT_INFO": "帳戶資訊"
},
"ERROR_VIEW": {
"ACCOUNT_EXPIRED": {
"TITLE": "帳戶已過期",
"DESCRIPTION": "此帳戶已過期。請在播放清單設定中檢查憑證或將其移除。"
},
"UNAUTHORIZED": {
"TITLE": "未授權",
"DESCRIPTION": "請在播放清單設定中檢查憑證或將其移除。"
},
"NOT_FOUND": {
"TITLE": "找不到入口網站",
"DESCRIPTION": "請在播放清單設定中檢查憑證和入口網站網址或將其移除。"
},
"EMPTY_CATEGORY": {
"TITLE": "空類別",
"DESCRIPTION": "此類別沒有內容,請選擇其他類別或更改內容類型"
},
"UNKNOWN_ERROR": {
"TITLE": "發生錯誤",
"DESCRIPTION": "未知錯誤,請稍後再試"
},
"NO_CATEGORY_SELECTED": {
"TITLE": "未選擇類別",
"DESCRIPTION": "請選擇一個類別以查看內容"
},
"PLAYLIST_SETTINGS": "播放清單設定",
"HOME": "首頁",
"DELETE": "刪除"
},
"EMPTY_LIST_VIEW": {
"TITLE": "找不到結果",
"NO_SEARCH_RESULTS": "找不到任何內容,請嘗試更改搜尋條件"
},
"STREAM_URL_COPIED": "串流網址已複製到剪貼簿",
"COPY_STREAM_URL": "複製串流網址",
"SELECT_CATEGORY": "選擇類別",
"SEARCH_VIEW": {
"RESULTS_FOUND": "找到 {{count}} 筆結果",
"NO_RESULTS_FOR": "找不到與「{{term}}」相符的結果"
}
},
"INFORMATION": "資訊",
"REMOTE_CONTROL": {
"TITLE": "遠端控制",
"UP_CHANNEL": "上一頻道",
"DOWN_CHANNEL": "下一頻道",
"HEADER": "IPTVNator 遠端控制",
"FOOTER": "IPTVNator 遠端控制"
},
"WORKSPACE": {
"SHELL": {
"GO_TO_DASHBOARD": "Back to dashboard",
"GO_TO_SOURCES": "Go to Sources",
"DROP_OVERLAY_TITLE": "Drop to add playlist",
"DROP_OVERLAY_BODY": "Release an .m3u or .m3u8 file anywhere in the workspace to import it.",
"DROP_OVERLAY_REJECTED_BODY": "Please drop an .m3u or .m3u8 file. Press Esc to dismiss.",
"DROP_OVERLAY_REJECTED_UNSUPPORTED": "Unsupported file type",
"DROP_OVERLAY_REJECTED_EMPTY": "That file is empty",
"DROP_OVERLAY_REJECTED_READ_ERROR": "Could not read that file",
"DROP_IMPORT_SUCCESS": "Importing \"{{title}}\"…",
"COMMANDS": {
"ADD_PLAYLIST_M3U_LABEL": "Add M3U playlist",
"ADD_PLAYLIST_M3U_DESCRIPTION": "Open add dialog on the M3U file or URL tab",
"ADD_PLAYLIST_XTREAM_LABEL": "Add Xtream Codes playlist",
"ADD_PLAYLIST_XTREAM_DESCRIPTION": "Open add dialog on the Xtream Codes tab",
"ADD_PLAYLIST_STALKER_LABEL": "Add Stalker portal",
"ADD_PLAYLIST_STALKER_DESCRIPTION": "Open add dialog on the Stalker Portal tab"
},
"EXTERNAL_PLAYBACK_CLOSE": "Close player"
},
"GLOBAL_FAVORITES": {
"NO_PLAYLISTS_TITLE": "No favorites to show",
"NO_PLAYLISTS_BODY": "Add a playlist to start collecting favorites from live channels, movies, and series.",
"NO_ITEMS_TITLE": "No favorites yet",
"NO_ITEMS_BODY": "Tap the star icon on any channel, movie, or series to save it here."
},
"GLOBAL_RECENT": {
"NO_PLAYLISTS_TITLE": "Nothing watched yet",
"NO_PLAYLISTS_BODY": "Add a playlist and your watching history will appear here.",
"NO_ITEMS_TITLE": "Nothing watched yet",
"NO_ITEMS_BODY": "Start watching anything from your library and it will show up here."
}
},
"DOWNLOADS": {
"NO_PLAYLISTS_TITLE": "Add a playlist to start downloading",
"NO_PLAYLISTS_BODY": "Once you add a playlist, you can save movies and episodes here for offline playback.",
"NO_ITEMS_BODY": "Use the download button on any movie or episode to save it for offline playback.",
"NO_FILTER_MATCH": "No downloads match the current filter",
"NO_FILTER_MATCH_HINT": "Try a different search term"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 605 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

@@ -0,0 +1,569 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="1024.000000pt" height="1024.000000pt" viewBox="0 0 1024.000000 1024.000000"
preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,1024.000000) scale(0.100000,-0.100000)"
fill="#ffffff" stroke="none">
<path d="M5007 9169 c-8 -11 -39 -46 -68 -78 -113 -120 -113 -121 -101 -133
16 -16 377 -24 387 -9 4 7 -13 36 -39 68 -25 30 -63 82 -84 114 -40 63 -70 75
-95 38z m53 -146 c0 -15 -36 -18 -45 -3 -3 5 -1 19 6 32 11 21 12 21 25 3 8
-10 14 -25 14 -32z"/>
<path d="M3763 9094 c-63 -31 -111 -139 -94 -214 12 -56 39 -99 74 -120 35
-22 97 -26 129 -9 17 9 28 2 86 -58 170 -174 478 -499 572 -603 57 -63 118
-130 134 -148 l31 -33 -32 -24 c-41 -32 -132 -155 -168 -225 -16 -30 -38 -89
-50 -130 l-21 -75 -1319 -1 -1320 0 -56 -22 c-65 -26 -159 -114 -193 -182 -44
-86 -61 -160 -59 -245 10 -313 13 -3440 4 -3955 -10 -567 -10 -620 5 -665 30
-88 79 -160 143 -208 118 -90 229 -121 415 -115 58 2 106 -1 106 -5 0 -13 -41
-89 -71 -134 -16 -23 -68 -113 -115 -200 -84 -155 -181 -309 -206 -331 -8 -6
-125 -15 -293 -21 -154 -6 -300 -15 -325 -21 -25 -5 -71 -9 -103 -10 -50 0
-59 -3 -68 -23 -13 -30 4 -77 29 -77 9 0 29 8 42 18 24 16 230 17 3980 18
3759 1 3957 0 3990 -16 31 -16 38 -16 63 -4 33 18 46 59 24 81 -19 19 -191 32
-447 33 l-176 0 -39 52 c-63 84 -100 141 -305 478 -18 30 -51 81 -73 113 l-39
59 138 -7 c96 -5 157 -4 199 5 135 27 270 131 330 254 46 93 50 123 48 296 -1
80 -4 1122 -6 2316 l-3 2171 -37 77 c-63 132 -156 212 -306 261 -52 17 -125
17 -1383 10 -1200 -6 -1328 -5 -1328 9 0 39 -51 171 -95 244 -26 44 -74 109
-107 144 -32 34 -57 66 -56 70 3 7 474 499 675 705 l119 121 65 -5 c101 -8
154 29 180 128 14 54 6 105 -24 150 -72 106 -203 106 -285 0 -41 -55 -48 -83
-33 -143 l13 -48 -284 -293 c-157 -160 -321 -332 -365 -382 -45 -49 -103 -112
-131 -139 l-50 -48 -44 16 c-23 9 -70 20 -103 24 l-60 7 -3 201 -2 200 -43 -5
-42 -6 -3 -197 -2 -198 -35 0 c-20 0 -60 -9 -89 -19 l-54 -19 -114 117 c-62
64 -219 229 -348 366 -129 138 -262 278 -294 313 l-60 63 11 51 c19 94 -27
180 -113 211 -60 21 -89 21 -131 1z m2575 -130 c12 -14 22 -33 22 -43 0 -28
-49 -71 -81 -71 -57 0 -79 81 -34 126 30 30 58 26 93 -12z m-2454 5 c33 -26
34 -62 1 -94 -24 -25 -68 -33 -92 -17 -11 7 -33 54 -33 71 0 5 9 20 21 35 25
32 66 34 103 5z m1309 -1084 c146 -58 229 -135 294 -275 19 -41 39 -83 44 -92
13 -25 11 -58 -3 -58 -29 0 -58 41 -58 80 0 81 -166 258 -232 248 -19 -3 -17
-8 24 -56 49 -57 148 -228 148 -255 0 -16 -33 -17 -425 -17 -234 0 -428 1
-432 3 -26 9 41 170 109 261 28 37 72 83 97 102 119 88 299 112 434 59z m257
-320 c0 -5 -5 -3 -10 5 -5 8 -10 20 -10 25 0 6 5 3 10 -5 5 -8 10 -19 10 -25z
m-870 -219 c1323 0 2457 1 2520 2 63 1 369 0 680 -2 l565 -3 48 -23 c74 -35
152 -112 188 -185 l31 -64 -3 -1748 c-4 -1845 -4 -1851 6 -2423 5 -271 4 -379
-5 -420 -31 -137 -86 -205 -219 -269 l-76 -36 -3160 -1 c-1738 0 -3193 3
-3233 7 -141 14 -268 105 -309 222 -16 48 -18 87 -14 482 2 237 5 1159 6 2050
2 891 6 1676 10 1743 7 116 9 126 35 155 15 18 37 50 48 73 32 63 133 195 185
240 53 47 154 98 212 109 51 9 75 22 75 40 0 53 -208 16 -316 -57 -46 -30
-195 -231 -225 -302 -28 -68 -39 -58 -39 37 0 118 60 253 140 317 76 60 129
71 305 62 77 -4 1222 -6 2545 -6z m2386 -5283 c97 -8 74 -18 -42 -18 -61 0
-88 4 -91 13 -5 14 18 15 133 5z m400 -22 c-3 -4 4 -17 16 -27 11 -11 65 -78
119 -151 90 -119 145 -180 156 -169 4 4 -57 108 -107 181 -31 46 -90 151 -90
160 0 23 78 -67 162 -185 48 -69 127 -155 134 -147 8 8 -35 96 -83 169 -26 40
-53 89 -60 108 -6 19 -13 31 -13 25 -1 -5 -6 1 -11 14 -12 31 -1 42 17 16 16
-23 20 -29 107 -141 34 -45 78 -103 97 -129 19 -27 46 -55 60 -64 28 -18 32
-26 -43 94 -64 103 -120 219 -115 242 2 12 17 -5 46 -52 24 -39 88 -133 144
-210 55 -77 122 -174 150 -215 64 -97 86 -120 115 -120 36 0 28 52 -14 98 -7
7 -13 22 -13 31 0 29 -26 84 -55 114 -15 16 -24 31 -21 34 9 9 -35 43 -85 64
-42 18 -51 29 -107 128 -34 60 -62 112 -62 116 0 15 82 -80 120 -140 26 -39
58 -72 92 -95 55 -37 79 -69 221 -298 37 -61 67 -113 67 -117 0 -3 -8 -4 -17
-1 -10 3 -130 8 -268 11 -137 3 -262 7 -277 9 -15 2 -46 21 -70 44 -24 22 -68
60 -98 84 -56 45 -84 92 -41 68 12 -6 21 -9 21 -6 0 2 27 -5 61 -15 33 -10 71
-19 82 -19 21 1 21 1 4 11 -10 6 -55 23 -100 38 -145 49 -211 77 -277 117 -36
22 -82 48 -104 59 -21 11 -59 38 -84 61 -40 36 -46 46 -47 84 l-1 42 18 -23
c75 -98 107 -132 131 -145 16 -9 31 -13 34 -11 6 6 -23 64 -36 72 -19 11 -82
125 -79 142 2 10 34 -25 91 -100 86 -114 118 -147 144 -147 23 0 14 18 -63
132 -142 210 -105 195 58 -24 74 -100 113 -138 138 -138 11 0 -38 82 -123 208
-54 78 -70 122 -46 122 5 0 8 -4 5 -9z m-5041 -22 c-9 -26 -43 -67 -68 -81
-17 -9 -17 -7 -7 14 12 22 70 88 78 88 2 0 0 -9 -3 -21z m3405 2 c74 -6 169
-13 210 -17 41 -3 107 -2 145 3 89 13 578 -1 621 -16 17 -7 59 -43 93 -81 59
-66 154 -132 262 -183 88 -41 304 -180 401 -257 59 -47 105 -86 104 -88 -7 -6
-4769 -3 -4839 4 l-75 7 70 66 c94 88 121 107 303 212 175 100 343 216 383
264 48 57 60 60 257 61 99 0 209 4 245 8 65 7 100 3 275 -29 175 -33 439 -20
745 35 97 18 137 20 250 15 88 -4 144 -3 160 4 26 11 154 9 390 -8z m-3161
-42 c-6 -13 -31 -49 -54 -79 -46 -60 -90 -140 -78 -140 5 0 30 25 58 56 42 48
50 54 56 38 6 -15 8 -12 8 12 1 25 53 114 67 114 2 0 1 -19 -2 -42 -6 -49 13
-103 73 -201 23 -38 39 -55 45 -49 7 7 -10 50 -48 126 -39 79 -54 120 -47 127
10 10 25 -10 120 -153 21 -32 44 -60 51 -63 30 -11 30 9 1 58 -54 94 -99 186
-98 204 0 14 3 12 12 -7 6 -14 20 -34 30 -45 21 -22 127 -191 127 -201 0 -20
-123 -86 -201 -107 -30 -9 -95 -27 -144 -40 -50 -14 -137 -45 -195 -70 -58
-24 -114 -47 -124 -51 -15 -5 -17 -9 -8 -18 17 -17 15 -45 -4 -52 -25 -9 -304
-7 -304 3 0 4 17 30 39 57 21 27 61 94 89 149 74 143 92 171 102 155 12 -19
82 18 98 52 14 30 159 188 172 188 19 0 -9 -72 -33 -87 -30 -19 -79 -95 -81
-126 -1 -26 3 -33 22 -35 23 -4 72 31 72 51 0 13 149 205 163 210 21 8 29 -10
16 -34z m356 -127 c25 -40 43 -78 40 -83 -12 -18 -33 -8 -45 21 -7 17 -39 72
-71 122 -33 50 -59 96 -59 102 1 19 89 -86 135 -162z m35 102 c49 -65 74 -120
65 -142 -5 -14 -8 -13 -18 6 -7 12 -31 53 -54 92 -38 61 -53 100 -38 100 2 0
23 -25 45 -56z m137 -37 c13 -27 22 -51 20 -53 -6 -7 -60 64 -79 103 -9 17
-13 35 -10 38 9 9 39 -30 69 -88z m113 40 c0 -8 -11 -24 -25 -37 -22 -21 -25
-22 -25 -5 0 19 27 55 42 55 4 0 8 -6 8 -13z m3850 -17 c20 -20 26 -40 13 -40
-15 0 -73 40 -73 50 0 17 39 11 60 -10z m-4494 -467 c-3 -11 -21 -33 -39 -50
l-32 -31 -110 7 c-60 5 -101 9 -90 9 12 1 26 7 33 14 7 7 46 13 95 14 85 3
117 10 117 25 0 11 23 39 28 34 2 -2 1 -12 -2 -22z"/>
<path d="M7017 7298 c-22 -16 -20 -17 114 -69 65 -25 92 -43 159 -106 104 -98
145 -177 160 -307 13 -123 3 -3516 -11 -3571 -33 -124 -132 -235 -271 -304
-47 -22 -87 -41 -91 -41 -3 0 -18 -5 -34 -12 -99 -40 -127 -41 -1243 -44
-3194 -8 -3280 -8 -3475 14 -351 39 -470 114 -600 376 -38 78 -55 101 -70 101
-27 0 -30 -30 -11 -106 28 -109 73 -188 150 -265 39 -38 94 -83 121 -98 52
-28 165 -63 242 -75 l44 -6 -1 -258 -1 -257 27 -10 c15 -6 29 -8 31 -6 3 3 8
118 11 255 5 230 6 251 22 251 10 0 21 -7 24 -16 3 -9 6 -121 6 -250 l0 -234
30 0 30 0 0 236 0 235 23 -3 22 -3 3 -233 2 -232 29 0 28 0 7 92 c3 50 6 158
6 240 0 138 1 148 19 148 26 0 31 -50 31 -287 l0 -194 28 3 27 3 5 230 c3 127
7 231 8 233 1 1 9 2 17 2 8 0 16 -1 17 -2 1 -2 4 -106 7 -233 l6 -230 27 -3
28 -3 2 233 3 233 25 0 25 0 3 -233 2 -232 30 0 30 0 0 230 c0 219 1 230 19
230 10 0 22 -7 25 -16 3 -9 6 -109 6 -224 l0 -208 29 -4 28 -4 7 120 c3 65 6
167 6 225 l0 106 1778 1 c977 1 1908 2 2067 4 160 1 312 -1 339 -5 l49 -8 -7
-207 c-3 -114 -3 -215 0 -224 3 -9 17 -16 32 -16 l25 0 -7 223 -7 223 28 -2
28 -1 3 -221 2 -222 35 0 35 0 0 220 0 220 25 0 25 0 0 -220 0 -220 35 0 35 0
0 225 c0 218 1 225 20 225 19 0 20 -7 20 -118 0 -66 3 -167 7 -225 l6 -107 29
0 28 0 0 224 c0 124 4 227 9 230 5 4 16 3 25 0 14 -5 16 -35 16 -231 l0 -224
33 3 32 3 5 230 c4 200 7 230 21 233 14 2 17 -19 22 -164 4 -92 7 -198 7 -236
l0 -68 30 0 30 0 0 230 c0 199 2 231 15 237 9 3 19 2 23 -2 4 -3 9 -110 11
-236 l3 -229 34 0 34 0 0 226 c0 225 5 264 35 264 13 0 15 -37 15 -245 l0
-245 30 0 30 0 2 262 3 262 90 18 c191 38 315 130 396 292 36 73 44 100 47
159 4 65 3 69 -12 56 -41 -35 -56 -56 -96 -134 -85 -169 -171 -232 -411 -305
-124 -38 -152 -42 -379 -61 -248 -21 -572 -21 -593 0 -5 5 14 16 45 26 105 34
183 83 262 164 95 98 132 172 146 292 7 55 10 691 8 1829 -3 1629 -4 1749 -21
1803 -37 126 -117 243 -209 311 -79 57 -269 96 -311 64z"/>
<path d="M8127 7298 l-28 -10 23 -20 c13 -11 57 -36 98 -56 100 -48 198 -146
259 -260 48 -89 63 -107 85 -99 21 8 10 76 -26 164 -33 81 -123 187 -192 228
-81 47 -171 69 -219 53z"/>
<path d="M3440 7190 c-1238 -6 -1245 -6 -1308 -27 -92 -32 -140 -63 -218 -145
-60 -63 -74 -86 -104 -163 -28 -75 -35 -108 -40 -200 -8 -144 -3 -3027 5
-3169 6 -101 9 -116 49 -200 75 -160 164 -233 335 -277 61 -16 134 -21 376
-29 378 -12 4200 -4 4345 9 231 20 372 110 441 280 l23 56 2 868 c1 477 -1
869 -5 871 -3 2 -41 1 -83 -1 l-77 -6 -1 -533 0 -534 44 0 c35 0 48 -5 56 -19
19 -37 12 -58 -21 -65 -17 -3 -203 -6 -414 -6 l-382 0 -6 -182 c-4 -99 -7
-286 -7 -414 0 -216 -1 -232 -17 -229 -10 2 -355 6 -768 9 -412 3 -762 9 -777
12 -27 6 -37 27 -19 38 25 16 304 26 491 19 l206 -8 0 167 c0 115 -3 164 -11
159 -25 -21 -252 -102 -337 -122 -189 -43 -215 -48 -295 -55 l-83 -7 0 -103 0
-104 -50 0 -50 0 0 105 0 105 -59 0 c-130 0 -447 71 -584 131 -77 34 -134 67
-360 206 l-52 31 -8 -36 c-5 -21 -6 -73 -2 -117 3 -44 5 -123 4 -175 -5 -207
-8 -185 26 -182 70 7 915 6 968 -2 45 -6 57 -11 55 -24 -2 -8 -14 -19 -28 -22
-40 -11 -773 -21 -957 -14 l-168 7 1 286 c0 157 4 301 9 320 7 34 5 37 -77
114 l-85 80 -282 1 -281 1 0 -377 0 -376 315 -1 c173 -1 322 -4 330 -7 24 -10
18 -41 -10 -48 -14 -4 -176 -6 -360 -6 -185 1 -340 -2 -345 -5 -17 -10 -20 79
-18 452 l3 373 -445 2 -445 3 -3 33 c-2 23 2 38 13 46 15 11 18 59 26 432 8
361 19 548 31 559 2 1 20 5 41 9 l39 7 -4 -500 -3 -501 63 0 64 0 -3 534 -3
533 -90 7 c-49 3 -115 6 -148 6 l-58 0 0 40 c0 40 0 40 38 40 l37 0 4 520 c4
547 4 550 -40 550 -15 0 -19 7 -19 34 l0 33 133 6 c72 3 277 5 454 4 l321 -2
-2 402 -2 401 43 4 43 3 0 -396 0 -396 288 4 287 4 65 65 65 64 0 138 c0 75 4
222 9 325 l9 189 30 -6 c16 -3 37 -6 47 -6 10 0 20 -10 23 -21 5 -19 10 -20
39 -14 59 13 285 16 446 6 159 -11 202 -17 202 -31 0 -17 -44 -21 -262 -27
l-228 -6 0 -149 c0 -81 1 -148 3 -148 2 0 32 14 68 31 75 37 297 112 413 140
45 10 106 19 137 19 31 0 97 3 148 7 l92 6 -3 99 -3 98 32 0 c17 0 38 3 47 6
14 5 16 -7 16 -100 l0 -106 38 0 c20 0 109 -9 197 -19 131 -16 187 -28 305
-66 80 -26 156 -54 168 -62 13 -8 25 -13 27 -11 7 8 15 244 8 255 -5 7 -65 14
-162 20 -102 5 -156 12 -158 20 -6 16 121 27 224 19 76 -5 82 -4 88 14 5 16
15 20 50 20 l43 0 2 -192 c0 -131 4 -196 12 -206 15 -18 119 -87 170 -113 30
-15 38 -17 38 -5 0 7 21 37 46 65 l46 51 -100 0 c-89 0 -100 2 -105 19 -2 10
-2 23 2 29 3 5 52 14 109 18 l102 9 -94 96 c-86 87 -120 139 -102 157 4 3 13
2 20 -3 7 -6 35 -26 61 -45 76 -54 130 -106 151 -145 21 -40 30 -43 39 -14 9
28 142 167 176 185 15 7 34 11 42 8 25 -9 7 -45 -47 -99 -28 -27 -67 -70 -87
-95 l-36 -45 99 -1 c55 -1 102 -4 105 -7 3 -4 3 -18 -1 -32 -6 -25 -7 -25
-111 -25 -58 0 -105 -4 -105 -9 0 -4 43 -49 95 -100 53 -50 93 -96 90 -101 -9
-15 -72 -12 -105 5 -30 16 -61 66 -74 120 -19 76 -52 73 -133 -12 l-64 -68 79
-75 c44 -41 87 -90 98 -107 l18 -33 127 0 c70 0 134 -2 141 -5 14 -5 15 142 5
648 l-2 137 41 0 41 0 6 -232 c4 -128 7 -308 7 -399 l0 -166 413 -7 c226 -4
420 -9 430 -12 9 -3 17 -12 17 -19 0 -9 -6 -12 -15 -9 -10 4 -18 -3 -25 -20
-8 -22 -16 -26 -48 -26 l-39 0 -6 -297 c-9 -397 -9 -612 -1 -704 l6 -76 57 -6
c31 -3 63 -8 73 -12 12 -5 18 1 22 22 3 15 4 397 2 848 -4 850 -4 864 -46 945
-46 90 -156 179 -285 230 -56 22 -75 24 -280 27 -476 6 -2112 8 -3295 3z
m2676 -141 c32 -8 41 -14 32 -20 -26 -17 -238 -7 -238 12 0 19 140 24 206 8z
m-3094 -72 c23 -18 71 -70 107 -115 l63 -83 14 26 c8 15 43 60 80 100 69 78
142 121 166 97 22 -22 -3 -61 -81 -126 -44 -36 -88 -81 -99 -99 l-19 -34 55 9
c31 5 83 8 116 6 55 -3 61 -5 58 -23 -7 -48 -7 -48 -107 -42 -57 4 -95 3 -95
-3 0 -16 57 -75 115 -120 30 -23 55 -50 55 -59 0 -25 -29 -61 -48 -61 -24 0
-121 102 -166 173 -20 32 -42 57 -49 54 -7 -2 -27 -23 -45 -48 -126 -170 -161
-201 -188 -164 -8 11 -12 25 -9 32 2 8 41 58 85 112 44 53 80 100 80 102 0 3
-30 2 -67 -2 -110 -13 -113 -12 -113 16 0 21 5 25 33 27 46 2 129 -2 150 -8 9
-3 17 -2 17 3 0 4 -43 55 -95 112 -63 69 -95 112 -95 128 0 33 30 30 82 -10z
m-452 -12 c14 -25 11 -29 -102 -142 l-115 -115 121 -118 121 -118 -24 -26
c-16 -17 -27 -22 -32 -15 -9 15 -207 217 -221 225 -6 4 -63 -46 -127 -109
-106 -106 -118 -115 -134 -102 -12 8 -17 21 -13 32 3 10 54 67 114 126 l108
108 -110 108 -110 109 18 28 19 27 113 -114 113 -115 118 118 c65 65 120 118
124 118 3 0 12 -11 19 -25z m4399 -130 c48 50 96 103 107 119 l21 29 22 -31
22 -31 -112 -108 -111 -108 33 -25 c44 -32 199 -181 199 -191 0 -4 -8 -17 -19
-30 l-19 -23 -107 112 c-59 62 -111 112 -116 112 -4 0 -58 -52 -120 -115 -62
-64 -117 -114 -122 -112 -6 2 -17 13 -25 25 -13 20 -8 27 102 134 l117 112
-111 111 c-60 60 -110 114 -110 119 0 5 8 18 18 29 17 19 20 17 130 -99 l113
-119 88 90z m-4835 -3136 c8 -11 51 -58 96 -104 l82 -84 56 62 c65 71 182 187
189 187 3 0 13 -10 23 -22 18 -23 17 -23 -101 -149 l-119 -126 59 -54 c32 -30
84 -82 116 -116 l57 -63 -20 -24 -19 -25 -118 120 -119 121 -114 -116 c-64
-64 -118 -116 -122 -116 -4 0 -15 9 -25 20 -17 19 -15 22 84 128 55 60 107
114 114 120 11 9 -11 37 -105 132 -118 120 -119 120 -102 145 l16 25 29 -21
c16 -11 35 -29 43 -40z m914 19 c33 -15 51 -34 81 -86 58 -98 69 -110 80 -92
44 72 131 171 163 185 41 20 68 15 68 -12 0 -21 -36 -83 -48 -83 -11 0 -108
-94 -120 -116 -10 -18 -5 -19 99 -16 109 4 109 4 109 -20 0 -48 -9 -51 -119
-41 -55 4 -101 5 -101 2 0 -4 44 -48 97 -97 85 -79 96 -92 84 -106 -37 -44
-144 13 -200 108 l-34 57 -43 -61 c-60 -82 -158 -150 -182 -126 -10 11 25 67
93 146 35 41 64 77 65 80 0 3 -47 3 -105 2 l-105 -4 0 32 0 31 100 -7 c70 -5
100 -4 100 4 0 6 -40 54 -90 105 -68 72 -90 101 -90 122 0 25 3 27 28 20 15
-3 46 -15 70 -27z m3740 -84 l111 -116 112 116 113 117 25 -26 26 -25 -112
-113 -111 -112 104 -110 c57 -60 103 -116 102 -124 -2 -7 -12 -19 -23 -27 -18
-12 -28 -4 -125 102 l-104 114 -122 -121 -121 -120 -16 25 c-10 14 -17 27 -17
29 0 2 51 54 112 115 l113 111 -117 118 -117 118 21 22 c12 13 25 23 28 23 4
0 57 -52 118 -116z m-2908 -283 c0 -108 -10 -133 -52 -129 l-33 3 -3 103 -3
102 46 0 45 0 0 -79z"/>
<path d="M7919 7161 c-63 -20 -153 -78 -193 -123 -24 -26 -57 -78 -72 -115
-26 -62 -29 -79 -29 -188 0 -117 1 -122 36 -196 48 -99 96 -151 177 -191 61
-30 76 -33 180 -37 110 -3 115 -2 176 28 34 17 85 52 112 78 50 48 113 154
118 196 1 13 5 27 8 32 3 6 6 37 7 71 3 79 -27 168 -85 255 -52 79 -89 109
-191 156 -80 37 -189 52 -244 34z m146 -196 l0 -115 -39 0 -39 0 7 107 c8 109
13 123 51 123 19 0 20 -7 20 -115z m-151 51 c-5 -12 -46 -36 -62 -36 -9 0 51
49 60 50 4 0 5 -6 2 -14z m312 -57 c16 -7 64 -75 64 -92 0 -11 -18 -18 -72
-27 -40 -6 -78 -13 -85 -15 -21 -7 -22 7 -3 59 11 28 21 69 24 91 2 22 5 42 5
45 1 2 14 -9 29 -26 16 -17 33 -33 38 -35z m-333 -48 c38 -40 55 -65 51 -75
-8 -21 -19 -20 -94 9 -35 14 -72 25 -82 25 -17 0 -17 2 -3 37 34 81 54 82 128
4z m-19 -137 c44 -6 46 -8 46 -40 l0 -34 -97 4 -98 3 -3 37 -3 36 54 0 c30 0
75 -3 101 -6z m194 -38 c4 -33 -13 -56 -42 -56 -28 0 -46 18 -46 46 0 57 82
66 88 10z m193 34 l69 0 0 -30 0 -30 -100 0 -100 0 0 36 c0 36 1 36 31 30 17
-3 62 -6 100 -6z m-333 -145 c2 -14 -17 -38 -62 -78 l-65 -58 -15 28 c-23 47
-36 102 -21 97 6 -3 36 4 66 15 66 24 93 23 97 -4z m257 3 c14 -6 25 -16 25
-22 0 -6 5 -5 12 2 16 16 88 16 88 0 0 -23 -89 -128 -104 -122 -29 11 -96 108
-96 138 0 19 38 21 75 4z m-125 -41 c0 -19 3 -68 6 -110 l7 -77 -39 0 -39 0
-3 104 c-3 102 -2 105 20 109 46 9 48 7 48 -26z m-131 -114 c1 -30 -2 -33 -27
-33 -30 0 -52 16 -52 37 0 7 15 29 33 49 l32 37 6 -29 c4 -16 7 -44 8 -61z
m241 -17 c-19 -24 -40 -19 -40 8 0 29 19 39 39 20 12 -11 12 -16 1 -28z"/>
<path d="M3676 6943 c-3 -42 -6 -145 -6 -229 l0 -153 63 43 c44 31 61 49 59
62 -1 10 -5 91 -9 179 -4 99 -10 163 -17 167 -6 4 -27 8 -47 8 l-36 0 -7 -77z"/>
<path d="M4549 6800 c-110 -10 -406 -95 -524 -149 -269 -125 -461 -294 -648
-574 -176 -262 -261 -519 -291 -869 l-5 -58 54 0 c29 0 60 -3 69 -6 14 -5 16
6 16 85 l0 91 30 0 30 0 0 -87 0 -88 76 0 76 0 -4 93 -4 92 39 0 38 0 -3 -90
-3 -90 84 0 83 0 -4 90 -4 90 33 0 32 0 3 -91 3 -91 83 -1 83 -2 -3 93 -3 92
38 0 37 0 0 -92 0 -93 80 3 80 4 0 89 0 89 35 0 35 0 0 -205 0 -205 -29 0
c-35 0 -41 16 -41 110 l0 65 -80 0 -80 0 0 -87 0 -88 -35 0 -35 0 0 88 0 87
-80 0 -80 0 0 -88 0 -88 -32 3 -33 3 -3 85 -3 85 -82 -2 -82 -2 3 -86 2 -86
-32 3 -33 3 -5 85 -5 85 -73 0 -72 0 0 -87 0 -88 -30 0 -30 0 0 85 0 85 -70 0
-70 0 0 -97 c0 -318 132 -682 340 -940 64 -80 244 -259 315 -313 81 -62 282
-179 405 -237 128 -61 167 -71 395 -108 135 -22 170 -24 225 -16 36 6 94 13
130 16 130 12 361 55 422 79 122 47 277 125 396 200 101 64 140 97 245 206
263 273 419 571 472 900 23 143 23 517 0 643 -47 265 -143 499 -294 722 -72
107 -273 305 -386 382 -196 133 -421 225 -630 259 -115 19 -436 27 -566 14z
m1054 -298 c26 -24 27 -30 27 -116 0 -107 6 -121 43 -107 24 9 26 16 29 70 l3
61 108 -77 c112 -78 170 -140 266 -283 61 -91 172 -326 211 -445 33 -104 52
-245 32 -245 -6 0 -14 5 -17 10 -8 14 -96 13 -152 -2 -35 -8 -50 -8 -64 1 -17
10 -129 15 -339 13 -36 0 -115 0 -176 0 -72 0 -114 -4 -119 -12 -5 -8 -10 -8
-20 0 -7 6 -53 12 -102 13 -79 2 -91 0 -120 -22 -20 -15 -50 -26 -84 -29 l-53
-5 20 34 c11 19 33 55 48 82 17 28 23 47 16 47 -18 0 -99 -62 -139 -105 -50
-55 -56 -40 -56 135 l0 149 -65 3 -65 3 -3 352 -2 353 249 0 c137 0 255 2 264
6 19 7 27 48 27 133 0 117 -3 115 108 58 53 -27 109 -61 125 -75z m-1409 77
c3 -17 6 -58 6 -90 0 -32 4 -69 10 -83 l10 -26 255 0 255 0 0 -55 0 -55 -90 0
c-49 0 -90 3 -90 8 0 4 -134 6 -299 4 l-299 -3 -6 53 c-3 29 -7 79 -8 112 -2
69 1 73 127 129 101 46 121 47 129 6z m-290 -156 c3 -21 6 -59 6 -85 l0 -48
-112 0 -112 0 39 41 c41 43 151 129 165 129 4 0 10 -17 14 -37z m682 -769 c-3
-26 -6 -70 -6 -98 l0 -51 -15 29 c-18 34 -20 137 -3 154 23 23 31 12 24 -34z
m218 -50 c14 -5 16 -35 16 -229 l0 -223 33 -5 c17 -3 93 -3 168 0 152 7 204 0
214 -25 14 -37 -19 -43 -223 -40 l-192 3 0 -232 0 -233 -35 0 -34 0 5 158 c2
86 6 190 8 230 l4 72 -245 0 -245 0 7 33 c9 37 20 47 58 47 23 0 27 3 22 23
-12 46 -22 127 -17 132 9 8 62 6 62 -3 0 -5 -7 -31 -15 -58 -23 -76 -20 -91
18 -97 17 -4 104 -9 191 -13 l159 -7 -7 220 c-6 196 -5 222 9 237 19 18 18 18
39 10z m552 -371 l-1 -88 83 -5 82 -5 0 93 0 92 30 0 30 0 0 -89 0 -90 85 -3
85 -3 0 93 0 92 36 0 36 0 -4 -89 -3 -90 82 -3 82 -3 3 90 3 90 33 3 32 3 0
-93 0 -94 68 7 c37 4 70 5 75 2 4 -2 7 34 7 81 0 47 3 86 8 86 4 0 17 3 30 6
22 6 22 5 22 -85 l0 -91 79 0 c63 0 80 -3 85 -16 11 -28 -4 -34 -85 -34 l-79
0 0 -85 c0 -84 0 -85 -25 -85 -20 0 -25 6 -31 34 -3 19 -4 58 -2 88 l3 53 -81
0 -81 1 5 -89 5 -88 -34 3 -34 3 -3 85 -3 85 -82 -2 -82 -2 3 -81 4 -81 -34 3
-33 3 -3 93 c-2 83 -4 91 -18 77 -11 -10 -36 -15 -85 -15 l-69 0 0 -85 0 -85
-30 0 -30 0 0 97 c0 75 -3 94 -12 85 -7 -7 -41 -12 -84 -12 l-71 0 1 -82 1
-83 -30 0 -30 0 -3 192 -2 192 27 4 c16 2 31 5 34 6 3 0 5 -38 5 -86z m-972
-246 c11 -42 11 -42 -26 -51 -27 -6 -28 -5 -28 37 0 24 3 47 7 51 16 16 39 -2
47 -37z m-318 -104 c5 -10 10 -197 12 -416 l3 -398 -29 3 -30 3 -6 376 c-3
238 -1 390 5 413 11 39 31 47 45 19z m497 -155 c8 -207 9 -653 2 -660 -3 -3
-16 -3 -29 -1 l-23 5 -6 405 c-3 224 -4 410 -1 415 3 4 15 8 28 8 23 0 23 -1
29 -172z m-979 145 c4 -16 10 -576 7 -735 l-1 -68 -38 0 c-45 0 -54 9 -136
127 -99 143 -177 336 -221 548 -25 117 -30 110 83 109 53 -1 122 -4 153 -8 44
-6 63 -4 88 8 17 9 31 21 31 26 0 17 28 11 34 -7z m896 -62 c-7 -45 -10 -193
-8 -402 3 -297 1 -333 -13 -342 -9 -6 -24 -7 -33 -4 -14 6 -16 45 -16 399 l0
393 38 16 c20 9 38 15 40 14 1 -1 -2 -34 -8 -74z m698 -321 c-3 -336 -5 -400
-17 -400 -12 0 -13 37 -8 243 9 308 19 557 24 557 2 0 2 -180 1 -400z m-1322
356 l24 -6 0 -385 0 -385 -30 0 -30 0 1 408 c1 224 3 400 6 390 2 -9 15 -19
29 -22z m1283 -86 c-2 -84 -3 -89 -9 -45 -12 75 -12 173 0 155 5 -8 9 -58 9
-110z m533 23 c6 -295 2 -703 -7 -700 -14 5 -19 797 -5 797 6 0 11 -40 12 -97z
m-1392 -312 l0 -399 -26 -6 c-15 -4 -29 -4 -33 -1 -9 9 -14 582 -6 703 l7 102
29 0 29 0 0 -399z m970 -56 c2 -185 6 -280 10 -235 5 56 7 63 8 30 1 -25 5
-62 8 -82 6 -35 5 -38 -17 -38 l-24 0 -1 393 c0 215 3 358 6 317 4 -41 9 -214
10 -385z m193 56 c-2 -207 -7 -377 -11 -379 -4 -1 -9 10 -11 25 -6 53 11 755
19 743 4 -7 6 -182 3 -389z m493 20 c3 -369 1 -411 -23 -411 -13 0 -14 11 -9
63 3 34 7 211 8 394 2 202 6 326 12 316 5 -9 10 -172 12 -362z m409 327 c-13
-94 -73 -319 -99 -372 -14 -28 -40 -73 -58 -101 l-32 -50 -7 45 c-4 25 -8 150
-9 279 l-1 234 78 -2 c43 -1 85 3 93 9 34 22 42 12 35 -42z m-2560 -726 c-5
-29 -10 -33 -33 -30 l-27 3 -3 358 c-1 197 1 372 6 390 6 22 16 33 33 37 l24
6 3 -366 c1 -201 0 -380 -3 -398z m587 376 c3 -216 2 -397 -3 -401 -12 -15
-46 2 -53 26 -8 29 -8 715 0 745 4 14 14 22 29 22 l23 0 4 -392z m-696 368 c1
-1 3 -172 5 -381 l4 -380 -30 -3 -30 -3 -2 391 -3 390 28 -6 c15 -4 28 -7 28
-8z m502 -378 l-3 -393 -25 0 -25 0 -3 384 c-2 403 -3 400 41 401 16 0 17 -23
15 -392z m1212 1 c0 -246 -4 -379 -10 -379 -6 0 -10 135 -10 386 0 254 3 383
10 379 6 -4 10 -143 10 -386z m112 -122 c2 -190 0 -247 -9 -247 -10 0 -12 86
-11 383 1 303 3 354 9 247 4 -74 9 -246 11 -383z m116 127 c-3 -325 -5 -374
-18 -374 -13 0 -15 49 -15 378 -1 207 1 359 2 337 2 -22 7 -110 12 -195 l9
-155 -2 197 c0 108 2 194 7 191 4 -2 6 -173 5 -379z m123 -328 c-7 -55 -27
-72 -37 -31 -3 14 -1 130 5 258 6 128 11 273 11 322 0 50 4 108 8 130 9 49 22
-609 13 -679z m105 590 c3 -52 9 -83 14 -76 5 7 6 55 3 107 -5 76 -3 93 8 93
12 0 13 -24 7 -142 -4 -79 -7 -252 -7 -385 -1 -237 -1 -243 -21 -243 -20 0
-20 5 -19 388 1 213 3 378 5 367 2 -11 6 -60 10 -109z m244 -78 c0 -112 3
-246 6 -298 5 -66 2 -109 -7 -140 -13 -42 -14 -33 -21 160 -7 222 0 480 13
480 5 0 9 -91 9 -202z m-2106 155 c3 -21 6 -194 6 -385 l0 -348 -35 0 -35 0 0
385 0 385 29 0 c25 0 29 -4 35 -37z m1347 -50 c5 -384 3 -673 -6 -670 -12 4
-15 757 -3 757 4 0 9 -39 9 -87z m198 -492 c1 -63 4 -92 11 -85 6 6 11 138 13
334 l2 325 2 -372 c2 -304 0 -373 -11 -373 -22 0 -26 58 -30 410 -3 310 -3
317 4 95 4 -132 8 -283 9 -334z m264 472 c11 -171 8 -653 -3 -653 -6 0 -10 53
-11 138 -4 512 -3 622 2 622 3 0 9 -48 12 -107z m202 -267 c0 -206 -4 -378 -8
-382 -14 -15 -28 20 -22 56 2 19 5 185 5 368 0 259 3 332 13 332 9 0 12 -82
12 -374z m-980 32 c-4 -178 -8 -343 -9 -368 -1 -39 -4 -45 -21 -42 -11 2 -21
5 -21 5 -7 8 -4 487 3 537 6 47 8 -14 6 -220 -2 -284 8 -397 20 -219 11 147 8
557 -3 564 -5 3 -10 19 -10 36 0 23 4 29 21 29 l22 0 -8 -322z m42 94 c1 -120
4 -281 8 -359 5 -125 4 -143 -9 -143 -14 0 -16 42 -16 367 0 201 3 363 8 359
4 -4 8 -105 9 -224z m976 -24 c4 -134 10 -285 14 -335 4 -62 2 -93 -4 -93 -7
0 -13 54 -17 143 -9 203 -12 536 -5 531 3 -2 9 -113 12 -246z m-751 -55 c-8
-30 -10 -6 -9 112 l0 150 10 -112 c6 -74 6 -125 -1 -150z m-162 -120 c0 -191
-4 -304 -10 -308 -7 -4 -10 104 -10 317 0 212 4 318 10 308 6 -9 10 -139 10
-317z m-476 226 c8 -41 17 -180 20 -310 l6 -237 -25 -4 c-13 -3 -27 -3 -30 0
-3 3 -5 149 -5 326 0 331 6 374 34 225z m433 4 c-3 -10 -5 -4 -5 12 0 17 2 24
5 18 2 -7 2 -21 0 -30z m-155 -315 c3 -147 0 -218 -7 -218 -7 0 -9 77 -6 237
5 283 9 277 13 -19z m-106 155 c-3 -43 -9 -142 -12 -221 -6 -129 -9 -144 -28
-157 -11 -8 -24 -15 -28 -15 -10 0 -10 217 -1 363 l6 107 35 0 35 0 -7 -77z
m391 -285 c-1 -51 -3 -12 -3 87 0 99 2 141 3 93 2 -48 2 -129 0 -180z m-360
-335 c-5 -130 -4 -164 6 -154 8 8 13 62 16 161 l3 148 27 -3 26 -2 -3 -104
c-1 -57 -5 -128 -8 -156 -4 -44 -3 -53 10 -53 13 0 16 23 18 157 3 143 5 158
21 161 17 4 18 -6 15 -152 -2 -120 0 -156 10 -156 9 0 12 38 12 154 l0 155 31
-1 32 -1 -7 -141 c-4 -78 -11 -143 -17 -144 -13 -5 -1 -22 16 -22 10 0 15 36
20 155 7 141 9 155 26 155 17 0 18 -10 12 -155 -4 -138 -3 -155 11 -155 14 0
16 20 16 155 0 127 3 155 14 155 19 0 29 -92 24 -218 -2 -69 0 -92 10 -92 9 0
12 38 12 155 0 85 4 155 8 155 26 0 32 -30 32 -167 0 -89 4 -143 10 -143 6 0
10 57 10 150 0 143 1 150 20 150 11 0 19 -3 19 -7 -1 -5 -1 -73 0 -153 1 -94
5 -139 11 -129 5 9 8 78 7 155 -2 115 0 139 12 139 11 0 14 -15 12 -68 -1 -37
1 -109 6 -160 l8 -92 5 160 c7 210 23 211 31 2 3 -86 9 -160 12 -164 4 -3 5
68 4 158 -2 153 -1 164 16 164 17 0 19 -13 20 -176 l2 -175 -41 -27 c-23 -15
-58 -34 -77 -42 -57 -24 -282 -66 -388 -72 -97 -6 -99 -6 -108 18 -9 22 -10
22 -10 -11 -2 -61 -20 -110 -41 -110 -18 0 -20 7 -20 78 0 42 -3 109 -6 147
-4 51 -3 66 5 55 8 -11 11 33 11 158 l0 172 42 0 41 0 -6 -167z m-917 9 c0
-92 -3 -132 -10 -122 -13 20 -13 273 0 265 6 -4 10 -62 10 -143z m380 -13 c0
-93 -4 -149 -10 -149 -6 0 -10 59 -10 156 0 101 3 153 10 149 6 -4 10 -67 10
-156z m270 42 c0 -142 -8 -205 -25 -191 -10 8 -12 45 -9 148 5 147 8 167 24
157 6 -4 10 -52 10 -114z m50 -36 c0 -131 -2 -155 -15 -155 -13 0 -15 23 -15
148 0 82 3 152 7 155 19 20 23 -6 23 -148z m60 0 c0 -131 -2 -155 -15 -155
-13 0 -15 24 -15 155 0 131 2 155 15 155 13 0 15 -24 15 -155z m60 77 c0 -121
-11 -232 -24 -232 -8 0 -10 47 -8 155 2 127 6 155 17 155 12 0 15 -17 15 -78z
m-750 -77 c0 -90 -4 -145 -10 -145 -6 0 -10 53 -10 138 0 122 3 152 17 152 2
0 3 -65 3 -145z m49 -7 l-2 -153 -8 140 c-8 131 -7 165 6 165 3 0 4 -69 4
-152z m56 7 c7 -128 4 -169 -9 -154 -8 9 -14 299 -6 299 4 0 11 -65 15 -145z
m54 -153 c-7 -17 -19 114 -19 213 0 39 3 75 8 79 9 9 20 -273 11 -292z m90
200 c-1 -48 -5 -116 -9 -152 -5 -51 -7 -32 -8 93 -1 103 1 156 8 152 6 -3 9
-45 9 -93z m133 -19 l1 -118 12 120 c15 157 26 128 17 -45 l-7 -135 -32 -2
-33 -3 0 134 c0 142 4 166 26 166 11 0 14 -24 16 -117z m77 -100 c1 -68 -2
-83 -14 -83 -13 0 -15 23 -15 143 0 79 3 147 8 151 8 9 19 -96 21 -211z m54
120 c12 -174 10 -203 -13 -203 -19 0 -20 7 -20 150 0 119 3 150 13 150 10 0
16 -26 20 -97z m982 -35 c8 -161 6 -192 -17 -196 -17 -3 -18 10 -18 162 0 136
3 166 14 166 11 0 15 -29 21 -132z m59 95 c7 -47 6 -198 -3 -237 -3 -16 -11
-31 -17 -33 -12 -4 -27 267 -17 293 10 27 30 13 37 -23z m56 -95 c-4 -116 -7
-133 -22 -136 -16 -3 -18 8 -18 132 0 134 0 136 23 136 22 0 22 0 17 -132z
m63 35 c-5 -119 -8 -139 -28 -147 -13 -5 -15 12 -15 119 0 124 0 125 23 125
23 0 23 -1 20 -97z m47 3 c0 -71 -4 -97 -15 -106 -13 -11 -15 0 -15 94 0 88 3
106 15 106 12 0 15 -17 15 -94z m160 58 c-8 -35 -23 -51 -70 -76 -14 -7 -33
-23 -43 -35 -10 -13 -23 -23 -28 -23 -5 0 -9 38 -9 84 l0 84 79 1 79 1 -8 -36z
m-1683 -191 c-1 -43 -3 -10 -3 72 0 83 2 118 3 78 2 -40 2 -107 0 -150z"/>
<path d="M5723 4200 c0 -36 2 -50 4 -32 2 17 2 47 0 65 -2 17 -4 3 -4 -33z"/>
<path d="M5023 3910 c0 -41 2 -58 4 -37 2 20 2 54 0 75 -2 20 -4 3 -4 -38z"/>
<path d="M5022 3790 c0 -19 2 -27 5 -17 2 9 2 25 0 35 -3 9 -5 1 -5 -18z"/>
<path d="M5793 3915 c0 -22 2 -30 4 -17 2 12 2 30 0 40 -3 9 -5 -1 -4 -23z"/>
<path d="M3185 6230 c-60 -4 -159 -8 -218 -9 l-109 -1 4 -540 3 -540 62 0 63
0 0 45 c0 111 33 337 69 470 35 126 108 293 170 385 20 30 49 75 63 100 14 25
35 54 47 64 12 11 21 23 21 28 0 9 -4 8 -175 -2z"/>
<path d="M6180 6233 c0 -3 27 -46 60 -94 33 -48 77 -126 96 -174 20 -47 40
-85 45 -85 11 0 12 137 3 268 l-7 92 -98 0 c-55 0 -99 -3 -99 -7z"/>
<path d="M7873 6220 c-60 -24 -149 -109 -181 -174 -59 -118 -49 -302 24 -417
60 -96 182 -153 329 -153 71 -1 87 3 145 33 117 59 185 146 215 273 42 181
-51 366 -213 429 -84 32 -248 37 -319 9z m187 -360 c0 -272 -1 -290 -17 -289
-49 2 -48 -4 -50 297 l-2 282 34 0 34 0 1 -290z m-130 0 c0 -184 -3 -270 -11
-270 -6 0 -20 5 -31 11 -20 11 -20 15 -13 257 6 209 9 249 23 260 9 6 19 12
24 12 4 0 8 -121 8 -270z m238 -2 c2 -253 2 -257 -19 -263 -11 -4 -23 -4 -26
-1 -7 7 -8 64 -5 314 l2 213 23 -3 22 -3 3 -257z m-348 70 c0 -73 -3 -164 -7
-201 l-6 -68 -18 28 c-56 88 -38 373 23 373 4 0 8 -60 8 -132z m447 113 c41
-39 43 -284 2 -350 -24 -40 -35 -39 -44 5 -8 43 5 364 15 364 3 0 16 -9 27
-19z"/>
<path d="M6480 6210 c0 -3 0 -126 0 -273 1 -244 3 -287 30 -470 17 -111 30
-230 30 -264 l0 -63 48 0 49 0 -4 488 c-2 268 -6 511 -9 540 l-6 53 -69 -3
c-38 -2 -69 -5 -69 -8z"/>
<path d="M2036 6179 c-3 -17 -6 -259 -6 -537 l0 -505 38 7 c20 3 47 6 60 6
l22 0 0 508 c0 279 -3 517 -6 530 -5 19 -13 22 -54 22 -45 0 -48 -2 -54 -31z"/>
<path d="M2265 6192 c-3 -8 -5 -36 -5 -63 l0 -50 48 3 c44 3 47 5 50 32 2 16
1 44 -2 62 -6 30 -9 32 -46 30 -23 0 -42 -7 -45 -14z"/>
<path d="M2467 6204 c-4 -4 -7 -218 -7 -476 0 -394 -2 -474 -15 -505 -21 -49
-20 -97 1 -89 9 3 44 6 79 6 l63 0 4 193 c2 144 0 194 -9 202 -10 8 -14 91
-15 340 l-3 330 -45 3 c-25 2 -49 0 -53 -4z"/>
<path d="M2666 5883 c-3 -181 -9 -404 -12 -496 -3 -93 -3 -188 1 -213 l6 -44
66 0 66 0 -7 38 c-3 20 -6 263 -6 540 l0 502 -54 0 -54 0 -6 -327z"/>
<path d="M6725 6138 c-3 -40 -4 -127 -1 -193 2 -66 5 -276 5 -467 l1 -348 65
0 65 0 0 540 0 540 -64 0 -64 0 -7 -72z"/>
<path d="M6950 5698 c1 -282 4 -526 6 -543 l5 -30 65 3 64 4 -2 536 -3 537
-68 3 -68 3 1 -513z"/>
<path d="M2272 5954 c-42 -29 -22 -104 27 -104 49 0 86 64 54 92 -29 25 -57
29 -81 12z"/>
<path d="M2266 5735 c-33 -33 -9 -87 38 -87 15 0 37 9 49 21 l21 21 -20 27
c-25 33 -65 41 -88 18z"/>
<path d="M2274 5542 c-6 -4 -16 -17 -23 -30 -10 -19 -8 -26 13 -47 14 -14 30
-25 36 -25 20 0 49 20 60 41 24 43 -43 90 -86 61z"/>
<path d="M7895 5409 c-46 -17 -115 -74 -151 -125 -130 -183 -48 -476 151 -539
81 -25 213 -18 280 15 113 55 176 154 183 286 6 109 -13 172 -75 249 -71 88
-134 117 -260 121 -56 2 -111 -1 -128 -7z m236 -125 c26 -13 57 -37 69 -54 26
-36 60 -130 60 -164 0 -37 -38 -132 -66 -165 -54 -65 -213 -80 -305 -30 -95
52 -134 184 -89 302 25 66 64 101 143 129 63 22 121 17 188 -18z"/>
<path d="M7933 5220 c-67 -45 -95 -169 -53 -238 46 -75 180 -94 243 -35 73 69
74 173 3 251 -31 33 -39 36 -97 39 -52 3 -70 0 -96 -17z m108 -80 c19 -11 49
-59 49 -80 0 -23 -49 -60 -79 -60 -37 0 -43 9 -43 64 0 74 26 101 73 76z"/>
<path d="M2258 5265 l5 -65 -44 0 -44 0 -3 -115 -3 -115 26 -10 c15 -6 38 -10
52 -10 23 0 25 -3 19 -32 -4 -25 -10 -737 -7 -900 1 -27 3 -28 54 -28 l52 0 1
342 c0 189 4 432 9 540 l8 197 -69 3 -69 3 -3 33 -3 34 65 -4 c64 -3 65 -3 70
26 3 16 6 57 6 91 0 72 -4 75 -80 75 l-48 0 6 -65z"/>
<path d="M2428 4933 c-3 -130 -1 -150 15 -165 16 -17 17 -49 17 -398 l0 -380
54 0 54 0 6 253 c3 138 9 381 12 538 l6 286 -53 6 c-30 4 -66 7 -81 7 l-27 0
-3 -147z"/>
<path d="M2656 4795 c4 -148 8 -391 8 -540 l1 -270 55 0 55 0 0 100 c1 55 2
287 3 515 l2 415 31 14 c45 20 25 29 -75 33 l-89 3 9 -270z"/>
<path d="M2854 5038 c3 -13 6 -256 6 -540 l0 -518 245 0 c135 0 245 3 245 8 0
4 -20 32 -45 62 -42 51 -123 177 -159 247 -74 146 -140 421 -154 645 l-7 113
-69 3 c-67 3 -68 3 -62 -20z"/>
<path d="M6540 5000 c0 -83 -17 -235 -40 -358 -17 -86 -20 -147 -20 -378 l0
-274 75 0 75 0 0 248 c0 137 3 378 7 535 l6 287 -51 0 -52 0 0 -60z"/>
<path d="M6725 4858 c-3 -112 -5 -354 -3 -537 l3 -335 65 1 65 1 3 531 2 531
-49 0 c-27 0 -56 3 -64 6 -13 4 -16 -25 -22 -198z"/>
<path d="M6950 4519 c0 -489 2 -541 16 -535 9 3 40 6 70 6 l54 0 0 535 0 535
-70 0 -70 0 0 -541z"/>
<path d="M7892 4619 c-100 -39 -200 -165 -222 -279 -12 -65 2 -173 31 -235 32
-68 102 -140 167 -172 50 -25 68 -28 152 -28 83 0 103 4 156 28 84 39 166 123
199 204 46 114 30 256 -41 356 -40 56 -139 122 -204 136 -79 17 -178 13 -238
-10z m106 -187 c-3 -88 -5 -96 -28 -113 -33 -22 -189 -34 -196 -14 -20 52 83
193 161 219 62 22 66 16 63 -92z m171 68 c79 -57 131 -159 131 -254 0 -80 -76
-177 -169 -219 -67 -30 -183 -21 -248 19 -58 36 -103 106 -111 170 -5 44 -3
47 14 39 10 -4 51 -10 89 -13 47 -3 79 -11 98 -24 26 -19 27 -23 27 -107 l0
-88 33 10 33 11 -4 71 -3 70 49 52 c49 51 53 63 23 63 -8 0 -30 14 -48 32 -25
24 -33 41 -33 67 -1 20 -7 54 -15 76 -8 22 -15 43 -15 46 0 4 24 7 54 8 45 0
61 -5 95 -29z m-111 -192 c24 -24 8 -78 -24 -78 -15 0 -44 27 -44 41 0 11 37
49 48 49 4 0 13 -5 20 -12z"/>
<path d="M8063 4425 c0 -22 2 -30 4 -17 2 12 2 30 0 40 -3 9 -5 -1 -4 -23z"/>
<path d="M6331 4243 c-17 -35 -60 -108 -96 -163 l-65 -100 105 0 105 0 -1 143
c-1 186 -6 201 -48 120z"/>
<path d="M6223 3893 l-132 -4 -53 -62 c-29 -35 -82 -86 -117 -113 -36 -27 -66
-54 -68 -59 -2 -6 10 -18 25 -28 16 -9 57 -43 91 -76 46 -44 61 -54 61 -40 0
10 3 19 8 19 12 0 59 82 73 128 7 23 17 42 23 43 6 0 33 4 61 8 100 17 96 -11
-15 -119 -43 -41 -82 -85 -88 -96 -11 -22 -11 -22 98 -16 103 5 110 4 109 -14
-2 -55 -9 -58 -113 -55 -96 3 -97 2 -87 -18 7 -11 40 -44 74 -72 75 -62 87
-76 87 -106 0 -43 -43 -29 -124 42 -41 36 -84 77 -95 91 l-19 25 -30 -43 c-55
-80 -168 -166 -189 -144 -11 11 25 68 92 146 l65 75 -100 9 c-96 8 -100 9
-100 31 0 13 3 26 8 28 4 3 50 2 102 -2 52 -4 97 -6 100 -4 2 2 -28 36 -68 74
-39 39 -72 75 -72 81 0 11 -72 -28 -134 -73 l-39 -29 2 -176 c1 -97 4 -181 7
-188 3 -8 104 -12 354 -13 l350 -2 0 380 c0 208 -3 378 -7 377 -5 -1 -67 -4
-140 -5z"/>
<path d="M7920 3811 c-196 -61 -300 -225 -288 -453 5 -103 46 -193 121 -268
91 -92 193 -123 322 -101 143 25 256 117 315 256 30 71 34 90 34 170 0 69 -5
104 -23 152 -42 113 -148 205 -275 239 -55 15 -165 17 -206 5z m140 -191 l0
-110 -30 0 c-35 0 -34 -3 -35 127 l0 93 33 0 32 0 0 -110z m153 30 c32 -29 62
-67 71 -91 9 -23 16 -43 14 -44 -2 -1 -45 -6 -97 -10 -81 -6 -93 -5 -88 8 3 8
9 48 12 88 11 120 11 120 88 49z m-283 -29 c0 -38 3 -82 6 -99 l6 -30 -48 5
c-27 3 -71 8 -97 12 l-49 6 34 65 c25 48 44 70 73 87 67 38 75 34 75 -46z
m124 -187 c37 -37 6 -91 -41 -73 -18 6 -23 16 -23 43 0 45 34 61 64 30z m-134
-29 l0 -36 -97 3 c-85 3 -98 5 -101 21 -7 37 4 42 102 45 l96 3 0 -36z m380
26 c19 -5 25 -14 25 -34 0 -15 -3 -27 -7 -27 -5 0 -48 0 -98 0 l-90 0 0 35 0
35 73 -1 c39 -1 83 -4 97 -8z m-365 -213 c-4 -57 -9 -105 -11 -107 -2 -2 -27
10 -56 26 -42 24 -58 42 -85 91 l-33 62 32 1 c18 0 56 7 83 14 82 21 77 27 70
-87z m363 77 c7 -6 -31 -71 -65 -113 -28 -35 -90 -81 -94 -70 -1 2 -4 47 -8
101 l-6 98 85 -7 c47 -4 86 -8 88 -9z m-232 -103 c0 -101 -4 -112 -43 -112
-22 0 -23 3 -23 105 l0 105 33 0 32 0 1 -98z"/>
<path d="M1724 2748 c3 -18 8 -120 12 -225 7 -179 8 -193 27 -199 10 -3 23 -2
27 3 5 4 10 108 12 231 l3 222 -44 0 -43 0 6 -32z"/>
<path d="M1850 2527 c0 -257 2 -267 47 -267 l23 0 0 255 0 255 -35 0 -35 0 0
-243z"/>
<path d="M1977 2763 c-9 -8 -9 -450 -1 -481 5 -18 13 -22 33 -20 l26 3 1 253
2 252 -27 0 c-15 0 -31 -3 -34 -7z"/>
<path d="M2087 2723 c-3 -27 -3 -141 0 -255 l6 -208 29 0 28 0 0 233 c0 127
-3 242 -6 255 -4 14 -14 22 -29 22 -19 0 -23 -7 -28 -47z"/>
<path d="M8364 2763 c-17 -3 -23 -14 -28 -50 -8 -60 -8 -269 0 -366 7 -76 7
-77 35 -77 16 0 29 3 29 8 1 4 3 106 6 227 2 121 7 230 9 243 6 23 -1 25 -51
15z"/>
<path d="M8460 2764 c0 -18 24 -84 30 -84 4 0 10 12 13 28 3 15 9 35 12 45 6
14 2 17 -24 17 -17 0 -31 -3 -31 -6z"/>
<path d="M8237 2753 c-21 -3 -27 -9 -23 -20 3 -8 6 -118 6 -244 l0 -229 35 0
36 0 -3 247 c-2 154 -7 247 -13 248 -5 1 -23 0 -38 -2z"/>
<path d="M8098 2505 l3 -245 33 0 34 0 1 245 2 245 -38 0 -38 0 3 -245z"/>
<path d="M5945 2595 c-75 -40 -114 -109 -94 -163 13 -35 74 -98 110 -112 40
-17 100 13 147 74 27 35 28 68 3 122 -33 73 -109 109 -166 79z"/>
<path d="M3291 2589 c-40 -16 -121 -90 -121 -110 0 -29 24 -70 62 -106 40 -39
75 -53 114 -46 110 20 128 204 25 258 -34 17 -46 18 -80 4z"/>
<path d="M3670 2552 c-56 -54 -62 -79 -33 -139 19 -42 86 -93 120 -93 57 0
133 78 133 137 0 72 -66 143 -133 143 -31 0 -46 -8 -87 -48z"/>
<path d="M4144 2581 c-34 -20 -67 -63 -78 -98 -10 -31 15 -83 58 -121 45 -39
77 -48 116 -32 36 15 87 71 96 105 14 54 -26 128 -82 151 -45 19 -73 18 -110
-5z"/>
<path d="M4588 2575 c-38 -26 -78 -81 -78 -109 0 -48 65 -129 116 -146 43 -15
92 7 139 63 46 53 47 97 5 154 -49 66 -119 81 -182 38z"/>
<path d="M5027 2575 c-67 -46 -85 -118 -46 -181 45 -74 117 -94 180 -51 74 50
97 122 59 185 -44 71 -126 92 -193 47z"/>
<path d="M5465 2569 c-73 -65 -81 -128 -24 -193 60 -69 112 -76 177 -25 66 51
77 106 37 176 -47 79 -127 97 -190 42z"/>
<path d="M6378 2582 c-39 -26 -68 -67 -75 -105 -10 -65 54 -149 124 -163 52
-10 153 84 153 144 0 34 -24 75 -65 111 -42 36 -94 41 -137 13z"/>
<path d="M6823 2580 c-62 -38 -80 -117 -43 -190 26 -52 55 -70 110 -70 52 0
66 8 109 64 40 50 40 90 1 144 -51 71 -116 90 -177 52z"/>
<path d="M7800 1505 c0 -7 63 -45 75 -45 5 0 -7 11 -27 25 -37 25 -48 30 -48
20z"/>
<path d="M4997 1753 c-4 -3 -7 -23 -7 -44 0 -31 4 -37 26 -42 34 -6 57 18 49
52 -9 36 -48 55 -68 34z"/>
<path d="M2593 1894 c4 -7 0 -14 -8 -18 -30 -11 -18 -75 25 -133 23 -29 42
-53 44 -53 2 0 -9 23 -23 52 -16 34 -26 69 -26 99 0 26 -4 51 -9 56 -5 4 -6 3
-3 -3z"/>
<path d="M2542 1788 c-7 -7 -12 -23 -12 -36 0 -15 -4 -21 -12 -16 -7 4 -8 3
-4 -4 11 -18 14 -15 31 25 17 39 15 49 -3 31z"/>
<path d="M4967 8819 c-24 -14 -47 -62 -47 -99 l0 -30 120 0 c70 0 120 4 120
10 0 5 -9 34 -20 63 l-20 54 -53 7 c-68 8 -79 7 -100 -5z"/>
<path d="M4992 8523 l3 -78 41 -6 42 -5 5 70 c2 39 2 76 0 83 -3 8 -23 13 -49
13 l-45 0 3 -77z"/>
<path d="M1538 1884 c-14 -31 -1 -57 31 -62 28 -4 51 14 51 42 0 50 -62 65
-82 20z"/>
<path d="M8597 1883 c-8 -43 9 -65 46 -61 30 3 32 5 32 43 0 39 -1 40 -36 43
-33 3 -37 0 -42 -25z"/>
<path d="M8617 1733 c-4 -3 -7 -31 -7 -60 l0 -54 32 3 c28 3 33 8 40 38 11 54
1 80 -31 80 -15 0 -31 -3 -34 -7z"/>
<path d="M1534 1717 c-3 -8 -4 -32 -2 -53 3 -36 6 -39 35 -42 30 -3 32 -1 39
34 4 21 2 44 -3 53 -13 21 -61 27 -69 8z"/>
<path d="M1500 1512 c-25 -21 -19 -45 16 -61 46 -21 64 -15 64 22 0 55 -37 74
-80 39z"/>
<path d="M8612 1518 c-7 -7 -12 -27 -12 -45 0 -32 1 -33 40 -33 25 0 42 6 48
16 5 8 27 18 50 21 48 6 55 20 15 28 -16 3 -42 10 -59 15 -41 13 -67 13 -82
-2z"/>
<path d="M9150 1296 c0 -36 4 -46 20 -51 29 -9 40 2 40 39 0 36 -15 56 -42 56
-15 0 -18 -8 -18 -44z"/>
<path d="M9292 1308 c-17 -17 -15 -54 4 -72 23 -24 53 -20 66 9 21 46 -36 97
-70 63z"/>
<path d="M760 1295 c-30 -36 23 -95 72 -79 28 9 43 46 29 73 -14 25 -81 30
-101 6z"/>
<path d="M9463 1298 c-43 -21 -19 -88 31 -88 45 0 63 52 28 83 -21 19 -28 20
-59 5z"/>
<path d="M536 1287 c-12 -9 -17 -23 -14 -42 2 -24 8 -31 30 -33 38 -5 68 14
68 43 0 39 -49 58 -84 32z"/>
<path d="M9678 1289 c-25 -14 -22 -55 4 -73 28 -20 43 -20 62 0 44 44 -12 105
-66 73z"/>
<path d="M2634 1182 c-17 -11 -24 -54 -12 -69 8 -10 56 -13 199 -13 l189 0 10
26 c7 17 7 32 0 45 -10 18 -23 19 -193 19 -100 0 -187 -4 -193 -8z"/>
<path d="M3260 1165 c-12 -32 -4 -54 24 -60 16 -5 622 0 634 4 1 1 7 12 12 26
21 56 27 55 -331 55 l-329 0 -10 -25z"/>
<path d="M4212 1178 c-16 -16 -15 -55 0 -64 7 -5 315 -9 685 -10 585 -2 675 0
688 13 20 19 19 59 -1 67 -9 3 -318 6 -688 6 -509 0 -675 -3 -684 -12z"/>
<path d="M5748 1179 c-11 -6 -18 -22 -18 -39 0 -37 16 -42 135 -38 l90 3 0 40
0 40 -95 2 c-52 2 -103 -2 -112 -8z"/>
<path d="M6136 1174 c-31 -31 -16 -70 30 -80 38 -7 64 15 64 56 0 41 -62 57
-94 24z"/>
<path d="M6830 1181 c-32 -5 -35 -9 -35 -41 l0 -35 404 -3 c290 -1 408 1 417
9 17 14 18 51 2 67 -9 9 -106 12 -382 11 -204 -1 -387 -4 -406 -8z"/>
<path d="M2170 1149 l0 -29 84 0 c69 0 85 3 90 17 11 27 -8 35 -93 38 l-81 2
0 -28z"/>
<path d="M6437 1153 c-9 -50 -3 -53 104 -53 99 0 100 0 110 27 18 48 9 53
-105 53 l-104 0 -5 -27z"/>
<path d="M2995 1001 c-84 -6 -90 -7 -93 -29 -7 -47 9 -52 167 -52 155 0 171 4
171 47 0 43 -29 47 -245 34z"/>
<path d="M6085 1000 c-168 -5 -170 -5 -173 -28 -7 -49 7 -52 204 -52 195 0
214 5 214 51 0 19 -38 41 -63 37 -7 -1 -88 -5 -182 -8z"/>
<path d="M3674 986 c-3 -8 -4 -25 -2 -38 3 -23 5 -23 118 -23 l115 0 0 35 0
35 -113 3 c-91 2 -113 0 -118 -12z"/>
<path d="M4121 986 c-7 -8 -11 -23 -9 -33 3 -15 19 -19 108 -26 58 -4 175 -6
260 -5 l155 3 0 35 0 35 -251 3 c-211 2 -253 0 -263 -12z"/>
<path d="M4765 980 c-3 -11 -3 -29 0 -40 6 -20 13 -20 178 -18 l172 3 3 38 3
37 -175 0 c-166 0 -175 -1 -181 -20z"/>
<path d="M5244 986 c-3 -8 -4 -25 -2 -38 3 -22 7 -23 100 -26 89 -2 98 -1 108
18 6 11 8 30 5 40 -6 18 -16 20 -106 20 -77 0 -101 -3 -105 -14z"/>
<path d="M5537 994 c-13 -14 -7 -62 9 -68 9 -3 57 -6 109 -6 100 0 119 9 113
52 -3 22 -7 23 -114 26 -60 1 -113 -1 -117 -4z"/>
<path d="M6507 993 c-19 -3 -31 -13 -38 -30 -5 -14 -8 -27 -6 -29 2 -2 31 -7
65 -10 43 -5 66 -3 77 6 23 19 18 49 -11 60 -26 10 -36 10 -87 3z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 573 KiB

@@ -0,0 +1,16 @@
// The file contents for the current environment will overwrite these during build.
// The build system defaults to the dev environment which uses `index.ts`, but if you do
// `ng build --env=prod` then `index.prod.ts` will be used instead.
// The list of which env maps to which file can be found in `.angular-cli.json`.
import packageJson from '@package';
import type { WorkspaceProductBranding } from 'shared-interfaces';
export const AppConfig = {
production: false,
environment: 'DEV',
version: packageJson.version,
BACKEND_URL: 'http://localhost:3000',
defaultTranslateLang: 'en' as const,
product: null as WorkspaceProductBranding | null,
};
@@ -0,0 +1,27 @@
import packageJson from '@package';
import {
Language,
StreamFormat,
VideoPlayer,
type WorkspaceProductBranding,
} from 'shared-interfaces';
export const kiratvProduct: WorkspaceProductBranding = {
appDisplayName: 'KiraTV',
xtreamOnlyUi: true,
xtreamDefaultServerUrl: 'http://iptv.kiracloud.es',
defaultPlaylistTitle: 'Kira Cloud',
defaultLanguage: Language.SPANISH,
defaultVideoPlayer: VideoPlayer.ArtPlayer,
defaultStreamFormat: StreamFormat.TsStreamFormat,
indexHtmlLang: 'es',
};
export const AppConfig = {
production: true,
environment: 'KIRATV',
version: packageJson.version,
BACKEND_URL: 'https://iptvnator-playlist-parser-api.vercel.app',
defaultTranslateLang: 'es',
product: kiratvProduct,
};
@@ -0,0 +1,11 @@
import packageJson from '@package';
import type { WorkspaceProductBranding } from 'shared-interfaces';
export const AppConfig = {
production: true,
environment: 'PROD',
version: packageJson.version,
BACKEND_URL: 'https://iptvnator-playlist-parser-api.vercel.app',
defaultTranslateLang: 'en' as const,
product: null as WorkspaceProductBranding | null,
};
+11
View File
@@ -0,0 +1,11 @@
import packageJson from '@package';
import type { WorkspaceProductBranding } from 'shared-interfaces';
export const AppConfig = {
production: false,
environment: 'LOCAL',
version: packageJson.version,
BACKEND_URL: 'http://localhost:3000',
defaultTranslateLang: 'en' as const,
product: null as WorkspaceProductBranding | null,
};
@@ -0,0 +1,11 @@
import packageJson from '@package';
import type { WorkspaceProductBranding } from 'shared-interfaces';
export const AppConfig = {
production: false,
environment: 'WEB',
version: packageJson.version,
BACKEND_URL: 'http://localhost:3333',
defaultTranslateLang: 'en' as const,
product: null as WorkspaceProductBranding | null,
};
+32
View File
@@ -0,0 +1,32 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>IPTVnator</title>
<base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta property="og:type" content="website" />
<meta property="og:title" content="IPTVnator" />
<meta property="og:url" content="https://iptvnator.vercel.app" />
<meta
property="og:image"
content="https://raw.githubusercontent.com/4gray/iptvnator/electron/iptv-dark-theme.png"
/>
<meta
property="og:description"
content="IPTVnator is a video player application that provides support for the playback of IPTV playlists (m3u, m3u8)"
/>
<link rel="manifest" href="manifest.webmanifest" />
<link rel="apple-touch-icon" href="assets/icons/apple-touch-icon.png" />
<link rel="icon" type="image/x-icon" href="assets/icons/favicon.ico" />
<script>
if (global === undefined) {
var global = window;
}
</script>
</head>
<body class="mat-app-background">
<app-root></app-root>
</body>
</html>
+28
View File
@@ -0,0 +1,28 @@
<!doctype html>
<html lang="es">
<head>
<meta charset="utf-8" />
<title>KiraTV</title>
<base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta property="og:type" content="website" />
<meta property="og:title" content="KiraTV" />
<meta property="og:url" content="https://play.kiracloud.es" />
<meta
property="og:description"
content="Cliente IPTV para Kira Cloud: TV en directo, películas y series."
/>
<link rel="manifest" href="manifest.webmanifest" />
<link rel="apple-touch-icon" href="assets/icons/apple-touch-icon.png" />
<link rel="icon" type="image/x-icon" href="assets/icons/favicon.ico" />
<script>
if (global === undefined) {
var global = window;
}
</script>
</head>
<body class="mat-app-background">
<app-root></app-root>
</body>
</html>
+240
View File
@@ -0,0 +1,240 @@
@use 'sass:map';
@use '@angular/material' as mat;
@use 'styles';
@include mat.elevation-classes();
@include mat.app-background();
// ─── Typography ─────────────────────────────────────────────────────────────
$app-font-stack:
"'DM Sans', 'Roboto', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif";
$my-typography: mat.m2-define-typography-config(
$font-family: $app-font-stack,
);
@include mat.typography-hierarchy($my-typography);
// ─── M3 Themes ───────────────────────────────────────────────────────────────
$light-theme: mat.define-theme(
(
color: (
theme-type: light,
primary: mat.$violet-palette,
tertiary: mat.$cyan-palette,
),
typography: (
plain-family: $app-font-stack,
brand-family: $app-font-stack,
),
)
);
$dark-theme: mat.define-theme(
(
color: (
theme-type: dark,
primary: mat.$violet-palette,
tertiary: mat.$cyan-palette,
),
typography: (
plain-family: $app-font-stack,
brand-family: $app-font-stack,
),
)
);
// ─── Apply Themes ────────────────────────────────────────────────────────────
html {
@include mat.all-component-themes($light-theme);
// ── Light theme design tokens ─────────────────────────────────────────
--app-shell-bg: #eef0f3;
--app-rail-bg: #eef0f3;
--app-header-bg: #eef0f3;
--app-content-bg: #f5f6f8;
--app-rail-border: transparent;
--app-on-surface: #1d1b1e;
--app-hover-overlay: rgba(0, 0, 0, 0.06);
--app-search-bg: rgba(255, 255, 255, 0.7);
--app-search-border: rgba(0, 0, 0, 0.1);
--app-selection-color: #2f7bff;
--app-selection-on-color: #eef4ff;
--app-selection-surface: color-mix(
in srgb,
var(--app-selection-color) 14%,
transparent
);
--app-selection-surface-strong: color-mix(
in srgb,
var(--app-selection-color) 22%,
transparent
);
--app-selection-border: color-mix(
in srgb,
var(--app-selection-color) 52%,
transparent
);
--app-selection-glow: color-mix(
in srgb,
var(--app-selection-color) 34%,
transparent
);
// Content area
--app-content-shadow: -2px 4px 12px rgba(0, 0, 0, 0.06);
// Widget surfaces — no borders, layered backgrounds
--app-widget-bg: #ffffff;
--app-widget-header-bg: #fafbfc;
--app-widget-border: transparent;
--app-widget-shadow: 0 1px 3px rgba(0, 0, 0, 0.06), 0 4px 12px rgba(0, 0, 0, 0.04);
--app-widget-header-border: rgba(0, 0, 0, 0.06);
--app-card-hover-bg: #f0f2f5;
--app-separator: rgba(0, 0, 0, 0.14);
// Typography — subdued, not pure black
--app-heading-color: #1a1d23;
--app-body-color: #4a5060;
--app-muted-color: #8891a4;
--app-eyebrow-color: #7c8495;
// Provider accent colors
--app-provider-xtream: #6366f1;
--app-provider-stalker: #10b981;
--app-provider-m3u: #d97706;
// Hero
--app-accent-gradient: linear-gradient(
135deg,
rgba(99, 102, 241, 0.08) 0%,
rgba(168, 85, 247, 0.05) 100%
);
--app-hero-surface: rgba(99, 102, 241, 0.04);
.dark-theme {
@include mat.all-component-colors($dark-theme);
// ── Dark graphite theme ────────────────────────────────────────────
// Inspired by both Slack (sidebar distinction) and GitButler (data density)
// Key principle: clearly distinct surface layers using graphite steps
// Darkest → lightest: #0d0f12 → #141720 → #1c2030 → #222840
// App shell & navigation
--app-shell-bg: #0d0f12;
--app-rail-bg: #111318;
--app-header-bg: #111318;
--app-content-bg: #161a22;
--app-rail-border: transparent;
--app-on-surface: #e6e1e5;
--app-hover-overlay: rgba(255, 255, 255, 0.08);
--app-search-bg: rgba(255, 255, 255, 0.05);
--app-search-border: rgba(255, 255, 255, 0.09);
--app-selection-color: #78adff;
--app-selection-on-color: #071225;
--app-selection-surface: color-mix(
in srgb,
var(--app-selection-color) 18%,
transparent
);
--app-selection-surface-strong: color-mix(
in srgb,
var(--app-selection-color) 28%,
transparent
);
--app-selection-border: color-mix(
in srgb,
var(--app-selection-color) 62%,
transparent
);
--app-selection-glow: color-mix(
in srgb,
var(--app-selection-color) 44%,
transparent
);
// Content area
--app-content-shadow: -4px 8px 20px rgba(0, 0, 0, 0.18);
// Widget surfaces — NO border, surface contrast does the work
// Widgets sit on content-bg (#161a22), so widget-bg is notably lighter
--app-widget-bg: #1e2330;
--app-widget-header-bg: #232840;
--app-widget-border: transparent;
--app-widget-shadow: none;
--app-widget-header-border: rgba(255, 255, 255, 0.05);
--app-card-hover-bg: #252b3a;
--app-separator: rgba(255, 255, 255, 0.14);
// Typography — NOT pure white. Warm graphite-tinted whites
--app-heading-color: #d8dce8; // soft off-white, not #fff
--app-body-color: #8b93a8; // muted blue-grey
--app-muted-color: #5c6478; // dimmed
--app-eyebrow-color: #6b7494; // eyebrow labels
// Provider accents (slightly brighter for dark bg)
--app-provider-xtream: #818cf8;
--app-provider-stalker: #34d399;
--app-provider-m3u: #fbbf24;
// Hero section
--app-accent-gradient: linear-gradient(
135deg,
rgba(99, 102, 241, 0.12) 0%,
rgba(168, 85, 247, 0.07) 100%
);
--app-hero-surface: rgba(30, 35, 48, 0.9);
}
}
// ─── Global refined outlined inputs ──────────────────────────────────────────
// Applied app-wide AFTER mat.all-component-themes so these overrides win the
// cascade. Pairs with MAT_FORM_FIELD_DEFAULT_OPTIONS (outline + dynamic) set
// in app.config.ts.
$app-refined-input-density: mat.define-theme((
density: (scale: -2),
));
html {
@include mat.form-field-density($app-refined-input-density);
.mat-mdc-form-field {
--mdc-outlined-text-field-outline-color: var(--app-widget-header-border);
--mdc-outlined-text-field-hover-outline-color: var(--app-muted-color);
--mdc-outlined-text-field-focus-outline-color: var(--app-selection-color);
--mdc-outlined-text-field-container-shape: 10px;
--mdc-outlined-text-field-label-text-color: var(--app-muted-color);
--mdc-outlined-text-field-input-text-color: var(--app-heading-color);
--mdc-outlined-text-field-caret-color: var(--app-selection-color);
--mdc-outlined-text-field-label-text-size: 13px;
--mdc-outlined-text-field-input-text-size: 13.5px;
}
// Inputs sit slightly above the surrounding surface. color-mix is inlined
// here (not via a custom property on html) so var(--app-widget-bg)
// resolves at the wrapper — inside .dark-theme — rather than being
// locked to the light-mode value at html-level inheritance.
.mat-form-field-appearance-outline .mat-mdc-text-field-wrapper {
background: color-mix(in srgb, var(--app-widget-bg) 85%, white 7%);
border-radius: 10px;
}
.mat-mdc-form-field .mat-mdc-input-element,
.mat-mdc-form-field .mat-mdc-select-value {
font-size: 13.5px;
}
.mat-mdc-form-field-subscript-wrapper {
font-size: 11px;
letter-spacing: 0.01em;
margin-top: 2px;
.mat-mdc-form-field-hint-wrapper,
.mat-mdc-form-field-error-wrapper {
padding: 0 12px;
}
.mat-mdc-form-field-hint {
color: var(--app-muted-color);
}
}
}
+10
View File
@@ -0,0 +1,10 @@
import { bootstrapApplication } from '@angular/platform-browser';
import { registerAppDateLocales } from './app/app-date-locales';
import { AppComponent } from './app/app.component';
import { appConfig } from './app/app.config';
registerAppDateLocales();
bootstrapApplication(AppComponent, appConfig).catch((err) =>
console.error(err)
);
+35
View File
@@ -0,0 +1,35 @@
{
"name": "KiraTV",
"description": "Cliente IPTV para Kira Cloud (Xtream Codes).",
"short_name": "KiraTV",
"theme_color": "#1e1b4b",
"background_color": "#0f172a",
"display": "standalone",
"scope": "./",
"start_url": "./",
"categories": ["video"],
"icons": [
{
"src": "assets/icons/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "assets/icons/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
},
{
"src": "assets/icons/android-chrome-maskable-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "assets/icons/android-chrome-maskable-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
}
]
}
+35
View File
@@ -0,0 +1,35 @@
{
"name": "IPTVnator",
"description": "IPTVnator is a tool to watch and manage your IPTV playlists.",
"short_name": "IPTVnator",
"theme_color": "#1b1c1c",
"background_color": "#1b1c1c",
"display": "standalone",
"scope": "./",
"start_url": "./",
"categories": ["video"],
"icons": [
{
"src": "assets/icons/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "assets/icons/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
},
{
"src": "assets/icons/android-chrome-maskable-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "assets/icons/android-chrome-maskable-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
}
]
}
+102
View File
@@ -0,0 +1,102 @@
{
"id": "n8qbqhmshrk",
"_id": "1268xq358s7m",
"filename": "playlist.m3u8",
"title": "playlist.m3u8",
"count": 4,
"playlist": {
"header": {
"attrs": {},
"raw": "#EXTM3U"
},
"items": [
{
"name": "rpk-news\r",
"tvg": {
"id": "",
"name": "",
"language": "",
"country": "",
"logo": "",
"url": "",
"rec": ""
},
"group": {
"title": "news\r"
},
"http": {
"referrer": "",
"user-agent": ""
},
"url": "http://test/1/index.m3u8",
"raw": "#EXTINF:0 tvg-rec=\"3\",rpk-news\r\n#EXTGRP:news\r\nhttp://test/1/index.m3u8"
},
{
"name": "5th channel\r",
"tvg": {
"id": "",
"name": "",
"language": "",
"country": "",
"logo": "",
"url": "",
"rec": ""
},
"group": {
"title": "news\r"
},
"http": {
"referrer": "",
"user-agent": ""
},
"url": "http://test/2/index.m3u8",
"raw": "#EXTINF:0 tvg-rec=\"3\",5th channel\r\n#EXTGRP:news\r\nhttp://test/2/index.m3u8"
},
{
"name": "Multiland Channel\r",
"tvg": {
"id": "",
"name": "",
"language": "",
"country": "",
"logo": "",
"url": "",
"rec": ""
},
"group": {
"title": "category 2\r"
},
"http": {
"referrer": "",
"user-agent": ""
},
"url": "http://test/3/index.m3u8",
"raw": "#EXTINF:0 tvg-rec=\"3\",Multiland Channel\r\n#EXTGRP:category 2\r\nhttp://test/3/index.m3u8"
},
{
"name": "Unicuuuum\r",
"tvg": {
"id": "",
"name": "",
"language": "",
"country": "",
"logo": "",
"url": "",
"rec": ""
},
"group": {
"title": "category 2\r"
},
"http": {
"referrer": "",
"user-agent": ""
},
"url": "http://test/4/index.m3u8",
"raw": "#EXTINF:0 tvg-rec=\"3\",Unicuuuum\r\n#EXTGRP:category 2\r\nhttp://test/4/index.m3u8"
}
]
},
"importDate": "2020-10-02T17:28:03.300Z",
"lastUsage": "2020-10-02T17:28:03.300Z",
"favorites": []
}
+103
View File
@@ -0,0 +1,103 @@
// ─── Shared List Navigation Styles ────────────────────────────────────────────
.nav-list {
flex: 1;
overflow-y: auto;
padding: 0 8px 12px;
display: flex;
flex-direction: column;
gap: 2px;
}
.nav-item {
position: relative;
width: 100%;
display: flex;
align-items: center;
gap: 10px;
padding: 6px 4px;
border: 1px solid transparent;
border-radius: 10px;
background: transparent;
color: var(--mat-sys-on-surface-variant);
text-align: left;
text-decoration: none;
cursor: pointer;
font-size: 0.875rem;
font-weight: 500;
box-sizing: border-box;
transition:
background 0.15s ease,
color 0.15s ease,
border-color 0.15s ease,
box-shadow 0.18s ease,
transform 0.18s ease;
mat-icon {
font-size: 18px;
width: 18px;
height: 18px;
flex-shrink: 0;
}
span,
.nav-item-label {
line-height: 1.2;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
flex: 1;
min-width: 0;
}
.nav-item-meta {
font-size: 0.8rem;
min-width: 2ch;
text-align: right;
flex-shrink: 0;
color: var(--mat-sys-on-surface-variant);
opacity: 0.7;
}
&:hover:not(.selected):not(.active):not(.is-active) {
background: var(--app-selection-surface);
color: var(--mat-sys-on-surface);
}
&.selected,
&.active,
&.is-active {
background: linear-gradient(
135deg,
var(--app-selection-surface-strong),
var(--app-selection-surface)
) !important;
color: var(--app-selection-color) !important;
border-color: var(--app-selection-border) !important;
font-weight: 600;
box-shadow:
inset 0 0 0 1px var(--app-selection-border),
0 12px 20px -18px var(--app-selection-glow);
transform: translateY(-1px);
* {
color: var(--app-selection-color) !important;
}
.nav-item-meta {
color: var(--app-selection-color) !important;
opacity: 0.92;
}
/* &::before {
content: '';
position: absolute;
inset-inline-start: 2px;
top: 7px;
bottom: 7px;
width: 2px;
border-radius: 999px;
background: var(--app-selection-color);
box-shadow: 0 0 10px var(--app-selection-glow);
} */
}
}
+1
View File
@@ -0,0 +1 @@
import 'zone.js';
+52
View File
@@ -0,0 +1,52 @@
/**
* This file includes polyfills needed by Angular and is loaded before the app.
* You can add your own extra polyfills to this file.
*
* This file is divided into 2 sections:
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
* file.
*
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
*
* Learn more in https://angular.io/guide/browser-support
*/
/***************************************************************************************************
* BROWSER POLYFILLS
*/
/**
* By default, zone.js will patch all possible macroTask and DomEvents
* user can disable parts of macroTask/DomEvents patch by setting following flags
* because those flags need to be set before `zone.js` being loaded, and webpack
* will put import in the top of bundle, so user need to create a separate file
* in this directory (for example: zone-flags.ts), and put the following flags
* into that file, and then add the following code before importing zone.js.
* import './zone-flags.ts';
*
* The flags allowed in zone-flags.ts are listed here.
*
* The following flags will work for all browsers.
*
* (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
* (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
* (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
*
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
* with the following flag, it will bypass `zone.js` patch for IE/Edge
*
* (window as any).__Zone_enable_cross_context_check = true;
*
*/
/***************************************************************************************************
* Zone JS is required by default for Angular itself.
*/
import 'zone.js'; // Included with Angular CLI.
/***************************************************************************************************
* APPLICATION IMPORTS
*/
+1
View File
@@ -0,0 +1 @@
import 'jest-preset-angular/setup-jest';
+140
View File
@@ -0,0 +1,140 @@
@use '../../../libs/ui/components/src/lib/resizable/resizable.scss';
@use './settings-theme';
// ─── Tailwind CSS ─────────────────────────────────────────────────────────────
// Preflight is disabled in tailwind.config.js to avoid conflicts with
// Angular Material. Only components + utilities are loaded.
@tailwind base;
@tailwind components;
@tailwind utilities;
// ─── Third-party ─────────────────────────────────────────────────────────────
@import '@yangkghjh/videojs-aspect-ratio-panel/dist/videojs-aspect-ratio-panel.css';
@import 'material-design-icons-iconfont/dist/material-design-icons.css';
// ─── Bundled Fonts ────────────────────────────────────────────────────────────
@import '@fontsource/dm-sans/400.css';
@import '@fontsource/dm-sans/500.css';
@import '@fontsource/dm-sans/600.css';
@import '@fontsource/roboto/300.css';
@import '@fontsource/roboto/400.css';
@import '@fontsource/roboto/500.css';
@import '@fontsource/jetbrains-mono/400.css';
@import '@fontsource/jetbrains-mono/500.css';
@import '@fontsource/crimson-pro/400.css';
@import '@fontsource/crimson-pro/600.css';
@import '@fontsource/crimson-pro/700.css';
// ─── Shared Components ────────────────────────────────────────────────────────
app-root.macos-platform .current-playlist {
padding-top: 30px;
}
app-root.macos-platform app-navigation .portal-status-container {
padding-top: 30px;
}
// ─── Base ─────────────────────────────────────────────────────────────────────
body,
html {
user-select: none;
margin: 0;
padding: 0;
height: 100%;
font-family:
'DM Sans',
'Roboto',
-apple-system,
BlinkMacSystemFont,
'Segoe UI',
'Helvetica Neue',
Arial,
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
// Re-enable context menu and text selection for input fields
input,
textarea {
user-select: text;
}
@media (display-mode: standalone) {
body {
overscroll-behavior-y: contain;
overflow: hidden;
}
}
// ─── Utilities ────────────────────────────────────────────────────────────────
.mat-tab-label-active {
opacity: 1 !important;
}
input,
button,
textarea,
:focus {
outline: none;
}
// ─── Dark Theme ───────────────────────────────────────────────────────────────
.dark-theme {
background: var(--mat-sys-surface) !important;
// Refined scrollbar for dark mode
::-webkit-scrollbar {
width: 6px;
height: 6px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background-color: var(--mat-sys-outline-variant);
border-radius: 999px;
&:hover {
background-color: var(--mat-sys-outline);
}
}
}
.scroll-viewport-portals {
min-height: calc(100vh - 170px) !important;
overflow-x: hidden !important;
}
.mat-drawer-inner-container {
overflow: hidden !important;
}
.cdk-overlay-backdrop {
backdrop-filter: blur(4px);
}
// Full-screen overlay dialogs (global search/recent) must stay interactive in Electron.
.global-search-overlay,
.global-search-overlay .mat-mdc-dialog-surface,
.global-search-overlay .mat-mdc-dialog-container {
app-region: no-drag;
}
// Command palette dialog — the palette-shell renders its own background, border,
// radius and shadow, so strip MDC's dialog surface chrome to avoid a darker
// halo peeking out behind the rounded corners.
.workspace-command-palette-overlay .mat-mdc-dialog-surface {
background: transparent;
box-shadow: none;
border-radius: 14px;
padding: 0;
overflow: visible;
}
.mat-mdc-snack-bar-container.settings-snackbar {
margin-bottom: calc(76px + env(safe-area-inset-bottom, 0px));
}
+26
View File
@@ -0,0 +1,26 @@
import { setupZoneTestEnv } from 'jest-preset-angular/setup-env/zone/index.mjs';
Object.defineProperty(globalThis, 'jest', {
configurable: true,
value: import.meta.jest,
});
if (typeof (globalThis as { IDBFactory?: unknown }).IDBFactory === 'undefined') {
Object.defineProperty(globalThis, 'IDBFactory', {
configurable: true,
value: class MockIDBFactory {},
});
}
if (!Element.prototype.animate) {
Element.prototype.animate = () =>
({
cancel: () => undefined,
finished: Promise.resolve(),
}) as unknown as Animation;
}
setupZoneTestEnv({
errorOnUnknownElements: true,
errorOnUnknownProperties: true,
});
@@ -0,0 +1,4 @@
import parser from '../../../../node_modules/iptv-playlist-parser/src/index.js';
export const parse = parser.parse;
export default parser;
@@ -0,0 +1 @@
export class PlayerDialogComponent {}
+475
View File
@@ -0,0 +1,475 @@
/* SystemJS module definition */
declare const nodeModule: NodeModule;
interface NodeModule {
id: string;
}
import {
EpgChannel,
EpgChannelMetadata,
EpgProgram,
ExternalPlayerSession,
PlaybackPositionData,
Playlist,
PlaylistRefreshEvent,
PlaylistRefreshPayload,
PortalDebugEvent,
XtreamBackupFavoriteItem,
XtreamBackupHiddenCategory,
XtreamBackupRecentlyViewedItem,
XtreamCategory,
} from 'shared-interfaces';
import {
DbOperationEvent,
GlobalFavoriteItem,
GlobalRecentlyAddedItem,
GlobalRecentItem,
GlobalSearchResult,
XCategoryFromDb,
XtreamContent,
} from 'services';
type JsonObject = Record<string, unknown>;
type JsonArray = unknown[];
declare global {
interface Window {
electron: {
onPortalDebugEvent?: (
callback: (data: PortalDebugEvent) => void
) => () => void;
onPlaylistRefreshEvent?: (
callback: (data: PlaylistRefreshEvent) => void
) => () => void;
getAppVersion: () => Promise<string>;
platform: string;
fetchPlaylistByUrl: (
url: string,
title?: string
) => Promise<Playlist>;
updatePlaylistFromFilePath: (
filePath: string,
title: string
) => Promise<Playlist>;
openPlaylistFromFile: () => Promise<Playlist>;
saveFileDialog: (
defaultPath: string,
filters?: { name: string; extensions: string[] }[]
) => Promise<string | null>;
writeFile: (
filePath: string,
content: string
) => Promise<{ success: boolean }>;
setUserAgent: (userAgent: string, referer?: string) => void;
openInMpv: (
url: string,
title: string,
thumbnail: string,
userAgent: string,
referer?: string,
origin?: string,
contentInfo?: unknown,
startTime?: number,
headers?: Record<string, string>
) => Promise<ExternalPlayerSession>;
openInVlc: (
url: string,
title: string,
thumbnail: string,
userAgent: string,
referer?: string,
origin?: string,
contentInfo?: unknown,
startTime?: number,
headers?: Record<string, string>
) => Promise<ExternalPlayerSession>;
autoUpdatePlaylists: (playlists: Playlist[]) => Promise<Playlist[]>;
fetchEpg: (urls: string[]) => Promise<{
success: boolean;
message?: string;
skipped?: string[];
}>;
getChannelPrograms: (channelId: string) => Promise<EpgProgram[]>;
getEpgChannelMetadata: (
channelIds: string[]
) => Promise<Record<string, EpgChannelMetadata | null>>;
getEpgChannels: () => Promise<EpgChannel[]>;
getEpgChannelsByRange: (
skip: number,
limit: number
) => Promise<EpgChannel[]>;
forceFetchEpg: (
url: string
) => Promise<{ success: boolean; message?: string }>;
clearEpgData: () => Promise<{ success: boolean }>;
checkEpgFreshness: (
urls: string[],
maxAgeHours?: number
) => Promise<{ staleUrls: string[]; freshUrls: string[] }>;
searchEpgPrograms: (
searchTerm: string,
limit?: number
) => Promise<EpgProgram[]>;
updateSettings: (settings: JsonObject) => Promise<void>;
getAiSettings: () => Promise<{
aiProvider: string;
aiModelName: string;
aiApiKey: string;
}>;
setMpvPlayerPath: (mpvPlayerPath: string) => Promise<void>;
setVlcPlayerPath: (vlcPlayerPath: string) => Promise<void>;
stalkerRequest: (payload: {
url: string;
macAddress: string;
params: Record<string, string>;
token?: string;
serialNumber?: string;
requestId?: string;
}) => Promise<JsonObject>;
xtreamRequest: (payload: {
url: string;
params: Record<string, string>;
requestId?: string;
sessionId?: string;
suppressErrorLog?: boolean;
}) => Promise<{ payload: unknown; action: string }>;
xtreamCancelSession: (
sessionId: string
) => Promise<{ success: boolean; cancelled: number }>;
xtreamProbeUrl: (
url: string,
method?: 'GET' | 'HEAD'
) => Promise<{ status: number; url: string }>;
refreshPlaylist: (
payload: PlaylistRefreshPayload
) => Promise<Playlist>;
cancelPlaylistRefresh: (
operationId: string
) => Promise<{ success: boolean }>;
// Database operations
dbCreatePlaylist: (
playlist: Playlist
) => Promise<{ success: boolean }>;
dbGetPlaylist: (playlistId: string) => Promise<Playlist | null>;
dbUpsertAppPlaylist: (
playlist: Playlist
) => Promise<{ success: boolean }>;
dbUpsertAppPlaylists: (
playlists: Playlist[]
) => Promise<{ success: boolean; count: number }>;
dbGetAppPlaylists: () => Promise<Playlist[]>;
dbGetAppPlaylist: (playlistId: string) => Promise<Playlist | null>;
dbUpdatePlaylist: (
playlistId: string,
updates: Partial<Playlist>
) => Promise<{ success: boolean }>;
dbDeletePlaylist: (
playlistId: string,
operationId?: string
) => Promise<{ success: boolean }>;
dbDeleteXtreamContent: (
playlistId: string,
operationId?: string
) => Promise<{
success: boolean;
favorites: XtreamBackupFavoriteItem[];
recentlyViewed: XtreamBackupRecentlyViewedItem[];
hiddenCategories: XtreamBackupHiddenCategory[];
}>;
dbRestoreXtreamUserData: (
playlistId: string,
favorites: XtreamBackupFavoriteItem[],
recentlyViewed: XtreamBackupRecentlyViewedItem[],
operationId?: string
) => Promise<{ success: boolean }>;
dbHasCategories: (
playlistId: string,
type: string
) => Promise<boolean>;
dbGetCategories: (
playlistId: string,
type: string
) => Promise<XCategoryFromDb[]>;
dbSaveCategories: (
playlistId: string,
categories: XtreamCategory[],
type: string,
hiddenCategoryXtreamIds?: number[]
) => Promise<{ success: boolean }>;
dbGetAllCategories: (
playlistId: string,
type: string
) => Promise<XCategoryFromDb[]>;
dbUpdateCategoryVisibility: (
categoryIds: number[],
hidden: boolean
) => Promise<{ success: boolean }>;
dbHasContent: (
playlistId: string,
type: string
) => Promise<boolean>;
dbGetContent: (
playlistId: string,
type: string
) => Promise<XtreamContent[]>;
dbSaveContent: (
playlistId: string,
streams: JsonArray,
type: string,
operationId?: string
) => Promise<{ success: boolean; count: number }>;
dbClearXtreamImportCache: (
playlistId: string,
type: 'live' | 'movie' | 'series'
) => Promise<{ success: boolean }>;
dbSearchContent: (
playlistId: string,
searchTerm: string,
types: string[],
excludeHidden?: boolean
) => Promise<XtreamContent[]>;
dbGlobalSearch: (
searchTerm: string,
types: string[],
excludeHidden?: boolean
) => Promise<GlobalSearchResult[]>;
dbGetGlobalRecentlyAdded: (
kind: 'all' | 'vod' | 'series',
limit?: number
) => Promise<GlobalRecentlyAddedItem[]>;
dbGetRecentlyViewed: () => Promise<GlobalRecentItem[]>;
dbClearRecentlyViewed: () => Promise<{ success: boolean }>;
// Favorites
dbAddFavorite: (
contentId: number,
playlistId: string,
backdropUrl?: string
) => Promise<{ success: boolean }>;
dbRemoveFavorite: (
contentId: number,
playlistId: string
) => Promise<{ success: boolean }>;
dbIsFavorite: (
contentId: number,
playlistId: string
) => Promise<boolean>;
dbGetFavorites: (playlistId: string) => Promise<XtreamContent[]>;
dbGetGlobalFavorites: () => Promise<GlobalFavoriteItem[]>;
dbGetAllGlobalFavorites: () => Promise<GlobalFavoriteItem[]>;
dbReorderGlobalFavorites: (
updates: { content_id: number; position: number }[]
) => Promise<{ success: boolean }>;
// Recently viewed (playlist-specific)
dbGetRecentItems: (playlistId: string) => Promise<XtreamContent[]>;
dbAddRecentItem: (
contentId: number,
playlistId: string,
backdropUrl?: string
) => Promise<{ success: boolean }>;
dbClearPlaylistRecentItems: (
playlistId: string
) => Promise<{ success: boolean }>;
dbRemoveRecentItem: (
contentId: number,
playlistId: string
) => Promise<{ success: boolean }>;
dbGetContentByXtreamId: (
xtreamId: number,
playlistId: string,
contentType?: 'live' | 'movie' | 'series'
) => Promise<XtreamContent | null>;
dbSetContentBackdropIfMissing: (
contentId: number,
backdropUrl?: string
) => Promise<{ success: boolean }>;
dbGetAppState: (key: string) => Promise<string | null>;
dbSetAppState: (
key: string,
value: string
) => Promise<{ success: boolean }>;
// Remote control
onChannelChange?: (
callback: (data: { direction: 'up' | 'down' }) => void
) => () => void;
onRemoteControlCommand?: (
callback: (data: {
type:
| 'channel-select-number'
| 'volume-up'
| 'volume-down'
| 'volume-toggle-mute';
number?: number;
}) => void
) => () => void;
updateRemoteControlStatus?: (status: {
portal: 'm3u' | 'xtream' | 'stalker' | 'unknown';
isLiveView: boolean;
channelName?: string;
channelNumber?: number;
epgTitle?: string;
epgStart?: string;
epgEnd?: string;
supportsVolume?: boolean;
volume?: number;
muted?: boolean;
}) => void;
// Player error notifications
onPlayerError?: (
callback: (data: {
player: string;
error: string;
originalError: string;
}) => void
) => void;
onExternalPlayerSessionUpdate?: (
callback: (data: ExternalPlayerSession) => void
) => () => void;
getLocalIpAddresses: () => Promise<string[]>;
// EPG progress listener
onEpgProgress?: (
callback: (data: {
url: string;
status: 'loading' | 'complete' | 'error';
stats?: { totalChannels: number; totalPrograms: number };
error?: string;
}) => void
) => void;
// DB save content progress listener
onDbSaveContentProgress: (
callback: (count: number) => void
) => void;
removeDbSaveContentProgress: () => void;
onDbOperationEvent?: (
callback: (data: DbOperationEvent) => void
) => () => void;
dbDeleteAllPlaylists: (
operationId?: string
) => Promise<{ success: boolean }>;
dbCancelOperation: (
operationId: string
) => Promise<{ success: boolean }>;
// Playback positions
dbSavePlaybackPosition: (
playlistId: string,
data: {
contentXtreamId: number;
contentType: 'vod' | 'episode';
seriesXtreamId?: number;
seasonNumber?: number;
episodeNumber?: number;
position: number;
duration: number;
title: string;
posterUrl?: string;
}
) => Promise<{ success: boolean }>;
dbGetPlaybackPosition: (
playlistId: string,
contentXtreamId: number,
contentType: 'vod' | 'episode'
) => Promise<PlaybackPositionData | null>;
dbGetSeriesPlaybackPositions: (
playlistId: string,
seriesXtreamId: number
) => Promise<PlaybackPositionData[]>;
dbGetRecentPlaybackPositions: (
playlistId: string,
limit?: number
) => Promise<PlaybackPositionData[]>;
dbGetAllPlaybackPositions: (
playlistId: string
) => Promise<PlaybackPositionData[]>;
dbClearAllPlaybackPositions: (
playlistId: string
) => Promise<{ success: boolean }>;
dbClearPlaybackPosition: (
playlistId: string,
contentXtreamId: number,
contentType: 'vod' | 'episode'
) => Promise<{ success: boolean }>;
onPlaybackPositionUpdate: (
callback: (data: PlaybackPositionData) => void
) => () => void;
closeExternalPlayerSession: (
sessionId: string
) => Promise<ExternalPlayerSession | null>;
// Downloads
downloadsStart: (data: {
playlistId: string;
xtreamId: number;
contentType: 'vod' | 'episode';
title: string;
url: string;
posterUrl?: string;
downloadFolder: string;
headers?: {
userAgent?: string;
referer?: string;
origin?: string;
};
seriesXtreamId?: number;
seasonNumber?: number;
episodeNumber?: number;
// Playlist info for auto-creation if needed
playlistName?: string;
playlistType?:
| 'xtream'
| 'stalker'
| 'm3u-file'
| 'm3u-text'
| 'm3u-url';
serverUrl?: string;
portalUrl?: string;
macAddress?: string;
}) => Promise<{ success: boolean; id?: number; error?: string }>;
downloadsCancel: (
downloadId: number
) => Promise<{ success: boolean; error?: string }>;
downloadsRetry: (
downloadId: number,
downloadFolder: string
) => Promise<{ success: boolean; error?: string }>;
downloadsRemove: (
downloadId: number
) => Promise<{ success: boolean; error?: string }>;
downloadsGetList: (playlistId?: string) => Promise<DownloadItem[]>;
downloadsGet: (downloadId: number) => Promise<DownloadItem | null>;
downloadsGetDefaultFolder: () => Promise<string>;
downloadsSelectFolder: () => Promise<string | null>;
downloadsRevealFile: (
filePath: string
) => Promise<{ success: boolean; error?: string }>;
downloadsPlayFile: (
filePath: string
) => Promise<{ success: boolean; error?: string }>;
downloadsClearCompleted: (
playlistId?: string
) => Promise<{ success: boolean }>;
onDownloadsUpdate: (callback: () => void) => () => void;
};
process: NodeJS.Process;
require: NodeRequire;
}
/** Download item from the database */
interface DownloadItem {
id: number;
playlistId: string;
xtreamId: number;
contentType: 'vod' | 'episode';
seriesXtreamId?: number;
seasonNumber?: number;
episodeNumber?: number;
title: string;
url: string;
fileName?: string;
filePath?: string;
posterUrl?: string;
status: 'queued' | 'downloading' | 'completed' | 'failed' | 'canceled';
bytesDownloaded?: number;
totalBytes?: number;
errorMessage?: string;
createdAt?: string;
updatedAt?: string;
}
}
+56
View File
@@ -0,0 +1,56 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
// Content paths scoped to the Angular web app and shared libs
content: [
'./apps/web/src/**/*.{html,ts,scss}',
'./libs/**/*.{html,ts,scss}',
],
// Match Angular Material's dark theme class strategy
darkMode: 'class',
theme: {
extend: {
fontFamily: {
sans: ['Inter', 'Roboto', 'Helvetica Neue', 'sans-serif'],
},
colors: {
// Surface colors wired to Material sys vars so Tailwind
// utilities automatically respect the active theme
surface: 'var(--mat-sys-surface)',
'surface-low': 'var(--mat-sys-surface-container-low)',
'surface-mid': 'var(--mat-sys-surface-container)',
'surface-high': 'var(--mat-sys-surface-container-high)',
'on-surface': 'var(--mat-sys-on-surface)',
'on-surface-variant': 'var(--mat-sys-on-surface-variant)',
outline: 'var(--mat-sys-outline)',
'outline-variant': 'var(--mat-sys-outline-variant)',
primary: 'var(--mat-sys-primary)',
'on-primary': 'var(--mat-sys-on-primary)',
'primary-container': 'var(--mat-sys-primary-container)',
'on-primary-container': 'var(--mat-sys-on-primary-container)',
secondary: 'var(--mat-sys-secondary)',
'secondary-container': 'var(--mat-sys-secondary-container)',
'on-secondary-container':
'var(--mat-sys-on-secondary-container)',
tertiary: 'var(--mat-sys-tertiary)',
'tertiary-container': 'var(--mat-sys-tertiary-container)',
error: 'var(--mat-sys-error)',
'error-container': 'var(--mat-sys-error-container)',
},
borderRadius: {
widget: '14px',
pill: '999px',
card: '18px',
},
boxShadow: {
widget: '0 1px 4px rgba(0,0,0,0.12), 0 0 0 1px rgba(255,255,255,0.04)',
'widget-hover':
'0 4px 16px rgba(0,0,0,0.22), 0 0 0 1px rgba(255,255,255,0.06)',
card: '0 2px 8px rgba(0,0,0,0.15)',
},
},
},
// CRITICAL: disable preflight to avoid conflicts with Angular Material
corePlugins: {
preflight: false,
},
};

Some files were not shown because too many files have changed in this diff Show More