Commit Graph
83 Commits
Author SHA1 Message Date
4gray 09b8752a3d fix(xtream): switch to XtreamApiService and sendRequest 2026-01-12 00:52:42 +01:00
4gray 51ce39e2b4 fix(ui): check portal statuses when menu opens 2026-01-12 00:43:21 +01:00
4gray 33d8036ecc Merge pull request #724 from 4gray/refactor/store-refactoring
refactor/store-refactoring
2026-01-12 00:40:40 +01:00
4gray 34c769e9a7 style(playlist-switcher): tweak button background 2026-01-12 00:39:11 +01:00
4gray dba45f27c3 fix(vjs-player): enable HLS quality selector 2026-01-12 00:39:11 +01:00
4gray 2630025b11 feat: restore hidden category state after playlist refresh 2026-01-11 21:20:50 +01:00
4gray afd8da0c25 feat: indicate loading while fetching details 2026-01-11 21:20:50 +01:00
4gray 971ad70893 refactor: add lifecycle-safe router unsubscribe and optimize portal checks 2026-01-10 16:53:05 +01:00
4gray 6b94fcbdd6 feat(ui): use playlist-switcher in all modules 2026-01-10 15:19:37 +01:00
4gray b9b7fc8a63 feat: add playlist switcher component UI and styles 2026-01-10 15:18:57 +01:00
4gray 529b53c66c fix(database): log errors for already applied migrations 2026-01-07 20:40:24 +01:00
4gray 2043b7d8a1 feat(xtream): add category management to hide/show categories
Add the ability to hide irrelevant or empty categories in Xtream playlists.
Users can now manage category visibility through a dialog accessible from
the sidebar header in both VOD/Series and Live TV views.

Features:
- New category management dialog with search filter and select/deselect all
- Visibility settings persisted to database per playlist
- Hidden categories are filtered from sidebar navigation
- New categories added during playlist refresh default to visible
- Database migration for existing installations

Files changed:
- Database: schema.ts, connection.ts (hidden column + migration)
- Backend: category.events.ts, main.preload.ts (IPC handlers)
- Frontend: new dialog component, store method, UI integration
- Translations: en.json
- Documentation: docs/architecture/category-management.md
2026-01-06 21:34:44 +01:00
4gray 5904025e82 refactor: remove unnecessary console logs from Stalker events and portal import components 2026-01-06 19:50:44 +01:00
4gray 0a4d00c081 Merge pull request #711 from 4gray/feat/epg-improvements
feat/epg-improvements
2026-01-06 00:40:07 +01:00
4gray 0662c15905 refactor(ui): tidy imports and cleanup RecentPlaylists 2026-01-05 21:55:19 +01:00
4gray f462569879 feat(types): allow empty episode info and export interface 2026-01-05 21:54:54 +01:00
4gray afad80e61b feat(ui): add ContentHero component and detail view styles
Add a new standalone ContentHero component (template and TS) that
provides a cinematic hero section with backdrop, poster, title,
description, tags/meta/action slots, and a back button event emitter.
The component chooses backdrop or poster as the background, falls back
to a default poster image on load error, and exposes inputs for title,
description, posterUrl, and backdropUrl.

Introduce extensive cinematic styles for the detail view:
- define CSS custom properties for light and dark themes, poster size,
  shadows, and color tokens
- implement gradient vignette, layout sizing, and theming via
  :host and :host-context(.dark-theme)
- change container sizing behavior to full-height and hide overflow

These changes create a reusable hero UI and themed detail-page styles
to support a Netflix-style streaming detail experience.
2026-01-05 21:54:54 +01:00
4gray 532b33a3a8 refactor(epg): tidy imports and format long lines
Reorder imports and remove an unused duplicate to improve clarity and
consistency. Reformat multi-argument and long console/log calls,
return objects and function arguments across multiple lines to keep
within line width and improve readability. Update array/object
literals and error handling pushes to use consistent multi-line
formatting. These changes are purely stylistic and do not alter
behavior; they make the code easier to read and maintain.
2026-01-05 21:52:45 +01:00
4gray 57246c421d fix: timezone handling
* EPG data is stored with ISO 8601 format including timezone offset
(e.g., 2025-12-26T16:00:00+01:00)
* When displayed, moment(isoString)
parses it correctly and converts to the user's local timezone
automatically
* No settings needed — times always show in the user's
machine timezone
2026-01-05 21:52:45 +01:00
4gray 16baf54b16 feat(stalker): support ministra shows under VOD content type
Update translations and refactor StalkerPortalImportComponent to use
Angular signals and readonly/dependency-injected readonly properties.
- Add new i18n keys: LOADING_SEASONS and NO_EPISODES; adjust
  PLAYBACK_ERROR punctuation.
- Replace EventEmitter @Output with a signals-based readonly output and
  mark form, constants and flags as readonly.
- Switch to inject() style for services and mark many injected fields
  private/readonly to clarify intent.
- Replace DataService import with STALKER_SERIAL_NUMBER token import.
- Improve logging formatting, whitespace and minor code cleanup.
- Minor template/style whitespace fixes.

These changes modernize the component for better immutability,
improve DX with clearer logging, and add missing user-facing
translation strings.
2026-01-05 21:44:29 +01:00
4gray 61eef5e00d feat(stalker): feat: add auth for stalker portal, expend portal import UI
Refactor stalker-series-view template to guard fields with conditionals
so that only available metadata is displayed. Replace selectedItem() with
displayItem() to use the updated selection accessor. Add checks for
director, actors, year/release date, genre/genres_str, imdb and kinopoisk
ratings to avoid showing empty labels.

Enhance stalker-portal-import component by adding reactive form fields
for serial/device IDs and signatures, importing MatProgressSpinnerModule,
and wiring TranslateService and StalkerSessionService into the component.
Include a small loading-container style. These changes prepare the UI for
improved import UX and safer rendering of optional series metadata.
2026-01-04 19:07:37 +01:00
4gray 99b5ad161f feat(ui): improve info overlay and add EPG header search styles
Update info-overlay template to read simplified EPG fields and
avoid indexing into arrays for title, icon and description so bindings
are resilient and clearer:
- Use epgProgram?.iconUrl instead of epgProgram?.icon?.[0]?.src
- Use epgProgram?.title instead of epgProgram?.title?.[0]?.value
- Use epgProgram?.desc instead of epgProgram?.desc?.[0]?.value
- Guard description rendering with epgProgram?.desc

Adjust multi-epg header layout and add search UI styles to support
desktop window chrome and draggable regions:
- Add left padding to #epg-navigation for macOS traffic lights, enable
  backdrop drag via -webkit-app-region: drag and set z-index to keep
  header above content.
- Exclude interactive elements (buttons, search inputs) from drag by
  applying -webkit-app-region: no-drag to maintain native interactions.
- Add extensive styles for a channel search container (search input,
  icons, clear button, filter count, animations) and scaffold a program
  search container.

These changes improve robustness of EPG data rendering and add styled
search controls while ensuring proper window dragging behavior on
desktop builds.
2026-01-02 17:22:09 +01:00
4gray 895a269200 feat(db): add EPG schema and IPC handlers for EPG storage
Add tables, indexes, FTS5 virtual table, and triggers to support EPG
(electronic program guide) data in the shared SQLite connection. The
changes introduce epg_channels and epg_programs tables, multiple
indexes for efficient lookups (by source, name, channel, start, and
time range), and an epg_programs_fts virtual table with triggers to
keep the full-text index synchronized with epg_programs.

Register EPG database event handlers in the Electron backend and
add an IPC handler for bulk-saving channels. The handler deletes
existing channels for a source and inserts new channels in chunks to
avoid large single inserts, returning the inserted count.

These changes enable storing, querying, and full-text searching EPG
data and prepare backend IPC endpoints for importing program guide
data.
2026-01-02 17:22:09 +01:00
4gray 81bdcd644c refactor: move global favorites to header 2025-12-26 00:53:14 +01:00
4gray 815279f49f feat(db): add shared database library with sql config
Introduce a shared database schema library for Drizzle ORM and
configure its TypeScript build settings. Move the canonical schema
into libs/shared/database/src/lib/schema.ts and expose strong
typing and table definitions for playlists, categories, content,
recently_viewed and favorites. Add tsconfig.lib.json to set
outDir, declaration output and node types for the shared lib.

Keep apps/electron-backend compatibility by re-exporting the
schema and types from the new shared library (apps/electron-backend
now imports the shared definitions rather than duplicating them).

These changes centralize the database schema as a single source
of truth, prevent duplication, and enable read-only consumers
(e.g. agent-backend) to depend on compiled type declarations.
2025-12-26 00:35:07 +01:00
4gray ac31cf18e5 refactor(web): replace individual action imports with namespaced
imports and update dispatch calls

Replace multiple direct or wildcard imports for actions with
namespaced action groups from 'm3u-state' (e.g. PlaylistActions,
ChannelActions, EpgActions). Update dispatch calls to use the
namespaced action creators (for example, setAdjacentChannelAsActive,
setEpgAvailableFlag, resetActiveEpgProgram, setCurrentEpgProgram,
setActiveEpgProgram, addPlaylist).

This cleans up imports, improves tree-shaking and readability,
and standardizes how actions are referenced across components. It
also fixes inconsistent import styles (wildcard vs. named) and
prepares the codebase for clearer action organization.
2025-12-21 00:42:48 +01:00
4gray 68b87040ad feat(m3u-state): reducers and add selectors
Move playlist reducers into a dedicated reducers module and re-export a
composed playlistReducer built from smaller reducer arrays (epg,
channel, playlist, favorites, filter). This extracts and organizes the
previously monolithic reducer implementation into focused reducer files,
improving modularity and maintainability.

Add simple selectors in the new reducers index for commonly accessed
pieces of PlaylistState (playlists, selected playlist id, epg availability,
active channel, current EPG program, channels list, playlists loaded flag,
current playlist id) so callers can import them from a single place.

These changes make reducer logic easier to reason about, enable
incremental testing and extension of individual reducer groups, and
centralize basic selectors for consistent usage across the app.
2025-12-20 23:59:40 +01:00
4gray 8482e7c76a style: remove redundant light-theme CSS block from playlist item
Delete an unnecessary media query that set `.meta` color for the
light color scheme in the recent-playlists playlist-item stylesheet.
The rule duplicated default styling and added extra specificity,
so removing it simplifies the CSS and avoids redundant overrides.

This reduces stylesheet size and potential maintenance confusion while
preserving visual behaviour across themes.
2025-12-14 17:01:02 +01:00
4gray aba6ef024f feat(ui): enable XC refresh only in Electron environment
Add an isElectron flag to PlaylistItemComponent and conditionally
render the refresh button only when running inside Electron.
This prevents exposing the server refresh action in non-Electron
(environments like the browser) where window.electron is unavailable
and the feature is not supported.

Update ensures safer behavior by checking !!window.electron in the
component and using that value in the template to guard the UI.
2025-12-06 21:44:50 +01:00
4gray ccc50573d4 feat(ui): add app-region drag/no-drag and tweak styles
Add app-region: drag to container and header elements and app-region:
no-drag to interactive controls multiple components so the
Tauri window dragging behaves correctly while keeping buttons and form
controls clickable. Expand header search max width from 500px to 800px
to give more room on larger screens. Clean up and restyle video-player
toolbar toolbar primary colors and unify toolbar spacing.

Files changed include navigation, sidebar, header, main containers,
live-stream layout, navigation-bar, stalker container, and video-player
toolbar. These changes improve window drag UX on desktop and refine
toolbar/header appearance.
2025-12-06 21:44:25 +01:00
4gray aa2d5b9508 feat(ui): add empty-state and expose addPlaylist event
Introduce explicit empty-state handling in RecentPlaylists:
- Replace previous direct rendering of an empty mat-list item with
  app-empty-state for two cases: a global "welcome" state when no
  playlists exist at all, and a "no-results" state when filters/search
  return nothing. This clarifies UX and provides a CTA for adding
  playlists in the welcome state.
- Change playlist data binding from playlists$ to playlistsData$ and
  adapt loops and accessors to data.playlists / data.totalCount.
- Keep existing global favorites item and playlist-item rendering.

Wire up addPlaylist event and components:
- Add addPlaylistClicked output to RecentPlaylists component and
  forward the event from the home component so the parent can open
  the add-playlist flow.
- Import EmptyStateComponent and PlaylistType types used by the new
  output.

Minor cleanup and imports:
- Reformat some imports and add tap to RxJS imports.
- Adjust template structure and placeholders for deferred loading.
2025-12-06 21:44:25 +01:00
4gray b82d47f6b6 feat(ui): add AddPlaylistMenu component for playlist imports
Introduce a reusable AddPlaylistMenuComponent that provides a Material
menu with options to add playlists via file, URL, text, Xtream or Stalker
portal. Define a PlaylistType union and expose a playlistTypeSelected
output so parent components can react to the selected import type.

- Add component TypeScript with Angular metadata and required Material
  imports.
- Add template with accessible menu items, icons, translation keys and
  click handlers that emit the selected PlaylistType.
- Organize menu items with a divider to separate common file/URL/text
  options from provider-specific imports.

This adds a focused UI building block for playlist import flows and
standardizes how import type selection is communicated to parent scopes.
2025-12-06 21:44:25 +01:00
4gray 578a9567d1 feat(ui): add recent-playlists empty state component
Add a new EmptyState component and template for the recent-playlists
widget, providing two visual states: "welcome" and "no-results".

- Create empty-state.component.html with:
  - a welcome illustration (monitor + WiFi) and content for first-time
    users, including translated title/description, add-playlist action
    button and features list.
  - a no-results illustration (magnifying glass + box) and compact
    content for empty search/results.
  - conditional rendering based on type() to switch states.

- Start empty-state.component.ts with type definition and imports for
  Angular Material and translation; wire up AddPlaylistMenu types.

This implements the UI for when there are no recent playlists and
provides the primary CTA to add the first playlist, improving onboarding
and empty-state UX.
2025-12-06 21:44:25 +01:00
4gray 5a453a3f40 style(recent-playlists): refine styles and add clipboard imports
Update recent playlists styles to improve visuals, hover feedback,
and theme adaptability. Key changes:
- Hide horizontal overflow on playlists list to avoid scroll bleed.
- Add rounded corners, subtle transitions, and hover background for
  mat-list-item; include light theme hover variant.
- Reduce drag preview radius, replace shadow with layered shadows,
  increase opacity, and extend drag animation duration for smoother
  interactions.
- Adjust responsive selector formatting.
- Add transitions and hover scaling to action buttons, plus light
  theme variant; improve icon opacity transitions.
- Improve icon container behavior and upload-type-icon visibility on
  hover.
- Restyle status dot and state shadows, tweak unavailable color.
- Restyle auto-refresh indicator with shadow, rotation on hover, and
  light theme background.
- Minor spacing and layout tweaks across SCSS.

Code imports:
- Add Clipboard and ClipboardModule import and include MatIconButton
  and MatTooltip references in playlist-info component to support new
  copy/tooltip UI affordances.

These changes enhance UX polish, accessibility of interactive affordances,
and light/dark theme consistency.
2025-12-06 21:44:25 +01:00
4gray 53cbd64575 feat(header): add home styling, search output and host binding
Enhance the header component to support a distinct "home" appearance
and emit search updates. Add a HostBinding that toggles a home-header
class from the isHome flag so styles can target the home state.
Expose a searchQuery output and wire an onSearchQueryUpdate method to
emit the search text, enabling parent components to react to user
searches.
Refactor imports to include HostBinding and output. Tidy toolbar metrics
and adjust element sizing for a compact brand block and pulsing logo.
Introduce comprehensive SCSS for the home header:
- gradient background, animated glow overlay, and edge accent
- brand block styling with blur, border, hover states and box-shadow
- logo sizing, pulse animation and responsive tweaks
- reduced toolbar height and overall visual polish
These changes separate home-specific styling from the default header
appearance and provide a programmatic hook for search interactions.
2025-12-06 21:44:25 +01:00
4gray 7ee2cc4eea feat(db): add API to delete all playlists and related rows
Add a new IPC handler_DELETE_ALL_PLAYLIST that removes all
and related data from the SQLite database in a safe order that respects
foreign key relationships. The handler deletes favorites and recently
viewed entries first, then content, categories, and finally playlists.
Errors are logged and propagated.

Expose the new operation in the renderer preload API as
dbDeleteAllPlaylists() to allow UI code to invoke the purge. This
provides a single-call way to clear playlists and their dependent
records for testing or user-driven reset.
2025-12-06 14:46:37 +01:00
4gray f05469cc44 feat(ui): extract channel list item template and add EPG dialog 2025-11-27 08:20:54 +01:00
4gray 008f267808 feat(ui/epg-list): replace mat-list with custom markup and add progress
Refactor EPG list template to remove Material selection list and 
dividers, replacing them with plain markup and CSS-friendly elements. 
Key changes: - Replace <mat-divider> with .header-divider for consistent
styling. - Replace mat-selection-list/mat-list-option with plain divs 
(.program-item,   .program-meta, .program-title) to allow richer DOM 
structure and avoid   Material selection semantics.
- Use track $index in ngFor to stabilize rendering and avoid using 
program   start/stop concatenation as key.
- Render live progress bar inside program items when a program is 
playing,   using calculateProgress(program) to set width.
- Convert empty-state <p> to .epg-not-available div for layout 
consistency. - Add clickable class and active class binding to 
interactive items. Code changes and cleanup:
- Update component imports to use ChangeDetectionStrategy and
  ChangeDetectorRef and remove unused Material imports (MatDivider, 
MatListModule)   from the component file.
- Adjust template bindings: use [innerHTML] and class bindings instead 
of   matList directives.
Why:
- Remove heavy dependency on Material selection list to gain finer 
control   over DOM and styles, enable custom progress UI and clickable 
behavior,
  and simplify template for better performance and maintainability.
2025-11-24 22:29:42 +01:00
4gray 573ca01925 fix(artplayer): manage Hls instance and centralize player teardown
Add a dedicated hls field and a destroyPlayer() helper to ensure Hls
instances are properly destroyed when the component is torn down or
re-initialized. Replace inline Hls creation with a guarded pattern that
destroys any existing hls before creating a new one, preventing leaks or
duplicate attachments. Use destroyPlayer() from ngOnDestroy and when the
channel input changes to centralize teardown logic and keep lifecycle
handling consistent.
2025-11-23 21:53:01 +01:00
4gray e279172dfe fix(ui): correct fonts, semicolons and preload target
- Add missing semicolon in apps/web/src/styles.scss to fix invalid CSS
  that could break style parsing for .scroll-viewport.
- Change preconnect in apps/web/src/index.html from fonts.gstatic.com to
  fonts.googleapis.com and consolidate multiple Google Fonts links into 
  a single stylesheet URL to reduce redundant requests and ensure 
  Material Icons and selected font families load together.
  Remove duplicated @import of Outfit in
  
  libs/ui/components/src/lib/multi-epg/multi-epg-container.component.scss, 
  switch component font-family to Roboto (with fallback) and update 
  button font to match, ensuring consistent typography and avoiding 
  external import duplication across components. ese changes fix a 
  ntax error, optimize font loading, and standardize
typography across the UI.
2025-11-23 18:50:46 +01:00
4gray 09ad2c3b1b refactor(ui): tidy imports, simplify cleanup, and format styles 2025-11-23 18:50:46 +01:00
4gray 6a8ea69492 feat(multi-epg): redesign multi-EPG styles with modern dark theme
Revamp the Multi-EPG component stylesheet to introduce a polished,
broadcast-control-room inspired dark theme and improved layout
styling.

- Add Google fonts (Outfit, JetBrains Mono) for a clean UI and mono
  date display.
- Introduce color variables, gradients and accents for consistent
  theming and easier maintenance.
- Rework base container (.parent) with subtle grid overlay and updated
  typography.
- Implement a frosted glass navigation bar (#epg-navigation) with
  blur, glow, and accessible button styles.
- Add today-date styling using a monospace font and glowing accent.
- Expand channels column width, update background, borders, shadows,
  and hover transitions for clearer channel separation.
- Replace many hard-coded colors with variables and add transitions
  for smoother interactions.
- Add utility classes for navigation buttons and improved disabled/
  hover states.

These changes improve visual hierarchy, accessibility, and maintainabiity
of the EPG UI while setting up a consistent design system for further
enhancements.
2025-11-22 11:40:16 +01:00
4gray 9073bf1bb3 feat(m3u): add compact mode and conditional EPG display
Add compact layout support for channel list items and make EPG
display conditional based on runtime environment and stored settings.

- Introduce .compact styles in channel-list-item.component.scss to
  reduce item height, padding, and logo size when EPG is hidden.
- Add StorageMap injection and read STORE_KEY.Settings in
  ChannelListContainerComponent to determine whether EPG is configured
  (only enable EPG in Electron when epgUrl exists; disable in PWA).
- Expose shouldShowEpg flag and itemSize getter to switch virtual
  scroll item size between 68 and 48 pixels.
- Bind [class.compact] on channel list item and wire [showEpg] input
  to channel-list-item components so item rendering adapts to mode.
- Replace hardcoded itemSize in cdk-virtual-scroll-viewport with
  dynamic [itemSize] to match compact/expanded layouts.

This reduces visual clutter and avoids showing EPG in environments
(where it is not configured or supported), improving UX and resource
usage.
2025-11-22 11:40:16 +01:00
4gray 5cf96d7112 feat(video-player): add channel number overlay UI
Add a transient channel number overlay to the video player UI so users
see the numeric channel feedback when entering or changing channels.

- Insert conditional overlay markup in the video-player template that
  renders when showChannelNumberOverlay is true and displays the
  channelNumberInput value.
- Add styles for .channel-number-overlay and
  .channel-number-display to center the overlay, style the numeric
  display (large bold font, dark translucent background, rounded
  corners, shadow) and include a brief scale-in animation.
- Keep overlay pointer-events disabled so it doesn't block player input.

This improves user experience by giving clear visual confirmation of
channel changes.
2025-11-22 11:40:16 +01:00
4gray 34ef9c57d1 fix: preserve favorites after auto-refresh 2025-11-22 11:40:16 +01:00
4gray 592f6e34f9 feat(toolbar): add info button and overlay toggle
Add "Show program info (Press I)" translation and an info icon
button to the video player toolbar. Emit an infoOverlayClicked event
from the toolbar and expose isLeftDrawerOpened to control the menu
icon state. Update the menu icon to reflect drawer open/closed state.

Implement showOverlay() on the info overlay component to toggle
visibility and auto-hide after 10 seconds when shown. This enables
manual toggling of the program info overlay via the new toolbar
button or keyboard shortcut, improving discoverability and user
control of program information.
2025-11-22 11:40:16 +01:00
4gray d564a0d564 feat(m3u): show current EPG program in channels list
Reset EPG fields when epgProgram becomes null to avoid stale
displayed durations and ensure consistent behavior when no program
is available.

Improve channel list container and item styling:
- hide horizontal overflow to prevent unexpected scrollbars
  (scroll-viewport, #all-channels, .channel-list).
- add empty-favorites layout and hint styles for clearer empty
  state presentation.
- refactor channel-list-item SCSS: introduce structured layout
  (.channel-list-item, .channel-content, .channel-logo,
  .channel-details), apply responsive truncation rules and font
  imports, add hover/active visuals and dark-theme support, and
  tweak drag-icon spacing.

These changes fix UI glitches (stale EPG, horizontal scrollbars)
and modernize the channel list presentation for better readability
and theming.
2025-11-22 11:40:16 +01:00
4gray 3bf328343b style(ui/info-overlay): redesign EPG layout and styles
Refactor the info-overlay template to introduce a structured EPG
layout: replace the previous flat channel-logo + content structure with
an .epg-layout wrapper that groups .channel-logo and a richer .content
area. Split content into .content-header (separate program title and
channel name), conditional program description rendering, and a
program-timeline containing explicit start/end times and a progress
track. Remove fixed image width attribute and rely on responsive CSS.

Revamp component SCSS: import refined fonts, increase overlay max-height,
add horizontal padding, and add new styles for .epg-layout, .channel-logo,
.content, .content-header, .program-title and related elements. Add
animations, improved image handling (object-fit + drop shadow), and
layout spacing to support varying content lengths and improve visual
hierarchy.

These changes improve responsiveness, accessibility of EPG text
display, and visual polish of the overlay.
2025-11-22 11:40:16 +01:00
4gray ce6aa1b3d1 feat(info-overlay): add no-EPG layout and gradient blur
Introduce a separate no-EPG presentation and move backdrop blur
into an isolated pseudo-element to avoid visual bleed and improve
layout control.

- Replace direct backdrop-filter on the overlay with a ::before
  pseudo-element that applies backdrop-filter and mask-image
  gradients (with -webkit- prefixed fallbacks) for a smoother
  gradient blur effect.
- Add isolation on the overlay to contain stacking context and set
  z-index of the pseudo-element to -1 to keep content above the blur.
- Add .no-epg modifier on the overlay and new .no-epg-layout,
  .channel-logo-large and .channel-name-large styles to provide a
  centered, accessible layout when no EPG data is available.
- Update template to render two distinct layouts: one when
  epgProgram exists (original detailed view) and one fallback view
  when epgProgram is missing, including larger channel logo and
  centered channel name.

These changes improve visual fidelity of the blur effect and add a
clear fallback UI for channels without EPG data.
2025-11-22 11:40:16 +01:00
4gray c8961c94d5 feat: use signal for active channel + listen for remote control events
- Replace local selected state with store signal (selectActive) in the
  channel list container so templates bind to activeChannel()?.url
  instead of comparing selected?.id. This unifies selection handling
  with the global store and prevents stale local state.
- Update selectChannel to dispatch setActiveChannel instead of mutating
  local selected property; keep EPG lookup behavior intact.
- Import selectActive alongside other selectors from m3u-state and
  remove unused local InjectionToken in video player.
- Add remote control listener in VideoPlayer (Electron) to handle
  channel up/down events and wire a new handleRemoteChannelChange
  method skeleton. Use combineLatest/take to safely read required
  observables for channel switching.
- Minor rxjs import and formatting adjustments.

These changes centralize active channel state in the store, simplify
template logic, and add support for remote channel changes on desktop.
2025-11-22 11:26:22 +01:00