mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-08 17:06:15 -08:00
Full audit of CLAUDE.md, AGENTS.md, README.md and docs/architecture/ against the codebase; every fix is backed by current code: - remove documented-but-unimplemented IPTVNATOR_DISABLE_HARDWARE_ACCELERATION flag (no reads anywhere in apps/, libs/, tools/) - CLAUDE.md: add epg_channel_mappings to the schema table list - m3u-playlist-module: *-tab dirs -> *-view (+recent-view), selectActivePlaylist, real PlaylistState shape, ChannelEpgMetadata instead of removed EnrichedChannel, actual /workspace/playlists routes, per-view outputs, live-epg-panel-state key - workspace-dashboard: per-rail Settings.dashboardRails toggles, three missing rails in the diagram, split live-favorites/recent-live rails, welcome-dashboard empty-state type, RECENTLY_WATCHED_LIVE_TV title key - stalker-portal: CategoryContentViewComponent for vod/series, collection-route components for favorites/recent, corrected series-view/favorites-button paths, actor/:personId route, epg panel selectors - category-management: reloadCategories lives in with-content.feature.ts, workspace-context-panel owns the dialog, XtreamPendingRestoreService flow - stalker-mock-server (+app README): scenario-seeded faker, resetAll() clears content cache too, ordinal season episode ids, handlers/ dir location - sqlite-db-worker: cancellation shipped (drop from out-of-scope), full operations module list - portal-detail-navigation: replace three removed component paths - tmdb-metadata-enrichment: details cache keys are id:<tmdbId>|v2 - electron-security: CSP frame-src youtube-nocookie exception, sandbox: !frameCopyExperiment nuance - download-manager: libs/portal/xtream instead of xtream-electron folder, data-driven downloads nav, drop removed app-search-result-item note - playlist-backup-restore: settings-backup facade owns the import handoff - workspace-shell: functional workspaceEntryRedirect, playlists route children - iptvnator-ui-guidelines: EPG card radius 11px, detail-view mixin is `base` - embedded-mpv-native, player-controls-contract: minor precision fixes Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
184 lines
8.6 KiB
Markdown
184 lines
8.6 KiB
Markdown
# Category Management Feature
|
|
|
|
## Overview
|
|
|
|
Xtream API playlists often contain many categories, some of which may be empty, in another language, or simply not relevant to the user. The category management feature allows users to hide unwanted categories from the sidebar while keeping them in the database for potential future use.
|
|
|
|
## User Flow
|
|
|
|
1. User navigates to an Xtream playlist (Live TV, Movies, or Series section)
|
|
2. In the sidebar header, next to "All categories", there's a **tune icon button**
|
|
3. Clicking it opens the **Category Management Dialog**
|
|
4. User sees all categories with checkboxes (checked = visible, unchecked = hidden)
|
|
5. User can:
|
|
- Individually toggle categories
|
|
- Use "Select All" / "Deselect All" buttons
|
|
- Search/filter categories by name
|
|
6. On save, visibility preferences are persisted to the database
|
|
7. Hidden categories no longer appear in the sidebar
|
|
|
|
## Technical Implementation
|
|
|
|
### Database Schema
|
|
|
|
Added `hidden` column to the `categories` table:
|
|
|
|
```sql
|
|
ALTER TABLE categories ADD COLUMN hidden INTEGER DEFAULT 0
|
|
```
|
|
|
|
- `hidden = 0` (false): Category is visible (default)
|
|
- `hidden = 1` (true): Category is hidden
|
|
|
|
**Migration**: Uses a safe migration pattern in `connection.ts` that catches errors for already-applied migrations, ensuring existing users get the new column automatically.
|
|
|
|
### Backend (Electron)
|
|
|
|
**File**: `apps/electron-backend/src/app/events/database/category.events.ts`
|
|
|
|
| IPC Handler | Purpose |
|
|
| ------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
|
|
| `DB_GET_CATEGORIES` | Returns visible categories only (`hidden = false`) in SQLite insertion order, preserving the Xtream server order by default |
|
|
| `DB_GET_ALL_CATEGORIES` | Returns all categories (for management dialog) |
|
|
| `DB_UPDATE_CATEGORY_VISIBILITY` | Batch updates `hidden` status for category IDs |
|
|
|
|
### Frontend Services
|
|
|
|
**File**: `libs/services/src/lib/database-electron.service.ts`
|
|
|
|
| Method | Purpose |
|
|
| ---------------------------- | ------------------------------ |
|
|
| `getXtreamCategories()` | Sidebar display (filtered) |
|
|
| `getAllXtreamCategories()` | Management dialog (unfiltered) |
|
|
| `updateCategoryVisibility()` | Save visibility changes |
|
|
|
|
### Components
|
|
|
|
**Category Management Dialog**
|
|
|
|
- Path: `libs/portal/xtream/feature/src/lib/category-management-dialog/`
|
|
- Features:
|
|
- Checkbox list of all categories
|
|
- Select All / Deselect All buttons
|
|
- Search/filter with clearable input
|
|
- Shows selected count vs total
|
|
- Saves changes to database on confirm
|
|
|
|
**Integration Points**
|
|
|
|
- `libs/workspace/shell/feature/src/lib/workspace-context-panel/workspace-context-panel.component.ts`
|
|
renders the tune icon button for Xtream Live TV, Movies, and Series sidebars.
|
|
- The workspace context panel lazy-loads `CategoryManagementDialogComponent`
|
|
from `@iptvnator/portal/xtream/feature`, opens it with playlist ID, content
|
|
type, and item counts, then calls `xtreamStore.reloadCategories()` after a
|
|
successful dialog save.
|
|
|
|
### Store
|
|
|
|
**File**: `libs/portal/xtream/data-access/src/lib/stores/features/with-content.feature.ts`
|
|
|
|
`reloadCategories()` (exposed on the `XtreamStore` facade via feature composition) refreshes categories from the database after visibility changes, ensuring the sidebar updates immediately.
|
|
|
|
## Behavior Notes
|
|
|
|
- **New categories**: When a playlist is refreshed, new categories from the remote API are added with `hidden = false` (visible by default)
|
|
- **Persistence**: Visibility settings survive playlist refresh (see below)
|
|
- **Per-playlist, per-type**: Categories are managed per playlist and per content type (live/movies/series)
|
|
- **No content deletion**: Hiding a category only affects sidebar visibility; the category and its content remain in the database
|
|
- **Display order**: The sidebar defaults to server order. Users can switch the
|
|
category panel to `A-Z` or `Z-A` from the sort menu next to category search.
|
|
- **All-hidden recovery**: Once the selected Xtream type is loaded, the manage
|
|
categories button remains available even if every visible category has been
|
|
hidden. The sidebar category list is filtered, but the dialog reads all
|
|
categories through `getAllXtreamCategories()` so users can select categories
|
|
again.
|
|
|
|
### Visibility Preservation During Refresh
|
|
|
|
When a user refreshes an Xtream playlist, hidden category preferences are preserved through the following mechanism:
|
|
|
|
1. **Before deletion**: The `DB_DELETE_XTREAM_CONTENT` handler extracts and returns the `hidden` status of all categories (keyed by `xtreamId` and `type`)
|
|
2. **Temporary storage**: The hidden categories are stored in `localStorage` under key `xtream-restore-{playlistId}` along with favorites and recently viewed data
|
|
3. **During re-import**: When categories are saved via `DB_SAVE_CATEGORIES`, the data source checks `localStorage` for saved hidden category xtreamIds
|
|
4. **Restoration**: Categories matching the saved xtreamIds are inserted with `hidden = true`, preserving the user's visibility preferences
|
|
5. **ID normalization**: Xtream category IDs arrive from the API as strings, while SQLite stores `categories.xtream_id` as an integer. Restoration must normalize incoming `category_id` values before matching them against saved hidden-category xtreamIds.
|
|
|
|
This ensures that users don't lose their category visibility customizations when refreshing playlists to get updated content.
|
|
|
|
### Debugging Note
|
|
|
|
Hidden-category restoration runs through the Electron DB worker. When debugging
|
|
or validating a fix in a live Electron app:
|
|
|
|
1. rebuild the worker-backed Electron runtime
|
|
2. restart the running Electron process
|
|
3. reconnect `agent-browser --cdp 9222`
|
|
|
|
Otherwise the app may still be using an older
|
|
`dist/apps/electron-backend/workers/database.worker.js` bundle even though the
|
|
TypeScript source has already been updated.
|
|
|
|
## Files Changed
|
|
|
|
```
|
|
libs/shared/database/src/lib/
|
|
├── schema.ts # Added hidden column to categories table
|
|
└── connection.ts # Added migration for existing databases
|
|
|
|
apps/electron-backend/src/app/
|
|
├── events/database/category.events.ts # IPC handlers (including hidden category restoration)
|
|
├── events/database/xtream.events.ts # Returns hidden categories during content deletion
|
|
└── api/main.preload.ts # Exposed new IPC methods (with hidden category params)
|
|
|
|
libs/services/src/lib/
|
|
└── database-electron.service.ts # Service methods (with hidden category support)
|
|
|
|
libs/playlist/shared/ui/src/lib/
|
|
├── recent-playlists/
|
|
│ └── recent-playlists.component.ts # Persists hidden categories (restore state) via XtreamPendingRestoreService on refresh
|
|
└── playlist-refresh-action.service.ts # Same restore-state persistence for the header refresh action
|
|
|
|
libs/services/src/lib/
|
|
└── xtream-pending-restore.service.ts # localStorage keyed `xtream-restore-{playlistId}`
|
|
|
|
libs/workspace/shell/feature/src/lib/
|
|
└── workspace-context-panel/
|
|
└── workspace-context-panel.component.ts # Tune button; lazy-loads the dialog, calls reloadCategories()
|
|
|
|
libs/portal/xtream/feature/src/lib/
|
|
└── category-management-dialog/ # Dialog component
|
|
├── category-management-dialog.component.ts
|
|
├── category-management-dialog.component.html
|
|
└── category-management-dialog.component.scss
|
|
|
|
libs/portal/xtream/data-access/src/lib/
|
|
├── data-sources/
|
|
│ └── electron-xtream-data-source.ts # Reads/passes hidden categories on save
|
|
└── stores/features/with-content.feature.ts # reloadCategories() (exposed on XtreamStore)
|
|
|
|
apps/web/src/assets/i18n/
|
|
└── en.json # Added translation keys
|
|
|
|
global.d.ts # TypeScript types for IPC methods
|
|
```
|
|
|
|
## Translation Keys
|
|
|
|
```json
|
|
{
|
|
"XTREAM": {
|
|
"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",
|
|
"NO_CATEGORIES": "No categories available",
|
|
"SAVE": "Save"
|
|
}
|
|
}
|
|
}
|
|
```
|