mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-05-11 04:21:42 +00:00
downloads notif fix
This commit is contained in:
parent
2494d45e8f
commit
8d918cdf5e
2 changed files with 81 additions and 61 deletions
|
|
@ -56,7 +56,9 @@ class NotificationService {
|
||||||
private appStateSubscription: any = null;
|
private appStateSubscription: any = null;
|
||||||
private lastSyncTime: number = 0;
|
private lastSyncTime: number = 0;
|
||||||
private readonly MIN_SYNC_INTERVAL = 5 * 60 * 1000; // 5 minutes minimum between syncs
|
private readonly MIN_SYNC_INTERVAL = 5 * 60 * 1000; // 5 minutes minimum between syncs
|
||||||
|
// Download notification tracking - stores progress value (50) when notified
|
||||||
|
private lastDownloadNotificationTime: Map<string, number> = new Map();
|
||||||
|
|
||||||
private constructor() {
|
private constructor() {
|
||||||
// Initialize notifications
|
// Initialize notifications
|
||||||
this.configureNotifications();
|
this.configureNotifications();
|
||||||
|
|
@ -88,7 +90,7 @@ class NotificationService {
|
||||||
|
|
||||||
// Request permissions if needed
|
// Request permissions if needed
|
||||||
const { status: existingStatus } = await Notifications.getPermissionsAsync();
|
const { status: existingStatus } = await Notifications.getPermissionsAsync();
|
||||||
|
|
||||||
if (existingStatus !== 'granted') {
|
if (existingStatus !== 'granted') {
|
||||||
const { status } = await Notifications.requestPermissionsAsync();
|
const { status } = await Notifications.requestPermissionsAsync();
|
||||||
if (status !== 'granted') {
|
if (status !== 'granted') {
|
||||||
|
|
@ -102,7 +104,7 @@ class NotificationService {
|
||||||
private async loadSettings(): Promise<void> {
|
private async loadSettings(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const storedSettings = await mmkvStorage.getItem(NOTIFICATION_SETTINGS_KEY);
|
const storedSettings = await mmkvStorage.getItem(NOTIFICATION_SETTINGS_KEY);
|
||||||
|
|
||||||
if (storedSettings) {
|
if (storedSettings) {
|
||||||
this.settings = { ...DEFAULT_NOTIFICATION_SETTINGS, ...JSON.parse(storedSettings) };
|
this.settings = { ...DEFAULT_NOTIFICATION_SETTINGS, ...JSON.parse(storedSettings) };
|
||||||
}
|
}
|
||||||
|
|
@ -122,7 +124,7 @@ class NotificationService {
|
||||||
private async loadScheduledNotifications(): Promise<void> {
|
private async loadScheduledNotifications(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const storedNotifications = await mmkvStorage.getItem(NOTIFICATION_STORAGE_KEY);
|
const storedNotifications = await mmkvStorage.getItem(NOTIFICATION_STORAGE_KEY);
|
||||||
|
|
||||||
if (storedNotifications) {
|
if (storedNotifications) {
|
||||||
this.scheduledNotifications = JSON.parse(storedNotifications);
|
this.scheduledNotifications = JSON.parse(storedNotifications);
|
||||||
}
|
}
|
||||||
|
|
@ -156,9 +158,9 @@ class NotificationService {
|
||||||
|
|
||||||
// Check if notification already exists for this episode
|
// Check if notification already exists for this episode
|
||||||
const existingNotification = this.scheduledNotifications.find(
|
const existingNotification = this.scheduledNotifications.find(
|
||||||
notification => notification.seriesId === item.seriesId &&
|
notification => notification.seriesId === item.seriesId &&
|
||||||
notification.season === item.season &&
|
notification.season === item.season &&
|
||||||
notification.episode === item.episode
|
notification.episode === item.episode
|
||||||
);
|
);
|
||||||
if (existingNotification) {
|
if (existingNotification) {
|
||||||
return null; // Don't schedule duplicate notifications
|
return null; // Don't schedule duplicate notifications
|
||||||
|
|
@ -166,22 +168,22 @@ class NotificationService {
|
||||||
|
|
||||||
const releaseDate = parseISO(item.releaseDate);
|
const releaseDate = parseISO(item.releaseDate);
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
|
|
||||||
// If release date has already passed, don't schedule
|
// If release date has already passed, don't schedule
|
||||||
if (releaseDate < now) {
|
if (releaseDate < now) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Calculate notification time (default to 24h before air time)
|
// Calculate notification time (default to 24h before air time)
|
||||||
const notificationTime = new Date(releaseDate);
|
const notificationTime = new Date(releaseDate);
|
||||||
notificationTime.setHours(notificationTime.getHours() - this.settings.timeBeforeAiring);
|
notificationTime.setHours(notificationTime.getHours() - this.settings.timeBeforeAiring);
|
||||||
|
|
||||||
// If notification time has already passed, don't schedule the notification
|
// If notification time has already passed, don't schedule the notification
|
||||||
if (notificationTime < now) {
|
if (notificationTime < now) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Schedule the notification
|
// Schedule the notification
|
||||||
const notificationId = await Notifications.scheduleNotificationAsync({
|
const notificationId = await Notifications.scheduleNotificationAsync({
|
||||||
content: {
|
content: {
|
||||||
|
|
@ -197,16 +199,16 @@ class NotificationService {
|
||||||
type: SchedulableTriggerInputTypes.DATE,
|
type: SchedulableTriggerInputTypes.DATE,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add to scheduled notifications
|
// Add to scheduled notifications
|
||||||
this.scheduledNotifications.push({
|
this.scheduledNotifications.push({
|
||||||
...item,
|
...item,
|
||||||
notified: false,
|
notified: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Save to storage
|
// Save to storage
|
||||||
await this.saveScheduledNotifications();
|
await this.saveScheduledNotifications();
|
||||||
|
|
||||||
return notificationId;
|
return notificationId;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('Error scheduling notification:', error);
|
logger.error('Error scheduling notification:', error);
|
||||||
|
|
@ -218,16 +220,16 @@ class NotificationService {
|
||||||
if (!this.settings.enabled) {
|
if (!this.settings.enabled) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
let scheduledCount = 0;
|
let scheduledCount = 0;
|
||||||
|
|
||||||
for (const item of items) {
|
for (const item of items) {
|
||||||
const notificationId = await this.scheduleEpisodeNotification(item);
|
const notificationId = await this.scheduleEpisodeNotification(item);
|
||||||
if (notificationId) {
|
if (notificationId) {
|
||||||
scheduledCount++;
|
scheduledCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return scheduledCount;
|
return scheduledCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -235,12 +237,12 @@ class NotificationService {
|
||||||
try {
|
try {
|
||||||
// Cancel with Expo
|
// Cancel with Expo
|
||||||
await Notifications.cancelScheduledNotificationAsync(id);
|
await Notifications.cancelScheduledNotificationAsync(id);
|
||||||
|
|
||||||
// Remove from our tracked notifications
|
// Remove from our tracked notifications
|
||||||
this.scheduledNotifications = this.scheduledNotifications.filter(
|
this.scheduledNotifications = this.scheduledNotifications.filter(
|
||||||
notification => notification.id !== id
|
notification => notification.id !== id
|
||||||
);
|
);
|
||||||
|
|
||||||
// Save updated list
|
// Save updated list
|
||||||
await this.saveScheduledNotifications();
|
await this.saveScheduledNotifications();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
@ -268,10 +270,10 @@ class NotificationService {
|
||||||
// Subscribe to library updates from catalog service
|
// Subscribe to library updates from catalog service
|
||||||
this.librarySubscription = catalogService.subscribeToLibraryUpdates(async (libraryItems) => {
|
this.librarySubscription = catalogService.subscribeToLibraryUpdates(async (libraryItems) => {
|
||||||
if (!this.settings.enabled) return;
|
if (!this.settings.enabled) return;
|
||||||
|
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
const timeSinceLastSync = now - this.lastSyncTime;
|
const timeSinceLastSync = now - this.lastSyncTime;
|
||||||
|
|
||||||
// Only sync if enough time has passed since last sync
|
// Only sync if enough time has passed since last sync
|
||||||
if (timeSinceLastSync >= this.MIN_SYNC_INTERVAL) {
|
if (timeSinceLastSync >= this.MIN_SYNC_INTERVAL) {
|
||||||
// Reduced logging verbosity
|
// Reduced logging verbosity
|
||||||
|
|
@ -309,7 +311,7 @@ class NotificationService {
|
||||||
if (nextAppState === 'active' && this.settings.enabled) {
|
if (nextAppState === 'active' && this.settings.enabled) {
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
const timeSinceLastSync = now - this.lastSyncTime;
|
const timeSinceLastSync = now - this.lastSyncTime;
|
||||||
|
|
||||||
// Only sync if enough time has passed since last sync
|
// Only sync if enough time has passed since last sync
|
||||||
if (timeSinceLastSync >= this.MIN_SYNC_INTERVAL) {
|
if (timeSinceLastSync >= this.MIN_SYNC_INTERVAL) {
|
||||||
// App came to foreground, sync notifications
|
// App came to foreground, sync notifications
|
||||||
|
|
@ -327,6 +329,21 @@ class NotificationService {
|
||||||
try {
|
try {
|
||||||
if (!this.settings.enabled) return;
|
if (!this.settings.enabled) return;
|
||||||
if (AppState.currentState === 'active') return;
|
if (AppState.currentState === 'active') return;
|
||||||
|
|
||||||
|
// Only notify at 50% progress
|
||||||
|
if (progress < 50) {
|
||||||
|
return; // Skip notifications before 50%
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we've already notified at 50% for this download
|
||||||
|
const lastNotifiedProgress = this.lastDownloadNotificationTime.get(title) || 0;
|
||||||
|
if (lastNotifiedProgress >= 50) {
|
||||||
|
return; // Already notified at 50%, don't notify again
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark that we've notified at 50%
|
||||||
|
this.lastDownloadNotificationTime.set(title, 50);
|
||||||
|
|
||||||
const downloadedMb = Math.floor((downloadedBytes || 0) / (1024 * 1024));
|
const downloadedMb = Math.floor((downloadedBytes || 0) / (1024 * 1024));
|
||||||
const totalMb = totalBytes ? Math.floor(totalBytes / (1024 * 1024)) : undefined;
|
const totalMb = totalBytes ? Math.floor(totalBytes / (1024 * 1024)) : undefined;
|
||||||
const body = `${progress}%` + (totalMb !== undefined ? ` • ${downloadedMb}MB / ${totalMb}MB` : '');
|
const body = `${progress}%` + (totalMb !== undefined ? ` • ${downloadedMb}MB / ${totalMb}MB` : '');
|
||||||
|
|
@ -348,6 +365,7 @@ class NotificationService {
|
||||||
try {
|
try {
|
||||||
if (!this.settings.enabled) return;
|
if (!this.settings.enabled) return;
|
||||||
if (AppState.currentState === 'active') return;
|
if (AppState.currentState === 'active') return;
|
||||||
|
|
||||||
await Notifications.scheduleNotificationAsync({
|
await Notifications.scheduleNotificationAsync({
|
||||||
content: {
|
content: {
|
||||||
title: 'Download complete',
|
title: 'Download complete',
|
||||||
|
|
@ -356,6 +374,9 @@ class NotificationService {
|
||||||
},
|
},
|
||||||
trigger: null,
|
trigger: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Clean up tracking entry after completion to prevent memory leaks
|
||||||
|
this.lastDownloadNotificationTime.delete(title);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('[NotificationService] notifyDownloadComplete error:', error);
|
logger.error('[NotificationService] notifyDownloadComplete error:', error);
|
||||||
}
|
}
|
||||||
|
|
@ -365,14 +386,14 @@ class NotificationService {
|
||||||
private async syncNotificationsForLibrary(libraryItems: any[]): Promise<void> {
|
private async syncNotificationsForLibrary(libraryItems: any[]): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const seriesItems = libraryItems.filter(item => item.type === 'series');
|
const seriesItems = libraryItems.filter(item => item.type === 'series');
|
||||||
|
|
||||||
// Limit series to prevent memory overflow during notifications sync
|
// Limit series to prevent memory overflow during notifications sync
|
||||||
const limitedSeries = memoryManager.limitArraySize(seriesItems, 50);
|
const limitedSeries = memoryManager.limitArraySize(seriesItems, 50);
|
||||||
|
|
||||||
if (limitedSeries.length < seriesItems.length) {
|
if (limitedSeries.length < seriesItems.length) {
|
||||||
logger.warn(`[NotificationService] Limited series sync from ${seriesItems.length} to ${limitedSeries.length} to prevent memory issues`);
|
logger.warn(`[NotificationService] Limited series sync from ${seriesItems.length} to ${limitedSeries.length} to prevent memory issues`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process in small batches with memory management
|
// Process in small batches with memory management
|
||||||
await memoryManager.processArrayInBatches(
|
await memoryManager.processArrayInBatches(
|
||||||
limitedSeries,
|
limitedSeries,
|
||||||
|
|
@ -386,10 +407,10 @@ class NotificationService {
|
||||||
3, // Very small batch size to prevent memory spikes
|
3, // Very small batch size to prevent memory spikes
|
||||||
800 // Longer delay to prevent API overwhelming and reduce heating
|
800 // Longer delay to prevent API overwhelming and reduce heating
|
||||||
);
|
);
|
||||||
|
|
||||||
// Force cleanup after processing
|
// Force cleanup after processing
|
||||||
memoryManager.forceGarbageCollection();
|
memoryManager.forceGarbageCollection();
|
||||||
|
|
||||||
// Reduced logging verbosity
|
// Reduced logging verbosity
|
||||||
// logger.log(`[NotificationService] Synced notifications for ${limitedSeries.length} series from library`);
|
// logger.log(`[NotificationService] Synced notifications for ${limitedSeries.length} series from library`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
@ -402,20 +423,20 @@ class NotificationService {
|
||||||
try {
|
try {
|
||||||
// Update last sync time at the start
|
// Update last sync time at the start
|
||||||
this.lastSyncTime = Date.now();
|
this.lastSyncTime = Date.now();
|
||||||
|
|
||||||
// Reduced logging verbosity
|
// Reduced logging verbosity
|
||||||
// logger.log('[NotificationService] Starting comprehensive background sync');
|
// logger.log('[NotificationService] Starting comprehensive background sync');
|
||||||
|
|
||||||
// Get library items
|
// Get library items
|
||||||
const libraryItems = await catalogService.getLibraryItems();
|
const libraryItems = await catalogService.getLibraryItems();
|
||||||
await this.syncNotificationsForLibrary(libraryItems);
|
await this.syncNotificationsForLibrary(libraryItems);
|
||||||
|
|
||||||
// Sync Trakt items if authenticated
|
// Sync Trakt items if authenticated
|
||||||
await this.syncTraktNotifications();
|
await this.syncTraktNotifications();
|
||||||
|
|
||||||
// Clean up old notifications
|
// Clean up old notifications
|
||||||
await this.cleanupOldNotifications();
|
await this.cleanupOldNotifications();
|
||||||
|
|
||||||
// Reduced logging verbosity
|
// Reduced logging verbosity
|
||||||
// logger.log('[NotificationService] Background sync completed');
|
// logger.log('[NotificationService] Background sync completed');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
@ -435,7 +456,7 @@ class NotificationService {
|
||||||
|
|
||||||
// Reduced logging verbosity
|
// Reduced logging verbosity
|
||||||
// logger.log('[NotificationService] Syncing comprehensive Trakt notifications');
|
// logger.log('[NotificationService] Syncing comprehensive Trakt notifications');
|
||||||
|
|
||||||
// Get all Trakt data sources (same as calendar screen uses)
|
// Get all Trakt data sources (same as calendar screen uses)
|
||||||
const [watchlistShows, continueWatching, watchedShows, collectionShows] = await Promise.all([
|
const [watchlistShows, continueWatching, watchedShows, collectionShows] = await Promise.all([
|
||||||
traktService.getWatchlistShows(),
|
traktService.getWatchlistShows(),
|
||||||
|
|
@ -446,7 +467,7 @@ class NotificationService {
|
||||||
|
|
||||||
// Combine and deduplicate shows using the same logic as calendar screen
|
// Combine and deduplicate shows using the same logic as calendar screen
|
||||||
const allTraktShows = new Map();
|
const allTraktShows = new Map();
|
||||||
|
|
||||||
// Add watchlist shows
|
// Add watchlist shows
|
||||||
if (watchlistShows) {
|
if (watchlistShows) {
|
||||||
watchlistShows.forEach((item: any) => {
|
watchlistShows.forEach((item: any) => {
|
||||||
|
|
@ -523,11 +544,11 @@ class NotificationService {
|
||||||
// Sync notifications for each Trakt show using memory-efficient batching
|
// Sync notifications for each Trakt show using memory-efficient batching
|
||||||
const traktShows = Array.from(allTraktShows.values());
|
const traktShows = Array.from(allTraktShows.values());
|
||||||
const limitedTraktShows = memoryManager.limitArraySize(traktShows, 30); // Limit Trakt shows
|
const limitedTraktShows = memoryManager.limitArraySize(traktShows, 30); // Limit Trakt shows
|
||||||
|
|
||||||
if (limitedTraktShows.length < traktShows.length) {
|
if (limitedTraktShows.length < traktShows.length) {
|
||||||
logger.warn(`[NotificationService] Limited Trakt shows sync from ${traktShows.length} to ${limitedTraktShows.length} to prevent memory issues`);
|
logger.warn(`[NotificationService] Limited Trakt shows sync from ${traktShows.length} to ${limitedTraktShows.length} to prevent memory issues`);
|
||||||
}
|
}
|
||||||
|
|
||||||
let syncedCount = 0;
|
let syncedCount = 0;
|
||||||
await memoryManager.processArrayInBatches(
|
await memoryManager.processArrayInBatches(
|
||||||
limitedTraktShows,
|
limitedTraktShows,
|
||||||
|
|
@ -542,7 +563,7 @@ class NotificationService {
|
||||||
2, // Even smaller batch size for Trakt shows
|
2, // Even smaller batch size for Trakt shows
|
||||||
1000 // Longer delay to prevent API rate limiting
|
1000 // Longer delay to prevent API rate limiting
|
||||||
);
|
);
|
||||||
|
|
||||||
// Clear Trakt shows array to free memory
|
// Clear Trakt shows array to free memory
|
||||||
memoryManager.clearObjects(traktShows, limitedTraktShows);
|
memoryManager.clearObjects(traktShows, limitedTraktShows);
|
||||||
|
|
||||||
|
|
@ -558,23 +579,23 @@ class NotificationService {
|
||||||
try {
|
try {
|
||||||
// Check memory pressure before processing
|
// Check memory pressure before processing
|
||||||
memoryManager.checkMemoryPressure();
|
memoryManager.checkMemoryPressure();
|
||||||
|
|
||||||
// Use the new memory-efficient method to fetch only upcoming episodes
|
// Use the new memory-efficient method to fetch only upcoming episodes
|
||||||
const episodeData = await stremioService.getUpcomingEpisodes('series', seriesId, {
|
const episodeData = await stremioService.getUpcomingEpisodes('series', seriesId, {
|
||||||
daysBack: 7, // 1 week back for notifications
|
daysBack: 7, // 1 week back for notifications
|
||||||
daysAhead: 28, // 4 weeks ahead for notifications
|
daysAhead: 28, // 4 weeks ahead for notifications
|
||||||
maxEpisodes: 10, // Limit to 10 episodes per series for notifications
|
maxEpisodes: 10, // Limit to 10 episodes per series for notifications
|
||||||
});
|
});
|
||||||
|
|
||||||
let upcomingEpisodes: any[] = [];
|
let upcomingEpisodes: any[] = [];
|
||||||
let metadata: any = null;
|
let metadata: any = null;
|
||||||
|
|
||||||
if (episodeData && episodeData.episodes.length > 0) {
|
if (episodeData && episodeData.episodes.length > 0) {
|
||||||
metadata = {
|
metadata = {
|
||||||
name: episodeData.seriesName,
|
name: episodeData.seriesName,
|
||||||
poster: episodeData.poster,
|
poster: episodeData.poster,
|
||||||
};
|
};
|
||||||
|
|
||||||
upcomingEpisodes = episodeData.episodes
|
upcomingEpisodes = episodeData.episodes
|
||||||
.filter(video => {
|
.filter(video => {
|
||||||
if (!video.released) return false;
|
if (!video.released) return false;
|
||||||
|
|
@ -612,7 +633,7 @@ class NotificationService {
|
||||||
// Get upcoming episodes from TMDB
|
// Get upcoming episodes from TMDB
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const fourWeeksLater = addDays(now, 28);
|
const fourWeeksLater = addDays(now, 28);
|
||||||
|
|
||||||
// Check current and next seasons for upcoming episodes
|
// Check current and next seasons for upcoming episodes
|
||||||
for (let seasonNum = tmdbDetails.number_of_seasons; seasonNum >= Math.max(1, tmdbDetails.number_of_seasons - 2); seasonNum--) {
|
for (let seasonNum = tmdbDetails.number_of_seasons; seasonNum >= Math.max(1, tmdbDetails.number_of_seasons - 2); seasonNum--) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -641,11 +662,11 @@ class NotificationService {
|
||||||
logger.warn(`[NotificationService] TMDB fallback failed for ${seriesId}:`, tmdbError);
|
logger.warn(`[NotificationService] TMDB fallback failed for ${seriesId}:`, tmdbError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!metadata) {
|
if (!metadata) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cancel existing notifications for this series
|
// Cancel existing notifications for this series
|
||||||
const existingNotifications = await Notifications.getAllScheduledNotificationsAsync();
|
const existingNotifications = await Notifications.getAllScheduledNotificationsAsync();
|
||||||
for (const notification of existingNotifications) {
|
for (const notification of existingNotifications) {
|
||||||
|
|
@ -653,17 +674,17 @@ class NotificationService {
|
||||||
await Notifications.cancelScheduledNotificationAsync(notification.identifier);
|
await Notifications.cancelScheduledNotificationAsync(notification.identifier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove from our tracked notifications
|
// Remove from our tracked notifications
|
||||||
this.scheduledNotifications = this.scheduledNotifications.filter(
|
this.scheduledNotifications = this.scheduledNotifications.filter(
|
||||||
notification => notification.seriesId !== seriesId
|
notification => notification.seriesId !== seriesId
|
||||||
);
|
);
|
||||||
|
|
||||||
// Schedule new notifications for upcoming episodes with memory limits
|
// Schedule new notifications for upcoming episodes with memory limits
|
||||||
if (upcomingEpisodes.length > 0 && metadata) {
|
if (upcomingEpisodes.length > 0 && metadata) {
|
||||||
// Limit notifications per series to prevent memory overflow
|
// Limit notifications per series to prevent memory overflow
|
||||||
const limitedEpisodes = memoryManager.limitArraySize(upcomingEpisodes, 5);
|
const limitedEpisodes = memoryManager.limitArraySize(upcomingEpisodes, 5);
|
||||||
|
|
||||||
const notificationItems: NotificationItem[] = limitedEpisodes.map(episode => ({
|
const notificationItems: NotificationItem[] = limitedEpisodes.map(episode => ({
|
||||||
id: episode.id,
|
id: episode.id,
|
||||||
seriesId,
|
seriesId,
|
||||||
|
|
@ -675,23 +696,23 @@ class NotificationService {
|
||||||
notified: false,
|
notified: false,
|
||||||
poster: metadata.poster,
|
poster: metadata.poster,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const scheduledCount = await this.scheduleMultipleEpisodeNotifications(notificationItems);
|
const scheduledCount = await this.scheduleMultipleEpisodeNotifications(notificationItems);
|
||||||
|
|
||||||
// Clear notification items array to free memory
|
// Clear notification items array to free memory
|
||||||
memoryManager.clearObjects(notificationItems, upcomingEpisodes);
|
memoryManager.clearObjects(notificationItems, upcomingEpisodes);
|
||||||
|
|
||||||
// Reduced logging verbosity
|
// Reduced logging verbosity
|
||||||
// logger.log(`[NotificationService] Scheduled ${scheduledCount} notifications for ${metadata.name}`);
|
// logger.log(`[NotificationService] Scheduled ${scheduledCount} notifications for ${metadata.name}`);
|
||||||
} else {
|
} else {
|
||||||
// logger.log(`[NotificationService] No upcoming episodes found for ${metadata?.name || seriesId}`);
|
// logger.log(`[NotificationService] No upcoming episodes found for ${metadata?.name || seriesId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear episode data to free memory
|
// Clear episode data to free memory
|
||||||
if (episodeData) {
|
if (episodeData) {
|
||||||
memoryManager.clearObjects(episodeData.episodes);
|
memoryManager.clearObjects(episodeData.episodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`[NotificationService] Error updating notifications for series ${seriesId}:`, error);
|
logger.error(`[NotificationService] Error updating notifications for series ${seriesId}:`, error);
|
||||||
} finally {
|
} finally {
|
||||||
|
|
@ -705,18 +726,18 @@ class NotificationService {
|
||||||
try {
|
try {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const oneDayAgo = new Date(now.getTime() - 24 * 60 * 60 * 1000);
|
const oneDayAgo = new Date(now.getTime() - 24 * 60 * 60 * 1000);
|
||||||
|
|
||||||
// Remove notifications for episodes that have already aired
|
// Remove notifications for episodes that have already aired
|
||||||
const validNotifications = this.scheduledNotifications.filter(notification => {
|
const validNotifications = this.scheduledNotifications.filter(notification => {
|
||||||
const releaseDate = parseISO(notification.releaseDate);
|
const releaseDate = parseISO(notification.releaseDate);
|
||||||
return releaseDate > oneDayAgo;
|
return releaseDate > oneDayAgo;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (validNotifications.length !== this.scheduledNotifications.length) {
|
if (validNotifications.length !== this.scheduledNotifications.length) {
|
||||||
this.scheduledNotifications = validNotifications;
|
this.scheduledNotifications = validNotifications;
|
||||||
await this.saveScheduledNotifications();
|
await this.saveScheduledNotifications();
|
||||||
// Reduced logging verbosity
|
// Reduced logging verbosity
|
||||||
// logger.log(`[NotificationService] Cleaned up ${this.scheduledNotifications.length - validNotifications.length} old notifications`);
|
// logger.log(`[NotificationService] Cleaned up ${this.scheduledNotifications.length - validNotifications.length} old notifications`);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('[NotificationService] Error cleaning up notifications:', error);
|
logger.error('[NotificationService] Error cleaning up notifications:', error);
|
||||||
|
|
@ -734,17 +755,17 @@ class NotificationService {
|
||||||
public getNotificationStats(): { total: number; upcoming: number; thisWeek: number } {
|
public getNotificationStats(): { total: number; upcoming: number; thisWeek: number } {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const oneWeekLater = addDays(now, 7);
|
const oneWeekLater = addDays(now, 7);
|
||||||
|
|
||||||
const upcoming = this.scheduledNotifications.filter(notification => {
|
const upcoming = this.scheduledNotifications.filter(notification => {
|
||||||
const releaseDate = parseISO(notification.releaseDate);
|
const releaseDate = parseISO(notification.releaseDate);
|
||||||
return releaseDate > now;
|
return releaseDate > now;
|
||||||
});
|
});
|
||||||
|
|
||||||
const thisWeek = upcoming.filter(notification => {
|
const thisWeek = upcoming.filter(notification => {
|
||||||
const releaseDate = parseISO(notification.releaseDate);
|
const releaseDate = parseISO(notification.releaseDate);
|
||||||
return releaseDate < oneWeekLater;
|
return releaseDate < oneWeekLater;
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
total: this.scheduledNotifications.length,
|
total: this.scheduledNotifications.length,
|
||||||
upcoming: upcoming.length,
|
upcoming: upcoming.length,
|
||||||
|
|
@ -758,12 +779,12 @@ class NotificationService {
|
||||||
clearInterval(this.backgroundSyncInterval);
|
clearInterval(this.backgroundSyncInterval);
|
||||||
this.backgroundSyncInterval = null;
|
this.backgroundSyncInterval = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.librarySubscription) {
|
if (this.librarySubscription) {
|
||||||
this.librarySubscription();
|
this.librarySubscription();
|
||||||
this.librarySubscription = null;
|
this.librarySubscription = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.appStateSubscription) {
|
if (this.appStateSubscription) {
|
||||||
this.appStateSubscription.remove();
|
this.appStateSubscription.remove();
|
||||||
this.appStateSubscription = null;
|
this.appStateSubscription = null;
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit b22f2a386d86fbb31a5f60af62153e9ce77390a5
|
|
||||||
Loading…
Reference in a new issue