- Add o_name (original title) field to Stalker VOD interfaces
- Prefer o_name over name in adapters and grid list display
- Add playback position tracking for Stalker VOD content
- Support resume playback from last position in vod-details
- Add real-time position updates via IPC listener
- Add progress indicators for Stalker VOD items in grid view
- Add debug logging for VOD series seasons resource
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Added `VodDetailsRouteComponent` to handle VOD details with route parameters.
- Refactored existing `VodDetailsComponent` to use a unified structure for Xtream and Stalker portals.
- Enhanced VOD details display with normalized metadata and improved playback position handling.
- Integrated resizable sidebar functionality in main container and live stream layout components.
- Updated routing to use the new VOD details route component.
- Improved favorite toggling and download handling in VOD details.
- Adjusted styles for responsive sidebar and grid layouts.
Add comprehensive download functionality for Xtream and Stalker portals:
Backend (Electron):
- Add downloads table schema with foreign key to playlists
- Create downloads.events.ts with IPC handlers for download operations
- Support download start, cancel, retry, remove, and status queries
- Auto-create playlist entries for Stalker portals to satisfy FK constraints
- Add download folder selection and file reveal/play functionality
Frontend (Angular):
- Create DownloadsService with reactive signal-based state management
- Add DownloadsComponent with queue management UI
- Implement download buttons with three states: download, downloading, play local
- Support both Xtream and Stalker modes with proper playlist ID handling
- Add download progress indicators and status badges
UI Components:
- Update VodDetailsComponent with download/play-local buttons
- Update SeasonContainerComponent with episode download buttons
- Add navigation link to downloads page
- Style download buttons and progress indicators
Stalker Portal Support:
- Resolve stream URLs via fetchLinkToPlay API before downloading
- Handle both vod-series and regular-series episode types
- Use playlist._id for Stalker (vs portalId for Xtream)
- Pass playlist info for auto-creation in database
Translations:
- Add download-related strings for en, de, es, fr
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Move PlaybackPositionData interface to shared-interfaces lib
- Replace all `any` types with proper PlaybackPositionData typing
- Add comment clarifying position=duration semantics for watched episodes
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Swap videojs-hls-quality-selector for videojs-quality-selector-hls
and update package versions. Initialize plugins defensively: call the
new quality selector via qualitySelectorHls when available and wrap
both quality selector and aspectRatioPanel initializations in try/catch
blocks to avoid runtime errors if a plugin fails to load. Bump project
version to 0.18.0 and add the new dependency and packageManager entry.
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
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.
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.
* 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 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.
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.
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 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 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.
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.
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.
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.
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.
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.