* 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
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.
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.
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.
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.
Introduce a standalone EpgProgressPanelComponent with template and
bindings to show active, completed and queued EPG imports. The new
component:
- provides a header with title and optional "dismiss all" button when
multiple imports exist.
- lists active/completed imports with status icon, URL display,
dismiss button, and conditional progress bar for loading state.
- shows stats (channels/programs) or error text when available.
- renders a queued section with positions and dismiss controls.
- wires to EpgProgressService observables (imports, visibility and
counts) and implements helper getters (activeImports).
This adds UI for import progress feedback and controls so users can
monitor and manage EPG import operations. Files added:
- epg-progress-panel.component.ts
- epg-progress-panel.component.html
Introduce a lowercase display name index (Map) to allow O(1) resolution
from display name to channel id. Rebuild the index during merged-data
rebuild and use it in channel lookups to avoid expensive full scans.
Add a fallback partial-match pass only when the index lookup fails.
Add automatic and manual cleanup of expired programs:
- Add cleanupExpiredPrograms(hoursToKeep) to remove programs older
than the specified number of hours from epgDataMerged.
- Invoke cleanup after worker fetches (auto-cleanup with 24 hours).
- Expose an IPC handler EPG_CLEANUP_EXPIRED to trigger cleanup on
demand.
Other changes:
- Clear epgData.programs after merging to free memory.
- Log merged data rebuild and cleanup counts for observability.
These changes improve performance of channel resolution, reduce memory
usage by pruning stale program entries, and provide a manual hook for
on-demand maintenance.
Replace full-file parsing with a streaming SAX parser to avoid loading
entire XMLTV payloads into memory. Add support for gzipped feeds by
using streaming gunzip (createGunzip) and piping into a SaxesParser,
allowing incremental processing of channels and programmes.
Introduce:
- StreamingEpgParser class that incrementally builds channel and program
objects and emits batches.
- parseXmltvDate helper to normalize XMLTV datetimes to ISO strings.
- batching constants and response types for channel/program batches and
progress reporting.
- use of Readable/Saxes for streaming parsing and reduced memory use.
This change improves performance and memory usage for large EPG files,
enables progress reporting and batch emission to the main thread, and
prepares for handling very large or gzipped EPG sources.
Normalize .coderabbit.yaml structure and add automatic issue
labeling. Move auto_review under the top-level reviews key to match
expected nesting and restore YAML schema comment. Introduce
issue_enrichment.labeling with auto_apply_labels and detailed
labeling_instructions for bug, enhancement, and documentation so
issues are categorized automatically and consistently. Fix minor
formatting and spacing to improve readability and tooling support.
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.
Add a new mat-menu component for filtering and sorting playlists in the
header area. The filter section iterates playlistTypes and allows toggling
type selection with visual check state. The sort section adds options for
name (asc/desc) and date added (newest/oldest) with active-state visuals
and click handlers that call setSortOptions. A close button is also
included.
Remove unused/duplicate CSS rules from header styles: drop .filter-
container and obsolete .dropdown-menu-header rules to avoid styling
conflicts and reduce dead code. Adjust surrounding selector formatting.
Reduce the settings page container height calculation from
calc(100vh - 100px) to calc(100vh - 70px) so the content fits the
visible viewport when the header height is 70px. This prevents
unnecessary vertical overflow and avoids extra whitespace at the
bottom of the settings page.
Update English, German, and Russian locale files to improve playlist
UI text and provide explicit playlist type labels.
- Rename and adjust several labels: change FILTER_BY_TYPE to a more
descriptive "Playlist Types" and add a new FILTER_AND_SORT string.
- Normalize capitalization for SORT_BY ("Sort By") in en.json.
- Add PLAYLIST_TYPES object with keys for M3U, XTREAM, and STALKER,
providing localized descriptions for each language.
- Keep existing sorting options and parsing messages intact.
These changes make filtering, sorting, and playlist source options
clearer to users in multiple locales and prepare the UI for showing
playlist type choices.
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.
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.
Extract the file's basename and strip common playlist extensions
before passing it as the playlist title when loading from a selected
file. This replaces the previous hardcoded "from file" title with a
cleaner, context-aware name derived from the file path.
- import basename from node:path
- compute filename and remove .m3u, .m3u8, .pls, .txt extensions
- fall back to "from file" if resulting title is empty
This improves UX by giving imported playlists meaningful names.
Re-enable user selection for input and textarea elements so users
can select and copy text in form fields. Add an Electron context
menu handler that shows a focused edit menu only for recognized
text input types or editable fields. The menu includes Cut, Copy,
Paste and Select All and respects the editFlags to enable actions.
This restores native editing UX in the renderer while avoiding
global context menus elsewhere in the app.
Prevent global hotkeys from triggering while the user is typing in
input or textarea fields. Add a private isTypingInInput(event) helper
and short-circuit key handlers (info key and digit keys) to return
early when the event target is an input or textarea.
This avoids interfering with normal text entry (e.g., entering numbers
in forms) and prevents accidental overlay toggles or channel changes
while the user is focused on a form field.
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.
Add a Troubleshooting section to the README covering two common
platform-specific launch issues and how to resolve them.
- macOS: document Gatekeeper "App is damaged and can't be opened"
and show how to clear the quarantine flag with xattr.
- Linux: document chrome-sandbox SUID permission error and provide
two solutions — fix permissions (chown/chmod) for packaged installs,
or run with --no-sandbox by editing the desktop launcher or using the
command line.
These instructions reduce user confusion and support requests by
providing clear, actionable steps to get IPTVnator running on affected
systems.
Improve sandbox handling on Linux by detecting Snap, Flatpak,
and AppImage environments and applying appropriate Chromium
command-line switches:
- If running in Snap or Flatpak, disable Chromium's sandbox
(--no-sandbox) to avoid conflicts with the distribution's
own sandboxing.
- Otherwise (traditional packages and AppImage), disable the
SUID sandbox and prefer the user namespace sandbox
(--disable-setuid-sandbox). This avoids requiring a SUID
chrome-sandbox binary and aligns with modern Linux best
practices.
Also adjust apps/electron-backend/src/main.ts to only apply
these changes on Linux (process.platform === 'linux').
Minor formatting: expand the package.json copy "filter" array
to a multiline style for readability.
Add a publish-snap job to the CI workflow that runs after build and
only triggers for version tags (refs/tags/v*). The job downloads the
linux build artifacts, installs snapcraft, locates the generated .snap
file and uploads it to the Snapcraft Store releasing to the stable
channel. It validates the presence of a snap file and fails if none is
found.
This enables automated Snap distribution for tagged releases using the
SNAPCRAFT_STORE_CREDENTIALS secret.
Update GitHub Actions workflow to support multiple OS runners and CPU
architectures, standardize matrix keys, and adjust platform-specific
steps and artifact names.
- Replace simple os matrix with include entries specifying os, runner,
and arch to allow macOS x64/arm64 separation and explicit runners for
linux/windows.
- Use runner matrix value for runs-on and change timeout/strategy
accordingly.
- Adjust conditional checks to use normalized os values (linux, macos,
windows) rather than platform-specific runner labels.
- Install Linux system deps only when os == 'linux' and keep Flatpak
setup for electron-builder.
- Add a macOS-specific make step that passes the architecture to the
electron make command, while keeping a combined make step for
non-macOS builds.
- Upload macOS artifacts per architecture and rename artifact paths to
include arch; update release files list to include both macOS x64 and
arm64 artifact patterns.
These changes enable reliable, architecture-aware macOS builds,
prevent native module conflicts across runners, and ensure artifacts
are labeled and uploaded correctly.
Add a packaging rule to copy the built remote-control-web output from
dist/apps/remote-control-web into the installer as remote-control-web.
Previously the repository included the raw source pattern
remote-control-web/**/* which did not reflect the compiled build output.
By pointing files to the dist build and filtering all files, the packaged
app now contains the production web assets instead of source files.
This fixes missing runtime assets in releases and ensures the packaged
installer includes the correct built web app for remote control.
Add support for displaying local remote-control URLs and QR code in the
Settings UI, including styles for URL list, row layout, monospaced links,
and a QR container. Expose a new global API signature getLocalIpAddresses
for retrieving local IPs.
Fix several UI issues:
- Correct typo in header method name (opedAddPlaylistDialog -> openAddPlaylistDialog).
- Fix malformed GitHub URL and collapse img tag formatting.
- Reformat imports and viewChild usage for readability.
Change local development backend URL to localhost:3000 in the local
environment to point to the running local API during development.
These changes improve developer ergonomics (local backend), add a remote
control discovery UX for users on the same network, and tidy up header
bugs and formatting.
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.
Add new English keys for remote control URL and QR code to support
remote-control features in the settings UI. Extend French locale with
many missing and corrected translations: add "Playlists" root entry,
Xtream/Stalker import labels, UI copy improvements (e.g. "Chaînes",
grammar fixes), new playlist export/copy messages, search/auto-refresh
labels, and removal success message. Fix several typos and phrasing in
French strings (IPTV, chaînes, ajouter(e), requièrent).
These changes enable new remote-control functionality and improve UX
for French users by completing and correcting the translations.
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.