Proyecto App Windows
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
# Playlist Backup/Restore Architecture
|
||||
|
||||
This document describes the versioned playlist backup/restore flow used by the
|
||||
settings screen.
|
||||
|
||||
## Entry Points
|
||||
|
||||
- UI: `/Users/4gray/Code/iptvnator/apps/web/src/app/settings/settings.component.ts`
|
||||
- Backup service: `/Users/4gray/Code/iptvnator/libs/services/src/lib/playlist-backup.service.ts`
|
||||
- Manifest types: `/Users/4gray/Code/iptvnator/libs/shared/interfaces/src/lib/playlist-backup.interface.ts`
|
||||
- Xtream pending restore storage:
|
||||
`/Users/4gray/Code/iptvnator/libs/services/src/lib/xtream-pending-restore.service.ts`
|
||||
|
||||
## Manifest Contract
|
||||
|
||||
Backups are versioned JSON manifests, not raw `Playlist[]` dumps and not SQLite
|
||||
database snapshots.
|
||||
|
||||
Top-level shape:
|
||||
|
||||
- `kind: "iptvnator-playlist-backup"`
|
||||
- `version: 1`
|
||||
- `exportedAt`
|
||||
- `includeSecrets`
|
||||
- `settings?.epgUrls`
|
||||
- `playlists[]`
|
||||
|
||||
The manifest is portable across machines because it stores playlist definitions
|
||||
and portable user state, while excluding cache-only database content.
|
||||
|
||||
## Export Scope
|
||||
|
||||
### M3U
|
||||
|
||||
M3U backups are self-contained.
|
||||
|
||||
- Always export canonical `rawM3u` from `PlaylistsService.getRawPlaylistById()`
|
||||
- Preserve source metadata when available:
|
||||
- original source kind: `url`, `file`, or `text`
|
||||
- original URL
|
||||
- `userAgent`, `referrer`, `origin`
|
||||
- `filePathHint` for provenance only
|
||||
- Export playlist-scoped user state:
|
||||
- favorites by channel URL
|
||||
- recently viewed M3U items
|
||||
- hidden group titles
|
||||
|
||||
The embedded raw text is the canonical restore artifact. The internal parsed
|
||||
playlist object graph is not the backup format.
|
||||
|
||||
### Xtream
|
||||
|
||||
Xtream backups export only connection metadata plus portable user state.
|
||||
|
||||
- Connection metadata:
|
||||
- `serverUrl`
|
||||
- `username`
|
||||
- `password`
|
||||
- User state:
|
||||
- hidden categories by `{ categoryType, xtreamId }`
|
||||
- favorites by `{ contentType, xtreamId, addedAt?, position? }`
|
||||
- recently viewed by `{ contentType, xtreamId, viewedAt }`
|
||||
- playback positions as `PlaybackPositionData[]`
|
||||
|
||||
Explicitly excluded:
|
||||
|
||||
- cached categories/content rows
|
||||
- import-status flags and other app-state cache markers
|
||||
- downloads
|
||||
|
||||
### Stalker
|
||||
|
||||
Stalker backups export connection metadata plus playlist-scoped favorites/recent
|
||||
state.
|
||||
|
||||
- Exported connection fields:
|
||||
- `portalUrl`
|
||||
- `macAddress`
|
||||
- `isFullStalkerPortal`
|
||||
- `username`
|
||||
- `password`
|
||||
- `userAgent`
|
||||
- `referrer`
|
||||
- `origin`
|
||||
- serial/device/signature fields when present
|
||||
- Exported user state:
|
||||
- favorites snapshots
|
||||
- recently viewed snapshots
|
||||
|
||||
Explicitly excluded:
|
||||
|
||||
- `stalkerToken`
|
||||
- `stalkerAccountInfo`
|
||||
- playback positions in v1
|
||||
|
||||
### App Settings
|
||||
|
||||
Only EPG source URLs are backed up at the app-settings level.
|
||||
|
||||
- Exported: `settings.epgUrls`
|
||||
- Excluded: cached EPG database content
|
||||
|
||||
## Import Flow
|
||||
|
||||
The settings component hands file contents to `PlaylistBackupService`.
|
||||
|
||||
The service:
|
||||
|
||||
1. Validates the manifest kind/version before any writes.
|
||||
2. Rejects legacy raw `Playlist[]` JSON blobs.
|
||||
3. Builds stable source fingerprints for merge-vs-create decisions.
|
||||
4. Upserts playlists into app playlist storage.
|
||||
5. Restores provider-specific user state.
|
||||
|
||||
Fingerprint rules:
|
||||
|
||||
- M3U URL playlists: normalized URL
|
||||
- M3U without URL: hash of canonical `rawM3u`
|
||||
- Xtream: normalized `serverUrl + username`
|
||||
- Stalker: normalized `portalUrl + macAddress`
|
||||
|
||||
If a fingerprint matches an existing playlist:
|
||||
|
||||
- keep the existing playlist ID
|
||||
- update mutable metadata from the backup
|
||||
- replace playlist-scoped state with the backup payload
|
||||
|
||||
If no fingerprint matches:
|
||||
|
||||
- create a new playlist
|
||||
- reuse `exportedId` only when it is unused
|
||||
- otherwise generate a new UUID
|
||||
|
||||
## Xtream Restore Contract
|
||||
|
||||
Xtream restore is type-aware end to end. The app no longer stores plain
|
||||
`xtream_id[]` arrays for refresh/import restore because IDs can collide across
|
||||
`live`, `movie`, and `series`.
|
||||
|
||||
Runtime contract:
|
||||
|
||||
- shared shape: `XtreamPendingRestoreState`
|
||||
- persisted in local storage by playlist ID
|
||||
- consumed by:
|
||||
- Xtream refresh actions
|
||||
- settings backup import
|
||||
- Xtream content initialization
|
||||
|
||||
Electron restore behavior:
|
||||
|
||||
1. Category import reads pending hidden-category state while saving categories.
|
||||
2. After content import, favorites/recent state is restored by typed
|
||||
`{ contentType, xtreamId }` matching.
|
||||
3. Playback positions are cleared and re-applied from backup state.
|
||||
|
||||
For existing Xtream playlists with a fully populated offline cache, backup
|
||||
import applies the restore immediately. Otherwise the typed restore payload is
|
||||
left pending until the next Xtream initialization/import.
|
||||
|
||||
## Current UX
|
||||
|
||||
The settings page now exports/imports “playlist backups” instead of the old
|
||||
raw JSON application dump.
|
||||
|
||||
- Export filename:
|
||||
`iptvnator-playlist-backup-YYYY-MM-DD.json`
|
||||
- Import summary reports:
|
||||
- imported
|
||||
- merged
|
||||
- skipped
|
||||
- failed
|
||||
Reference in New Issue
Block a user