import { ReadingStats, Bookmark, RSSFeed, VoiceName } from '../types'; const STORAGE_KEYS = { STATS: 'newscaster_stats', BOOKMARKS: 'newscaster_bookmarks', RSS_FEEDS: 'newscaster_rss_feeds', LAST_PLAYED: 'newscaster_last_played' }; // Default stats const DEFAULT_STATS: ReadingStats = { totalArticlesRead: 0, totalMinutesListened: 0, totalWordsRead: 0, currentStreak: 0, longestStreak: 0, lastReadDate: '', articlesPerDay: {}, favoriteVoice: VoiceName.Puck, voiceUsage: { [VoiceName.Puck]: 0, [VoiceName.Charon]: 0, [VoiceName.Kore]: 0, [VoiceName.Fenrir]: 0, [VoiceName.Zephyr]: 0, [VoiceName.Aoede]: 0 } }; // ==================== STATS ==================== export const getStats = (): ReadingStats => { try { const stored = localStorage.getItem(STORAGE_KEYS.STATS); if (stored) { return { ...DEFAULT_STATS, ...JSON.parse(stored) }; } } catch (e) { console.warn('Failed to load stats:', e); } return DEFAULT_STATS; }; export const saveStats = (stats: ReadingStats): void => { try { localStorage.setItem(STORAGE_KEYS.STATS, JSON.stringify(stats)); } catch (e) { console.warn('Failed to save stats:', e); } }; export const updateStatsOnArticleComplete = ( wordCount: number, minutesListened: number, voice: VoiceName ): ReadingStats => { const stats = getStats(); const today = new Date().toISOString().split('T')[0]; // Update totals stats.totalArticlesRead += 1; stats.totalMinutesListened += minutesListened; stats.totalWordsRead += wordCount; // Update daily count stats.articlesPerDay[today] = (stats.articlesPerDay[today] || 0) + 1; // Update streak const yesterday = new Date(Date.now() - 86400000).toISOString().split('T')[0]; if (stats.lastReadDate === yesterday) { stats.currentStreak += 1; } else if (stats.lastReadDate !== today) { stats.currentStreak = 1; } stats.longestStreak = Math.max(stats.longestStreak, stats.currentStreak); stats.lastReadDate = today; // Update voice usage stats.voiceUsage[voice] = (stats.voiceUsage[voice] || 0) + 1; // Determine favorite voice let maxUsage = 0; Object.entries(stats.voiceUsage).forEach(([v, count]) => { if (count > maxUsage) { maxUsage = count; stats.favoriteVoice = v as VoiceName; } }); saveStats(stats); return stats; }; // ==================== BOOKMARKS ==================== export const getBookmarks = (): Bookmark[] => { try { const stored = localStorage.getItem(STORAGE_KEYS.BOOKMARKS); if (stored) { return JSON.parse(stored); } } catch (e) { console.warn('Failed to load bookmarks:', e); } return []; }; export const saveBookmark = (bookmark: Bookmark): void => { try { const bookmarks = getBookmarks(); // Remove existing bookmark for same URL const filtered = bookmarks.filter(b => b.url !== bookmark.url); filtered.unshift(bookmark); // Add to beginning // Keep only last 50 bookmarks const trimmed = filtered.slice(0, 50); localStorage.setItem(STORAGE_KEYS.BOOKMARKS, JSON.stringify(trimmed)); } catch (e) { console.warn('Failed to save bookmark:', e); } }; export const removeBookmark = (url: string): void => { try { const bookmarks = getBookmarks(); const filtered = bookmarks.filter(b => b.url !== url); localStorage.setItem(STORAGE_KEYS.BOOKMARKS, JSON.stringify(filtered)); } catch (e) { console.warn('Failed to remove bookmark:', e); } }; export const getBookmarkForUrl = (url: string): Bookmark | undefined => { const bookmarks = getBookmarks(); return bookmarks.find(b => b.url === url); }; // ==================== RSS FEEDS ==================== export const getRSSFeeds = (): RSSFeed[] => { try { const stored = localStorage.getItem(STORAGE_KEYS.RSS_FEEDS); if (stored) { return JSON.parse(stored); } } catch (e) { console.warn('Failed to load RSS feeds:', e); } return []; }; export const saveRSSFeed = (feed: RSSFeed): void => { try { const feeds = getRSSFeeds(); const existing = feeds.findIndex(f => f.id === feed.id); if (existing >= 0) { feeds[existing] = feed; } else { feeds.push(feed); } localStorage.setItem(STORAGE_KEYS.RSS_FEEDS, JSON.stringify(feeds)); } catch (e) { console.warn('Failed to save RSS feed:', e); } }; export const removeRSSFeed = (feedId: string): void => { try { const feeds = getRSSFeeds(); const filtered = feeds.filter(f => f.id !== feedId); localStorage.setItem(STORAGE_KEYS.RSS_FEEDS, JSON.stringify(filtered)); } catch (e) { console.warn('Failed to remove RSS feed:', e); } }; export const updateRSSFeedLastFetched = (feedId: string): void => { try { const feeds = getRSSFeeds(); const feed = feeds.find(f => f.id === feedId); if (feed) { feed.lastFetched = Date.now(); localStorage.setItem(STORAGE_KEYS.RSS_FEEDS, JSON.stringify(feeds)); } } catch (e) { console.warn('Failed to update RSS feed:', e); } }; // ==================== LAST PLAYED ==================== export const saveLastPlayed = (articleId: string, segmentIndex: number): void => { try { localStorage.setItem(STORAGE_KEYS.LAST_PLAYED, JSON.stringify({ articleId, segmentIndex, timestamp: Date.now() })); } catch (e) { console.warn('Failed to save last played:', e); } }; export const getLastPlayed = (): { articleId: string; segmentIndex: number } | null => { try { const stored = localStorage.getItem(STORAGE_KEYS.LAST_PLAYED); if (stored) { return JSON.parse(stored); } } catch (e) { console.warn('Failed to load last played:', e); } return null; };