Skip to content

Commit 0291fa8

Browse files
authored
Merge pull request #653 from 4gray/feat-info-overlay-no-epg-layout
feat-info-overlay-no-epg-layout
2 parents 0823af2 + 0b31aac commit 0291fa8

27 files changed

+1659
-366
lines changed

.claude/settings.local.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,9 @@
77
],
88
"deny": [],
99
"ask": []
10-
}
10+
},
11+
"enabledMcpjsonServers": [
12+
"nx-mcp"
13+
],
14+
"enableAllProjectMcpServers": true
1115
}

.mcp.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"mcpServers": {
3+
"nx-mcp": {
4+
"type": "stdio",
5+
"command": "npx",
6+
"args": ["nx", "mcp"]
7+
}
8+
}
9+
}

.vscode/extensions.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"recommendations": ["ms-playwright.playwright", "esbenp.prettier-vscode"]
3+
}

CLAUDE.md

Lines changed: 83 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -94,144 +94,162 @@ This is an Nx monorepo with the following structure:
9494
- **apps/electron-backend** - Electron main process
9595
- **apps/web-e2e** - Playwright end-to-end tests
9696
- **libs/** - Shared libraries:
97-
- **m3u-state** - NgRx state management for playlists
98-
- **services** - Abstract DataService and implementations
99-
- **shared/interfaces** - TypeScript interfaces and types
100-
- **shared/m3u-utils** - M3U playlist utilities
101-
- **ui/components** - Reusable UI components
102-
- **ui/pipes** - Angular pipes
103-
- **ui/shared-portals** - Portal-related UI components
97+
- **m3u-state** - NgRx state management for playlists
98+
- **services** - Abstract DataService and implementations
99+
- **shared/interfaces** - TypeScript interfaces and types
100+
- **shared/m3u-utils** - M3U playlist utilities
101+
- **ui/components** - Reusable UI components
102+
- **ui/pipes** - Angular pipes
103+
- **ui/shared-portals** - Portal-related UI components
104104

105105
### Frontend Architecture (Angular)
106106

107107
**State Management**: Uses NgRx for playlist state management:
108+
108109
- Store configuration in `apps/web/src/app/app.config.ts`
109110
- Playlist state, actions, effects, and reducers in `libs/m3u-state/`
110111
- Entity adapter pattern for managing playlists collection
111112
- Router store integration for route-based state
112113

113114
**Routing**: Lazy-loaded routes in `apps/web/src/app/app.routes.ts`
115+
114116
- Home/playlists overview: `/`
115117
- Video player: `/playlists/:id` or `/iptv`
116118
- Xtream Codes: `/xtreams/:id` (different routes for Electron vs web)
117119
- Stalker portal: `/portals/:id`
118120
- Settings: `/settings`
119121

120122
**Service Architecture** (Factory Pattern):
123+
121124
- Abstract `DataService` class in `libs/services/src/lib/data.service.ts` defines the contract
122125
- Two environment-specific implementations:
123-
- `ElectronService` (`apps/web/src/app/services/electron.service.ts`) - Uses IPC to communicate with Electron backend
124-
- `PwaService` (`apps/web/src/app/services/pwa.service.ts`) - Uses HTTP API and IndexedDB for standalone web version
126+
- `ElectronService` (`apps/web/src/app/services/electron.service.ts`) - Uses IPC to communicate with Electron backend
127+
- `PwaService` (`apps/web/src/app/services/pwa.service.ts`) - Uses HTTP API and IndexedDB for standalone web version
125128
- Factory function `DataFactory()` in `apps/web/src/app/app.config.ts` determines which implementation to inject:
126-
```typescript
127-
if (window.electron) {
128-
return new ElectronService();
129-
}
130-
return new PwaService();
131-
```
129+
```typescript
130+
if (window.electron) {
131+
return new ElectronService();
132+
}
133+
return new PwaService();
134+
```
132135

133136
**Data Storage (Environment-Specific)**:
137+
134138
- **Electron**: libSQL/SQLite database via Drizzle ORM
135-
- Location: `~/.iptvnator/databases/iptvnator.db`
136-
- Full-featured relational database with foreign keys and indexes
137-
- Supports local file or remote Turso instance via env vars
139+
- Location: `~/.iptvnator/databases/iptvnator.db`
140+
- Full-featured relational database with foreign keys and indexes
141+
- Supports local file or remote Turso instance via env vars
138142
- **PWA (Web)**: IndexedDB via `ngx-indexed-db`
139-
- Browser-based NoSQL storage
140-
- Same schema structure but implemented in IndexedDB
141-
- Limited by browser storage quotas
143+
- Browser-based NoSQL storage
144+
- Same schema structure but implemented in IndexedDB
145+
- Limited by browser storage quotas
142146

143147
### Backend Architecture (Electron)
144148

145149
**Main Entry**: `apps/electron-backend/src/main.ts`
150+
146151
- Bootstraps Electron app and initializes database
147152
- Registers event handlers for IPC communication
148153

149154
**Database**:
155+
150156
- **ORM**: Drizzle ORM with libSQL (local SQLite file or remote Turso)
151157
- **Location**: `~/.iptvnator/databases/iptvnator.db` (avoids spaces in path)
152158
- **Schema** (`apps/electron-backend/src/app/database/schema.ts`):
153-
- `playlists` - Playlist metadata (M3U, Xtream, Stalker)
154-
- `categories` - Content categories (live, movies, series)
155-
- `content` - Streams/VOD/series items
156-
- `favorites` - User favorites
157-
- `recentlyViewed` - Watch history
159+
- `playlists` - Playlist metadata (M3U, Xtream, Stalker)
160+
- `categories` - Content categories (live, movies, series)
161+
- `content` - Streams/VOD/series items
162+
- `favorites` - User favorites
163+
- `recentlyViewed` - Watch history
158164
- **Connection**: `apps/electron-backend/src/app/database/connection.ts`
159-
- Auto-creates tables on init
160-
- Supports local file or remote via env vars (`LIBSQL_URL`, `LIBSQL_AUTH_TOKEN`)
165+
- Auto-creates tables on init
166+
- Supports local file or remote via env vars (`LIBSQL_URL`, `LIBSQL_AUTH_TOKEN`)
161167

162168
**IPC Communication**:
169+
163170
- **Preload script**: `apps/electron-backend/src/app/api/main.preload.ts`
164-
- Exposes `window.electron` API via `contextBridge`
165-
- All IPC channels defined here (playlist operations, EPG, database CRUD, external players, etc.)
171+
- Exposes `window.electron` API via `contextBridge`
172+
- All IPC channels defined here (playlist operations, EPG, database CRUD, external players, etc.)
166173
- **Event handlers**: `apps/electron-backend/src/app/events/`
167-
- `database.events.ts` - Database CRUD operations
168-
- `playlist.events.ts` - Playlist import/update
169-
- `epg.events.ts` - EPG fetch and parsing (uses worker)
170-
- `xtream.events.ts` - Xtream Codes API
171-
- `stalker.events.ts` - Stalker portal API
172-
- `player.events.ts` - External player (MPV, VLC) integration
173-
- `settings.events.ts` - App settings
174-
- `electron.events.ts` - App version, etc.
174+
- `database.events.ts` - Database CRUD operations
175+
- `playlist.events.ts` - Playlist import/update
176+
- `epg.events.ts` - EPG fetch and parsing (uses worker)
177+
- `xtream.events.ts` - Xtream Codes API
178+
- `stalker.events.ts` - Stalker portal API
179+
- `player.events.ts` - External player (MPV, VLC) integration
180+
- `settings.events.ts` - App settings
181+
- `electron.events.ts` - App version, etc.
175182

176183
**Workers**:
184+
177185
- EPG parsing runs in worker thread: `apps/electron-backend/src/app/workers/epg-parser.worker.ts`
178186

179187
### Key Features
180188

181189
**Playlist Support**:
190+
182191
- M3U/M3U8 files (local or URL)
183192
- Xtream Codes API (`username`, `password`, `serverUrl`)
184193
- Stalker portal (`macAddress`, `url`)
185194

186195
**Video Players**:
196+
187197
- Built-in HTML5 player with HLS.js or Video.js
188198
- External players: MPV, VLC (via IPC to Electron backend)
189199

190200
**EPG (Electronic Program Guide)**:
201+
191202
- XMLTV format support
192203
- Background parsing in worker thread
193204
- Stored in database for quick lookup
194205

195206
**Favorites and Recently Viewed**:
207+
196208
- Per-playlist favorites and global favorites
197209
- Recently viewed tracks watch history
198210

199211
**Internationalization**:
212+
200213
- Uses `@ngx-translate` with 16 language files in `apps/web/src/assets/i18n/`
201214

202215
## Development Notes
203216

204217
### Environment Detection and Dual-Mode Architecture
205218

206219
The app determines whether it's running in Electron or as a PWA by checking:
220+
207221
```typescript
208-
window.electron // truthy in Electron, undefined in browser
222+
window.electron; // truthy in Electron, undefined in browser
209223
```
210224

211225
**Why Dual Mode?**
212226
IPTVnator supports both Electron (desktop app) and PWA (web browser) to provide flexibility:
227+
213228
- **Electron**: Full-featured desktop experience with local database, external player support (MPV/VLC), and native file system access
214229
- **PWA**: Lightweight web version that runs in any browser without installation
215230

216231
**Environment-Specific Behavior**:
232+
217233
- `app.config.ts` - `DataFactory()` selects DataService implementation based on environment
218234
- `app.routes.ts` - Different routes for Xtream portals (Electron uses Tauri-based routes, PWA uses standard routes)
219235
- Storage layer switches automatically:
220-
- Electron → libSQL/Drizzle ORM → `~/.iptvnator/databases/iptvnator.db`
221-
- PWA → IndexedDB → Browser storage
236+
- ElectronlibSQL/Drizzle ORM`~/.iptvnator/databases/iptvnator.db`
237+
- PWAIndexedDBBrowser storage
222238
- External player support (MPV/VLC) only available in Electron
223239
- File system operations only available in Electron (uploading playlists from disk)
224240

225241
**Base Href Configuration**:
226242
The app uses different base href values depending on the build target:
243+
227244
- **Development & PWA**: `baseHref="/"` (from `index.html`)
228-
- Used by: `npm run serve:frontend`, `npm run build:frontend:pwa`
229-
- For web servers with proper routing
245+
- Used by: `npm run serve:frontend`, `npm run build:frontend:pwa`
246+
- For web servers with proper routing
230247
- **Electron Production**: `baseHref="./"` (overridden in build config)
231-
- Used by: `npm run build:backend`, `npm run make:app`
232-
- Required for `file://` protocol in Electron
248+
- Used by: `npm run build:backend`, `npm run make:app`
249+
- Required for `file://` protocol in Electron
233250

234251
Build configurations in `apps/web/project.json`:
252+
235253
- `production`: Electron build with `baseHref="./"`
236254
- `pwa`: Web deployment with `baseHref="/"`
237255
- `development`: Dev mode with `baseHref="/"` from index.html
@@ -248,20 +266,23 @@ The factory pattern ensures a single codebase works in both environments without
248266
### Nx Commands
249267

250268
Use `nx` CLI for better performance:
269+
251270
```bash
252271
nx run <project>:<target>
253272
# Example: nx run web:build
254273
# Example: nx run electron-backend:serve
255274
```
256275

257276
To run multiple projects:
277+
258278
```bash
259279
nx run-many --target=test --all
260280
```
261281

262282
### Electron Build Process
263283

264284
The Electron backend depends on the web app being built first:
285+
265286
- `electron-backend:build` depends on `web:build`
266287
- Output goes to `dist/apps/electron-backend` (backend) and `dist/apps/web` (frontend)
267288
- Packaging combines both into distributable
@@ -273,18 +294,35 @@ No formal migration system yet. Schema changes are applied via raw SQL in `conne
273294
### Common Patterns
274295

275296
**IPC Communication**:
297+
276298
1. Define handler in appropriate events file (e.g., `database.events.ts`)
277299
2. Register with `ipcMain.handle()` in the event bootstrap function
278300
3. Expose in preload script via `contextBridge.exposeInMainWorld()`
279301
4. Call from Angular via `window.electron.<methodName>()`
280302

281303
**Adding New Playlist Source**:
304+
282305
1. Add type to `libs/shared/interfaces/src/lib/playlist.interface.ts`
283306
2. Create event handler in `apps/electron-backend/src/app/events/`
284307
3. Add UI in `apps/web/src/app/home/`
285308
4. Update database schema if needed
286309

287310
**State Management**:
311+
288312
- Use NgRx for global application state (playlists)
289313
- Use component stores (`@ngrx/component-store`) for feature-specific state
290314
- Use NgRx signals for reactive data streams
315+
316+
<!-- nx configuration start-->
317+
<!-- Leave the start & end comments to automatically receive updates. -->
318+
319+
# General Guidelines for working with Nx
320+
321+
- When running tasks (for example build, lint, test, e2e, etc.), always prefer running the task through `nx` (i.e. `nx run`, `nx run-many`, `nx affected`) instead of using the underlying tooling directly
322+
- You have access to the Nx MCP server and its tools, use them to help the user
323+
- When answering questions about the repository, use the `nx_workspace` tool first to gain an understanding of the workspace architecture where applicable.
324+
- When working in individual projects, use the `nx_project_details` mcp tool to analyze and understand the specific project structure and dependencies
325+
- For questions around nx configuration, best practices or if you're unsure, use the `nx_docs` tool to get relevant, up-to-date docs. Always use this instead of assuming things about nx configuration
326+
- If the user needs help with an Nx configuration or project graph error, use the `nx_workspace` tool to get any errors
327+
328+
<!-- nx configuration end-->

apps/electron-backend/src/app/events/playlist.events.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,11 +151,13 @@ ipcMain.handle(AUTO_UPDATE_PLAYLISTS, async (event, playlists) => {
151151
continue;
152152
}
153153

154-
// Preserve the original _id and autoRefresh setting
154+
// Preserve user data when updating playlist
155155
updatedPlaylists.push({
156156
...playlistObject,
157157
_id: playlist._id,
158158
autoRefresh: playlist.autoRefresh,
159+
favorites: playlist.favorites || [], // Preserve favorites
160+
userAgent: playlist.userAgent, // Preserve custom user agent
159161
});
160162

161163
console.log(`Successfully updated playlist "${playlist.title}"`);

apps/web/src/app/home/video-player/video-player.component.html

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616
(toggleLeftDrawerClicked)="drawer.toggle()"
1717
(toggleRightDrawerClicked)="drawerRight.toggle()"
1818
(multiEpgClicked)="openMultiEpgView()"
19+
(infoOverlayClicked)="toggleInfoOverlay()"
1920
[activeChannel]="activeChannel"
21+
[isLeftDrawerOpened]="drawer.opened"
2022
(settingsClicked)="openSettings()"
2123
/>
2224
@if (activeChannel.radio === 'true') {
@@ -98,6 +100,15 @@
98100
[channel]="activeChannel"
99101
[epgProgram]="(epgProgram$ | async)!"
100102
/>
103+
104+
<!-- channel number overlay -->
105+
@if (showChannelNumberOverlay) {
106+
<div class="channel-number-overlay">
107+
<div class="channel-number-display">
108+
{{ channelNumberInput }}
109+
</div>
110+
</div>
111+
}
101112
}
102113
}
103114
</mat-drawer-content>

apps/web/src/app/home/video-player/video-player.component.scss

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,39 @@
5454
}
5555
}
5656
}
57+
58+
.channel-number-overlay {
59+
position: fixed;
60+
top: 50%;
61+
left: 50%;
62+
transform: translate(-50%, -50%);
63+
z-index: 1000;
64+
pointer-events: none;
65+
}
66+
67+
.channel-number-display {
68+
background: rgba(0, 0, 0, 0.85);
69+
color: #fff;
70+
font-size: 6rem;
71+
font-weight: 700;
72+
font-family: 'DM Sans', sans-serif;
73+
padding: 2rem 3rem;
74+
border-radius: 16px;
75+
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
76+
border: 2px solid rgba(255, 255, 255, 0.1);
77+
min-width: 120px;
78+
text-align: center;
79+
letter-spacing: 0.05em;
80+
animation: scaleIn 0.15s ease-out;
81+
}
82+
83+
@keyframes scaleIn {
84+
from {
85+
opacity: 0;
86+
transform: scale(0.8);
87+
}
88+
to {
89+
opacity: 1;
90+
transform: scale(1);
91+
}
92+
}

0 commit comments

Comments
 (0)