mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-08 17:06:15 -08:00
Merge origin/master into PR 955
This commit is contained in:
commit
2a769ad44e
89 files changed
+6476
-465
No files matched your search
@@ -12,14 +12,26 @@
|
||||
|
||||
- Date display should follow the user-selected app language from `TranslateService`.
|
||||
- When a template renders localized month or weekday names, pass the normalized app locale explicitly to `DatePipe`.
|
||||
- Angular locale data is registered in [apps/web/src/app/app-date-locales.ts](/Users/4gray/Code/iptvnator/apps/web/src/app/app-date-locales.ts).
|
||||
- App language aliases are normalized in [libs/ui/pipes/src/lib/date-format.util.ts](/Users/4gray/Code/iptvnator/libs/ui/pipes/src/lib/date-format.util.ts):
|
||||
- `ary` -> `ar-MA`
|
||||
- `by` -> `be`
|
||||
- `zhtw` -> `zh-Hant`
|
||||
- Angular locale data is registered in [apps/web/src/app/app-date-locales.ts](/apps/web/src/app/app-date-locales.ts).
|
||||
- App language aliases are normalized in [libs/ui/pipes/src/lib/date-format.util.ts](/libs/ui/pipes/src/lib/date-format.util.ts):
|
||||
- `ary` -> `ar-MA`
|
||||
- `by` -> `be`
|
||||
- `zhtw` -> `zh-Hant`
|
||||
|
||||
## Parsing Boundaries
|
||||
|
||||
- Normalize provider-specific or legacy date strings to ISO as early as possible.
|
||||
- Keep optional epoch fields such as `startTimestamp` and `stopTimestamp` when the provider already supplies them.
|
||||
- Avoid new non-standard `Date.parse(...)` usage for provider formats; prefer explicit `date-fns` parsing when the input is not ISO.
|
||||
- Xtream `added` / `last_modified` values are provider-supplied epoch fields.
|
||||
Normalize them through `toXtreamRecentlyAddedTimestamp()` /
|
||||
`toXtreamRecentlyAddedEpochSeconds()` from `@iptvnator/shared/interfaces`
|
||||
before ranking or storing recently-added content. Values more than 24 hours
|
||||
in the future are treated as invalid so provider placeholders such as
|
||||
`2030-01-01` cannot permanently pin the top of recently-added rails.
|
||||
Recently-added ranking uses `added` before `last_modified` for live/VOD
|
||||
content and `last_modified` before `added` for series. The VOD/live fallback
|
||||
is intentional for providers that omit `added` but still expose a valid
|
||||
`last_modified` epoch. Legacy cached millisecond epochs in `content.added`
|
||||
are migrated to epoch seconds during database startup so indexed dashboard
|
||||
queries can continue to compare and sort text timestamps directly.
|
||||
@@ -0,0 +1,150 @@
|
||||
# PWA Self-hosted Architecture
|
||||
|
||||
This document describes the browser PWA and self-hosted Docker path.
|
||||
|
||||
## Ownership
|
||||
|
||||
- `apps/web` owns the Angular browser UI and PWA service worker configuration.
|
||||
- `apps/web-backend` owns the browser-only backend proxy for remote playlist,
|
||||
Xtream, and Stalker requests.
|
||||
- `docker/` owns the production self-hosted image that bundles the PWA and
|
||||
`web-backend` into one container.
|
||||
|
||||
The old external `4gray/iptvnator-backend` repository is not required for the
|
||||
default self-hosted deployment. Sync behavior from that repository only when a
|
||||
change intentionally restores or imports missing backend capabilities.
|
||||
|
||||
## Runtime Backend Configuration
|
||||
|
||||
The PWA reads `window.__IPTVNATOR_CONFIG__.BACKEND_URL` through
|
||||
`apps/web/src/app/services/runtime-config.ts`. The static placeholder lives at
|
||||
`apps/web/src/assets/app-config.js` and keeps hosted builds working without
|
||||
Docker-specific values.
|
||||
|
||||
The Docker entrypoint rewrites `assets/app-config.js` at container startup.
|
||||
`ngsw-config.json` explicitly excludes this file from Angular service worker
|
||||
asset hashing so a runtime rewrite does not break cache validation.
|
||||
|
||||
## Service Worker Build
|
||||
|
||||
Use the PWA build configuration for browser deployments:
|
||||
|
||||
```bash
|
||||
pnpm nx build web --configuration=pwa
|
||||
```
|
||||
|
||||
The build must emit these files in `dist/apps/web`:
|
||||
|
||||
- `ngsw-worker.js`
|
||||
- `ngsw.json`
|
||||
- `safety-worker.js`
|
||||
- `worker-basic.min.js`
|
||||
|
||||
`web:serve-static` serves `dist/apps/web` and builds with `web:build:pwa`, so it
|
||||
exercises the same output layout as Docker. If Nx daemon state returns stale
|
||||
service worker outputs while changing build options, run:
|
||||
|
||||
```bash
|
||||
pnpm nx reset
|
||||
pnpm nx build web --configuration=pwa --skip-nx-cache
|
||||
```
|
||||
|
||||
## Web Backend
|
||||
|
||||
The current self-hosted PWA uses these `apps/web-backend` routes:
|
||||
|
||||
- `GET /health`
|
||||
- `GET /config.js`
|
||||
- `POST /provider-targets` with `{ "url": "<provider-url>" }`
|
||||
- `GET /parse?targetId=<id>`
|
||||
- `GET /xtream?targetId=<id>&username=<u>&password=<p>&action=<action>`
|
||||
- `GET /stalker?targetId=<id>&macAddress=<mac>&action=<action>`
|
||||
|
||||
The PWA continues to use `PwaService`; only the backend base URL is resolved at
|
||||
runtime. Electron routes remain owned by the Electron backend and preload
|
||||
bridge.
|
||||
|
||||
EPG/XMLTV is not a supported self-hosted PWA capability yet. Do not document it
|
||||
as part of the Docker user flow or use it as the readiness signal for this path.
|
||||
|
||||
Provider URLs are registered before proxy calls so the proxy endpoints do not
|
||||
accept raw target URLs in query strings. Registration validates the target URL
|
||||
before any outbound request:
|
||||
|
||||
- only `http:` and `https:` provider URLs are accepted
|
||||
- URL credentials are rejected
|
||||
- loopback, private, link-local, and reserved network targets are blocked by
|
||||
default
|
||||
- `IPTVNATOR_PROXY_ALLOW_PRIVATE_NETWORKS=1` explicitly enables trusted
|
||||
local/LAN targets for development, mock servers, or private deployments
|
||||
|
||||
Do not disable TLS certificate validation in the backend proxy. For private
|
||||
certificate authorities, configure Node with `NODE_EXTRA_CA_CERTS`.
|
||||
|
||||
## PWA Portal User Data
|
||||
|
||||
Xtream favorites and recently viewed items use the browser-side
|
||||
`PwaXtreamDataSource` when Electron DB preload APIs are unavailable. The PWA
|
||||
stores this user activity in localStorage:
|
||||
|
||||
- `xtream-favorites`
|
||||
- `xtream-recent-items`
|
||||
|
||||
Entries should include a content snapshot when the item is added. Global
|
||||
collection routes and the dashboard can then restore titles, posters, content
|
||||
type, and category IDs after navigation or a page reload without relying on the
|
||||
Electron SQLite content table.
|
||||
|
||||
Shared collection services must not import `@iptvnator/portal/xtream/data-access`
|
||||
directly. Use `XTREAM_COLLECTION_DATA_SOURCE` from
|
||||
`@iptvnator/portal/shared/util` and bind it to `XTREAM_DATA_SOURCE` at the app
|
||||
provider boundary (`apps/web/src/app/app.config.ts`). This keeps
|
||||
`portal-shared-util` provider-neutral and avoids adding new Nx boundary cycles.
|
||||
|
||||
## Docker Runtime
|
||||
|
||||
The Docker image has two stages:
|
||||
|
||||
1. Build stage installs dependencies and runs `web:pwa` plus `web-backend`.
|
||||
2. Runtime stage uses `node:22-alpine` with nginx installed. nginx serves
|
||||
`dist/apps/web` and proxies `/api/*` to the local Express backend.
|
||||
The entrypoint renders the nginx config from a `${PORT}` template, starts the
|
||||
backend, waits for `/health`, and then starts nginx. If either process exits
|
||||
after startup, the entrypoint exits the container so the compose restart
|
||||
policy can recover the service.
|
||||
|
||||
Default runtime values:
|
||||
|
||||
- `BACKEND_URL=/api`
|
||||
- `CLIENT_URL=http://localhost:4333`
|
||||
- `PORT=3000`
|
||||
- `IPTVNATOR_PROXY_ALLOW_PRIVATE_NETWORKS=0`
|
||||
- `NODE_EXTRA_CA_CERTS` unset
|
||||
|
||||
When hosting behind another domain, set `CLIENT_URL` to the browser origin and
|
||||
keep `BACKEND_URL=/api` unless the reverse proxy exposes the backend elsewhere.
|
||||
Only set `IPTVNATOR_PROXY_ALLOW_PRIVATE_NETWORKS=1` when the self-hosted
|
||||
instance is restricted to trusted users and intentionally needs private network
|
||||
IPTV targets. For providers using private certificate authorities, mount the CA
|
||||
bundle into the container and set `NODE_EXTRA_CA_CERTS` to that mounted path.
|
||||
|
||||
## Validation
|
||||
|
||||
Use the narrow validation ladder for self-hosted changes:
|
||||
|
||||
```bash
|
||||
pnpm nx test web-backend
|
||||
pnpm nx test web --runTestsByPath apps/web/src/app/services/runtime-config.spec.ts
|
||||
pnpm nx build web --configuration=pwa --skip-nx-cache
|
||||
pnpm nx build web-backend
|
||||
pnpm nx run web-e2e:e2e -- --project=chromium --grep @self-hosted
|
||||
docker compose -f docker/docker-compose.yml config
|
||||
```
|
||||
|
||||
Run `docker build -t iptvnator:self-hosted-test -f docker/Dockerfile .` when a
|
||||
Docker daemon is available.
|
||||
|
||||
For manual Docker smoke testing, run the Xtream and Stalker mock servers plus a
|
||||
small M3U fixture, then verify in the browser that M3U, Xtream, and Stalker can
|
||||
add sources, play an item, toggle favorites, populate global favorites,
|
||||
populate recently viewed, and appear on the dashboard rails.
|
||||
@@ -150,6 +150,24 @@ Command palette behavior is shell-owned but view-extensible:
|
||||
value is disabled. The new player setting applies to the next playback
|
||||
session; an existing stream is not re-mounted.
|
||||
|
||||
Keyboard shortcut help is shell-owned:
|
||||
|
||||
1. `WorkspaceKeyboardShortcutsService` is provided by `WorkspaceShellComponent`.
|
||||
It owns the workspace-scoped `document:keydown` listener for `?` /
|
||||
`Shift+/`.
|
||||
2. The listener ignores events from inputs, textareas, selects, and
|
||||
content-editable elements via `isTypingInInput(...)`.
|
||||
3. `libs/portal/shared/util/src/lib/keyboard-shortcut-definitions.ts` is the
|
||||
metadata registry for shortcuts shown in the help dialog and documented in
|
||||
README. `keyboard-shortcuts.ts` owns the display transformation and help
|
||||
trigger detection.
|
||||
Shortcuts that only work through the Electron bridge, such as embedded MPV
|
||||
controls, must set `electronOnly: true` so the PWA dialog does not advertise
|
||||
unavailable commands.
|
||||
4. New custom shortcuts should be added to that registry when the handler is
|
||||
added. Do not include native browser/editor behavior such as `Tab` or
|
||||
platform text editing shortcuts.
|
||||
|
||||
## Maintenance Guidance
|
||||
|
||||
Use this document as the source of truth when changing workspace shell behavior.
|
||||
@@ -160,5 +178,7 @@ Use this document as the source of truth when changing workspace shell behavior.
|
||||
not duplicated inside the shell.
|
||||
3. If a provider route changes how playlist/session bootstrap works, update the
|
||||
route-session provider and shell-facing route contract together.
|
||||
4. Historical migration notes, cleanup lists, and one-off refactor steps should
|
||||
4. When adding a non-native keyboard shortcut, update the shared shortcuts
|
||||
registry, the help dialog tests, README, and the closest behavior test.
|
||||
5. Historical migration notes, cleanup lists, and one-off refactor steps should
|
||||
stay out of this file; track them in issues or PR notes instead.
|
||||
@@ -95,6 +95,16 @@ Response: `{ payload: <data>, action: <action> }`
|
||||
This mirrors the backend proxy in `apps/electron-backend` so the same
|
||||
Angular service code works in both environments.
|
||||
|
||||
### M3U fixture endpoint
|
||||
|
||||
```
|
||||
GET /playlist.m3u
|
||||
```
|
||||
|
||||
Returns a small deterministic four-channel playlist. The self-hosted PWA E2E
|
||||
suite uses this endpoint to verify M3U URL imports through `apps/web-backend`
|
||||
and the provider target registry.
|
||||
|
||||
### Stream stub endpoints
|
||||
|
||||
```
|
||||
|
||||
Reference in new issue
Block a user