From 52947bdfacd5f7b9b8155c4e9cc6bfacd3244e2e Mon Sep 17 00:00:00 2001 From: 4gray Date: Sat, 14 Feb 2026 11:45:56 +0100 Subject: [PATCH] refactor(logging): replace console.error and console.warn with logger utility in multiple components and services --- .../account-info/account-info.component.ts | 6 ++++-- .../category-management-dialog.component.ts | 6 ++++-- .../data-sources/pwa-xtream-data-source.ts | 4 +++- .../recently-viewed/recently-viewed.component.ts | 4 +++- .../search-results/search-results.component.ts | 4 +++- .../season-container.component.ts | 16 ++++++++++------ .../xtream-tauri/services/epg-queue.service.ts | 6 ++++-- .../stores/features/with-content.feature.ts | 13 ++++++------- .../stores/features/with-epg.feature.ts | 6 ++++-- .../stores/features/with-portal.feature.ts | 6 ++++-- .../stores/features/with-search.feature.ts | 4 +++- .../src/app/xtream-tauri/stores/xtream.store.ts | 10 ++++++---- .../vod-details/vod-details-route.component.ts | 11 +++++++---- .../app/xtream-tauri/with-favorites.feature.ts | 6 ++++-- .../src/app/xtream-tauri/with-recent-items.ts | 9 ++++----- 15 files changed, 69 insertions(+), 42 deletions(-) diff --git a/apps/web/src/app/xtream-tauri/account-info/account-info.component.ts b/apps/web/src/app/xtream-tauri/account-info/account-info.component.ts index 94cae7146..f463a92a3 100644 --- a/apps/web/src/app/xtream-tauri/account-info/account-info.component.ts +++ b/apps/web/src/app/xtream-tauri/account-info/account-info.component.ts @@ -7,6 +7,7 @@ import { TranslatePipe } from '@ngx-translate/core'; import { selectActivePlaylist } from 'm3u-state'; import { XtreamApiService } from '../services/xtream-api.service'; import { XtreamAccountInfo } from './account-info.interface'; +import { createLogger } from '../../shared/utils/logger'; @Component({ selector: 'app-account-info', @@ -22,6 +23,7 @@ export class AccountInfoComponent { }>(MAT_DIALOG_DATA); private readonly xtreamApiService = inject(XtreamApiService); private readonly store = inject(Store); + private readonly logger = createLogger('XtreamAccountInfo'); accountInfo: XtreamAccountInfo; formattedExpDate: string; @@ -59,7 +61,7 @@ export class AccountInfoComponent { ).toLocaleDateString(); } } catch (error) { - console.error('Failed to fetch account info:', error); + this.logger.error('Failed to fetch account info', error); } } @@ -70,4 +72,4 @@ export class AccountInfoComponent { get isTrial(): boolean { return this.accountInfo?.user_info?.is_trial === '1'; } -} \ No newline at end of file +} diff --git a/apps/web/src/app/xtream-tauri/category-management-dialog/category-management-dialog.component.ts b/apps/web/src/app/xtream-tauri/category-management-dialog/category-management-dialog.component.ts index 373ca23e3..69b6319ba 100644 --- a/apps/web/src/app/xtream-tauri/category-management-dialog/category-management-dialog.component.ts +++ b/apps/web/src/app/xtream-tauri/category-management-dialog/category-management-dialog.component.ts @@ -14,6 +14,7 @@ import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatSnackBar } from '@angular/material/snack-bar'; import { TranslatePipe } from '@ngx-translate/core'; import { DatabaseService, XCategoryFromDb } from 'services'; +import { createLogger } from '../../shared/utils/logger'; export interface CategoryManagementDialogData { playlistId: string; @@ -47,6 +48,7 @@ export class CategoryManagementDialogComponent implements OnInit { MatDialogRef ); readonly data = inject(MAT_DIALOG_DATA); + private readonly logger = createLogger('CategoryManagementDialog'); readonly isLoading = signal(true); readonly isSaving = signal(false); @@ -95,7 +97,7 @@ export class CategoryManagementDialogComponent implements OnInit { })) ); } catch (error) { - console.error('Error loading categories:', error); + this.logger.error('Error loading categories', error); } finally { this.isLoading.set(false); } @@ -175,7 +177,7 @@ export class CategoryManagementDialogComponent implements OnInit { this.dialogRef.close(true); } catch (error) { - console.error('Error saving category visibility:', error); + this.logger.error('Error saving category visibility', error); inject(MatSnackBar).open( 'Failed to save category visibility', 'Close', diff --git a/apps/web/src/app/xtream-tauri/data-sources/pwa-xtream-data-source.ts b/apps/web/src/app/xtream-tauri/data-sources/pwa-xtream-data-source.ts index 9fa5ab037..befc0cffd 100644 --- a/apps/web/src/app/xtream-tauri/data-sources/pwa-xtream-data-source.ts +++ b/apps/web/src/app/xtream-tauri/data-sources/pwa-xtream-data-source.ts @@ -14,6 +14,7 @@ import { XtreamContentItem, XtreamPlaylistData, } from './xtream-data-source.interface'; +import { createLogger } from '../../shared/utils/logger'; /** * LocalStorage keys for PWA persistence @@ -33,6 +34,7 @@ const STORAGE_KEYS = { @Injectable({ providedIn: 'root' }) export class PwaXtreamDataSource implements IXtreamDataSource { private readonly apiService = inject(XtreamApiService); + private readonly logger = createLogger('PwaXtreamDataSource'); // In-memory cache for the current session private categoryCache = new Map(); @@ -151,7 +153,7 @@ export class PwaXtreamDataSource implements IXtreamDataSource { hidden: boolean ): Promise { // Category visibility is not supported in PWA mode - console.warn('Category visibility not supported in PWA mode'); + this.logger.warn('Category visibility not supported in PWA mode'); } // ========================================================================= diff --git a/apps/web/src/app/xtream-tauri/recently-viewed/recently-viewed.component.ts b/apps/web/src/app/xtream-tauri/recently-viewed/recently-viewed.component.ts index 8bdbc4fc0..f91b302f9 100644 --- a/apps/web/src/app/xtream-tauri/recently-viewed/recently-viewed.component.ts +++ b/apps/web/src/app/xtream-tauri/recently-viewed/recently-viewed.component.ts @@ -7,6 +7,7 @@ import { ActivatedRoute, Router } from '@angular/router'; import groupBy from 'lodash/groupBy'; import { ContentCardComponent } from '../../shared/components/content-card/content-card.component'; import { XtreamStore } from '../stores/xtream.store'; +import { createLogger } from '../../shared/utils/logger'; @Component({ selector: 'app-recently-viewed', @@ -26,6 +27,7 @@ export class RecentlyViewedComponent { private activatedRoute = inject(ActivatedRoute); private router = inject(Router); private dialogData = inject(MAT_DIALOG_DATA, { optional: true }); + private readonly logger = createLogger('XtreamRecentlyViewed'); readonly isGlobal = this.dialogData?.isGlobal ?? false; readonly recentItems = computed(() => @@ -51,7 +53,7 @@ export class RecentlyViewedComponent { try { await this.xtreamStore.loadGlobalRecentItems(); } catch (error) { - console.error('Error loading global items:', error); + this.logger.error('Error loading global items', error); } } diff --git a/apps/web/src/app/xtream-tauri/search-results/search-results.component.ts b/apps/web/src/app/xtream-tauri/search-results/search-results.component.ts index 84e6df502..a58cadc0f 100644 --- a/apps/web/src/app/xtream-tauri/search-results/search-results.component.ts +++ b/apps/web/src/app/xtream-tauri/search-results/search-results.component.ts @@ -28,6 +28,7 @@ import { ContentCardComponent } from '../../shared/components/content-card/conte import { SearchLayoutComponent } from '../../shared/components/search-layout/search-layout.component'; import { XtreamStore } from '../stores/xtream.store'; import { SearchFilters } from '../stores/features/with-search.feature'; +import { createLogger } from '../../shared/utils/logger'; interface SearchResultsData { isGlobalSearch: boolean; @@ -55,6 +56,7 @@ export class SearchResultsComponent implements AfterViewInit { readonly router = inject(Router); readonly activatedRoute = inject(ActivatedRoute); readonly databaseService = inject(DatabaseService); + private readonly logger = createLogger('XtreamSearchResults'); /** Search term from store */ readonly searchTerm = this.xtreamStore.searchTerm; @@ -182,7 +184,7 @@ export class SearchResultsComponent implements AfterViewInit { this.xtreamStore.setIsSearching(false); } } catch (error) { - console.error('Error in global search:', error); + this.logger.error('Error in global search', error); this.xtreamStore.resetSearchResults(); } } diff --git a/apps/web/src/app/xtream-tauri/season-container/season-container.component.ts b/apps/web/src/app/xtream-tauri/season-container/season-container.component.ts index fe1ed9085..84bba4cc5 100644 --- a/apps/web/src/app/xtream-tauri/season-container/season-container.component.ts +++ b/apps/web/src/app/xtream-tauri/season-container/season-container.component.ts @@ -12,6 +12,7 @@ import { StalkerStore } from '../../stalker/stalker.store'; import { ProgressCapsuleComponent } from '../shared/progress-capsule/progress-capsule.component'; import { WatchedBadgeComponent } from '../shared/watched-badge/watched-badge.component'; import { DownloadsService } from '../../services/downloads.service'; +import { createLogger } from '../../shared/utils/logger'; type EpisodeViewMode = 'grid' | 'list'; const EPISODE_VIEW_MODE_KEY = 'iptvnator_episode_view_mode'; @@ -36,6 +37,7 @@ export class SeasonContainerComponent implements OnInit { private readonly xtreamStore = inject(XtreamStore); private readonly stalkerStore = inject(StalkerStore); private readonly downloadsService = inject(DownloadsService); + private readonly logger = createLogger('SeasonContainer'); readonly seasons = input.required>(); readonly seriesId = input.required(); @@ -177,7 +179,7 @@ export class SeasonContainerComponent implements OnInit { event.stopPropagation(); const playlistId = this.getPlaylistId(episode); if (!playlistId) { - console.warn('[SeasonContainer] Cannot toggle watched: no playlist ID'); + this.logger.warn('Cannot toggle watched: no playlist ID'); return; } @@ -218,9 +220,11 @@ export class SeasonContainerComponent implements OnInit { const contentId = this.getEpisodeContentId(episode); const inProgress = this.xtreamStore.isInProgress(contentId, 'episode'); if (inProgress) { - console.log( - `[SeasonContainer] Episode ${episode.title} (contentId=${contentId}, originalId=${(episode as any).originalId}) is IN PROGRESS` - ); + this.logger.debug('Episode in progress', { + title: episode.title, + contentId, + originalId: (episode as any).originalId, + }); } return inProgress; } @@ -354,11 +358,11 @@ export class SeasonContainerComponent implements OnInit { episode.episode_num // series param for episode number ); if (!url) { - console.error('[SeasonContainer] Failed to resolve Stalker stream URL'); + this.logger.error('Failed to resolve Stalker stream URL'); return; } } catch (error) { - console.error('[SeasonContainer] Error resolving Stalker stream URL:', error); + this.logger.error('Error resolving Stalker stream URL', error); return; } diff --git a/apps/web/src/app/xtream-tauri/services/epg-queue.service.ts b/apps/web/src/app/xtream-tauri/services/epg-queue.service.ts index 41a23327e..8909d1873 100644 --- a/apps/web/src/app/xtream-tauri/services/epg-queue.service.ts +++ b/apps/web/src/app/xtream-tauri/services/epg-queue.service.ts @@ -2,6 +2,7 @@ import { inject, Injectable, OnDestroy } from '@angular/core'; import { Subject } from 'rxjs'; import { EpgItem } from 'shared-interfaces'; import { XtreamApiService, XtreamCredentials } from './xtream-api.service'; +import { createLogger } from '../../shared/utils/logger'; interface CacheEntry { data: EpgItem[]; @@ -17,6 +18,7 @@ interface CacheEntry { @Injectable({ providedIn: 'root' }) export class EpgQueueService implements OnDestroy { private readonly apiService = inject(XtreamApiService); + private readonly logger = createLogger('EpgQueueService'); private readonly cache = new Map(); private queue: number[] = []; @@ -115,8 +117,8 @@ export class EpgQueueService implements OnDestroy { }); this.epgResult$.next({ streamId, items }); } catch (error) { - console.error( - `EpgQueueService: failed to load EPG for stream ${streamId}:`, + this.logger.error( + `Failed to load EPG for stream ${streamId}`, error ); } finally { diff --git a/apps/web/src/app/xtream-tauri/stores/features/with-content.feature.ts b/apps/web/src/app/xtream-tauri/stores/features/with-content.feature.ts index 97d2981f4..0959b8c9c 100644 --- a/apps/web/src/app/xtream-tauri/stores/features/with-content.feature.ts +++ b/apps/web/src/app/xtream-tauri/stores/features/with-content.feature.ts @@ -18,6 +18,7 @@ import { } from '../../data-sources/xtream-data-source.interface'; import { XtreamCredentials } from '../../services/xtream-api.service'; import { ContentType } from '../../xtream-state'; +import { createLogger } from '../../../shared/utils/logger'; /** * Content state for managing categories and streams @@ -61,6 +62,7 @@ const initialContentState: ContentState = { * - Import progress tracking */ export function withContent() { + const logger = createLogger('withContent'); return signalStoreFeature( withState(initialContentState), @@ -174,7 +176,7 @@ export function withContent() { isLoadingCategories: false, }); } catch (error) { - console.error('Error fetching categories:', error); + logger.error('Error fetching categories', error); patchState(store, { isLoadingCategories: false }); } }, @@ -234,7 +236,7 @@ export function withContent() { isLoadingContent: false, }); } catch (error) { - console.error('Error fetching content:', error); + logger.error('Error fetching content', error); patchState(store, { isLoadingContent: false }); } }, @@ -275,10 +277,7 @@ export function withContent() { ); localStorage.removeItem(restoreKey); } catch (err) { - console.error( - 'Error restoring user data:', - err - ); + logger.error('Error restoring user data', err); } } } finally { @@ -318,7 +317,7 @@ export function withContent() { serialCategories: series, }); } catch (error) { - console.error('Error reloading categories:', error); + logger.error('Error reloading categories', error); } }, diff --git a/apps/web/src/app/xtream-tauri/stores/features/with-epg.feature.ts b/apps/web/src/app/xtream-tauri/stores/features/with-epg.feature.ts index acebcb1df..f34272f0e 100644 --- a/apps/web/src/app/xtream-tauri/stores/features/with-epg.feature.ts +++ b/apps/web/src/app/xtream-tauri/stores/features/with-epg.feature.ts @@ -10,6 +10,7 @@ import { XtreamApiService, XtreamCredentials, } from '../../services/xtream-api.service'; +import { createLogger } from '../../../shared/utils/logger'; /** * EPG state for managing Electronic Program Guide data @@ -34,6 +35,7 @@ const initialEpgState: EpgState = { * - Loading channel EPG for preview */ export function withEpg() { + const logger = createLogger('withEpg'); return signalStoreFeature( withState(initialEpgState), @@ -94,7 +96,7 @@ export function withEpg() { return epgItems; } catch (error) { - console.error('Error loading EPG:', error); + logger.error('Error loading EPG', error); patchState(store, { epgItems: [], isLoadingEpg: false, @@ -119,7 +121,7 @@ export function withEpg() { 1 ); } catch (error) { - console.error('Error loading channel EPG:', error); + logger.error('Error loading channel EPG', error); return []; } }, diff --git a/apps/web/src/app/xtream-tauri/stores/features/with-portal.feature.ts b/apps/web/src/app/xtream-tauri/stores/features/with-portal.feature.ts index 032f35973..e41b6bda7 100644 --- a/apps/web/src/app/xtream-tauri/stores/features/with-portal.feature.ts +++ b/apps/web/src/app/xtream-tauri/stores/features/with-portal.feature.ts @@ -17,6 +17,7 @@ import { XtreamCredentials, } from '../../services/xtream-api.service'; import { PortalStatusType } from '../../xtream-state'; +import { createLogger } from '../../../shared/utils/logger'; /** * Portal state for managing playlist and portal status @@ -44,6 +45,7 @@ const initialPortalState: PortalState = { * - Checking portal status (active, inactive, expired, unavailable) */ export function withPortal() { + const logger = createLogger('withPortal'); return signalStoreFeature( withState(initialPortalState), @@ -98,7 +100,7 @@ export function withPortal() { } } } catch (error) { - console.error('Error fetching playlist:', error); + logger.error('Error fetching playlist', error); } }, @@ -140,7 +142,7 @@ export function withPortal() { patchState(store, { portalStatus: 'inactive' }); } } catch (error) { - console.error('Error checking portal status:', error); + logger.error('Error checking portal status', error); patchState(store, { portalStatus: 'unavailable' }); } }, diff --git a/apps/web/src/app/xtream-tauri/stores/features/with-search.feature.ts b/apps/web/src/app/xtream-tauri/stores/features/with-search.feature.ts index 2d9b1d4dc..5493fc8be 100644 --- a/apps/web/src/app/xtream-tauri/stores/features/with-search.feature.ts +++ b/apps/web/src/app/xtream-tauri/stores/features/with-search.feature.ts @@ -10,6 +10,7 @@ import { XTREAM_DATA_SOURCE, XtreamContentItem, } from '../../data-sources/xtream-data-source.interface'; +import { createLogger } from '../../../shared/utils/logger'; /** * Search filters configuration @@ -58,6 +59,7 @@ const initialSearchState: SearchState = { * - Global search results from external sources */ export function withSearch() { + const logger = createLogger('withSearch'); return signalStoreFeature( withState(initialSearchState), @@ -99,7 +101,7 @@ export function withSearch() { return results; } catch (error) { - console.error('Error searching content:', error); + logger.error('Error searching content', error); patchState(store, { searchResults: [], isSearching: false, diff --git a/apps/web/src/app/xtream-tauri/stores/xtream.store.ts b/apps/web/src/app/xtream-tauri/stores/xtream.store.ts index 5516500e5..e00d46971 100644 --- a/apps/web/src/app/xtream-tauri/stores/xtream.store.ts +++ b/apps/web/src/app/xtream-tauri/stores/xtream.store.ts @@ -28,6 +28,7 @@ import { withPlayer, withPlaybackPositions, } from './features'; +import { createLogger } from '../../shared/utils/logger'; /** * XtreamStore - Facade composing all feature stores. @@ -80,6 +81,7 @@ export const XtreamStore = signalStore( withMethods((store) => { const xtreamApiService = inject(XtreamApiService); const ngrxStore = inject(Store); + const logger = createLogger('XtreamStore'); const searchContent = (store as any) .searchContent as (term: string, types: string[], excludeHidden?: boolean) => Promise; @@ -143,7 +145,7 @@ export const XtreamStore = signalStore( stream_id: params.vodId, }); }).catch((error: unknown) => { - console.error('Error fetching VOD details:', error); + logger.error('Error fetching VOD details', error); store.setDetailsError( error instanceof Error ? error.message : 'Unknown error' ); @@ -175,7 +177,7 @@ export const XtreamStore = signalStore( series_id: params.serialId, }); }).catch((error: unknown) => { - console.error('Error fetching series details:', error); + logger.error('Error fetching series details', error); store.setDetailsError( error instanceof Error ? error.message : 'Unknown error' ); @@ -192,11 +194,11 @@ export const XtreamStore = signalStore( }, addToFavorites(item: unknown): void { - console.log('Legacy addToFavorites called', item); + logger.debug('Legacy addToFavorites called', item); }, removeFromFavorites(favoriteId: string): void { - console.log('Legacy removeFromFavorites called', favoriteId); + logger.debug('Legacy removeFromFavorites called', favoriteId); }, // Alias methods for backward compatibility diff --git a/apps/web/src/app/xtream-tauri/vod-details/vod-details-route.component.ts b/apps/web/src/app/xtream-tauri/vod-details/vod-details-route.component.ts index dedcd17f4..10058bef8 100644 --- a/apps/web/src/app/xtream-tauri/vod-details/vod-details-route.component.ts +++ b/apps/web/src/app/xtream-tauri/vod-details/vod-details-route.component.ts @@ -10,6 +10,7 @@ import { DownloadsService } from '../../services/downloads.service'; import { SettingsStore } from '../../services/settings-store.service'; import { XtreamStore } from '../stores/xtream.store'; import { SafePipe } from '@iptvnator/pipes'; +import { createLogger } from '../../shared/utils/logger'; /** * Route-based VOD details container for Xtream. @@ -39,6 +40,7 @@ export class VodDetailsRouteComponent implements OnInit, OnDestroy { private route = inject(ActivatedRoute); private readonly xtreamStore = inject(XtreamStore); private readonly downloadsService = inject(DownloadsService); + private readonly logger = createLogger('VodDetailsRoute'); readonly theme = this.settingsStore.theme; readonly isElectron = this.downloadsService.isAvailable; @@ -51,9 +53,10 @@ export class VodDetailsRouteComponent implements OnInit, OnDestroy { readonly hasPlaybackPosition = computed(() => { const vodId = this.route.snapshot.params.vodId; const inProgress = this.xtreamStore.isInProgress(Number(vodId), 'vod'); - console.log( - `[VodDetails] hasPlaybackPosition check: vodId=${vodId}, inProgress=${inProgress}` - ); + this.logger.debug('hasPlaybackPosition check', { + vodId, + inProgress, + }); return inProgress; }); @@ -106,7 +109,7 @@ export class VodDetailsRouteComponent implements OnInit, OnDestroy { vodItem.movie_data?.stream_id || (vodItem as any).stream_id ); - console.log(`[VodDetails] playVod: Resolved ID=${id} for item`, vodItem); + this.logger.debug('playVod resolved ID', { id, vodItem }); const contentInfo = { playlistId: this.xtreamStore.currentPlaylist().id, diff --git a/apps/web/src/app/xtream-tauri/with-favorites.feature.ts b/apps/web/src/app/xtream-tauri/with-favorites.feature.ts index 2b6e21dae..f4ee5bd07 100644 --- a/apps/web/src/app/xtream-tauri/with-favorites.feature.ts +++ b/apps/web/src/app/xtream-tauri/with-favorites.feature.ts @@ -7,8 +7,10 @@ import { } from '@ngrx/signals'; import { DatabaseService } from 'services'; import { FavoritesService } from './services/favorites.service'; +import { createLogger } from '../shared/utils/logger'; export const withFavorites = function () { + const logger = createLogger('withFavorites'); return signalStoreFeature( withState({ isFavorite: false, @@ -30,8 +32,8 @@ export const withFavorites = function () { playlistId ); if (!content) { - console.error( - 'Content not found for xtream ID:', + logger.error( + 'Content not found for xtream ID', xtreamId ); return false; diff --git a/apps/web/src/app/xtream-tauri/with-recent-items.ts b/apps/web/src/app/xtream-tauri/with-recent-items.ts index 284568b91..68753ad31 100644 --- a/apps/web/src/app/xtream-tauri/with-recent-items.ts +++ b/apps/web/src/app/xtream-tauri/with-recent-items.ts @@ -8,6 +8,7 @@ import { import { rxMethod } from '@ngrx/signals/rxjs-interop'; import { pipe, switchMap, tap } from 'rxjs'; import { DatabaseService } from 'services'; +import { createLogger } from '../shared/utils/logger'; export interface RecentlyViewedItem { id: number; @@ -22,6 +23,7 @@ export interface RecentlyViewedItem { } export const withRecentItems = function () { + const logger = createLogger('withRecentItems'); return signalStoreFeature( withState({ recentItems: [], @@ -110,7 +112,7 @@ export const withRecentItems = function () { recentItems: items || [], }); } catch (error) { - console.error('Error loading global recent items:', error); + logger.error('Error loading global recent items', error); patchState(store, { recentItems: [] }); } }, @@ -119,10 +121,7 @@ export const withRecentItems = function () { await dbService.clearGlobalRecentlyViewed(); patchState(store, { recentItems: [] }); } catch (error) { - console.error( - 'Error clearing global recently viewed:', - error - ); + logger.error('Error clearing global recently viewed', error); } }, }))