## New Features - Article Summary Mode: AI-generated 30-second summaries with complexity analysis - Reading Stats Dashboard: Track articles read, listening time, and streaks - Bookmark/Resume: Auto-save progress when pausing, resume from where you left off - Audio Export: Export articles as downloadable WAV files - RSS Feed Manager: Subscribe to feeds with real-time validation and 31+ recommendations - Smart Speed: Auto-adjust playback based on article complexity - Voice Moods: Quick presets for different listening scenarios ## RSS Enhancements - Expanded recommendations from 8 to 31 sources across 5 categories: * General News (9 sources) * Technology (8 sources) * Business & Finance (5 sources) * Science & Research (5 sources) * International News (4 sources) - Real-time URL validation with visual feedback - Detailed error messages for different failure scenarios - Always-visible categorized recommendations - Auto-loading articles when feeds are added ## Bug Fixes - Fixed voice selection: Selected voice now consistently applies to playback - Implemented voice generation counter to prevent voice mixing between paragraphs - Fixed speed control to snap to clean 0.5 increments (1.0, 1.5, 2.0, etc.) - Fixed dark mode toggle by configuring Tailwind CDN for class-based dark mode - Removed vibe visualizer animation ## UI/UX Improvements - Redesigned voice selector with prominent voice panel and preview functionality - Added voice cards with emojis and descriptions - Enhanced feature toolbar with quick access to all new features - Improved reader view with better typography and reading modes - Added ambient reading modes (clean, sepia, night light) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
124 lines
2.7 KiB
TypeScript
124 lines
2.7 KiB
TypeScript
|
|
export enum VoiceName {
|
|
Puck = 'Puck',
|
|
Charon = 'Charon',
|
|
Kore = 'Kore',
|
|
Fenrir = 'Fenrir',
|
|
Zephyr = 'Zephyr',
|
|
Aoede = 'Aoede',
|
|
}
|
|
|
|
export enum PlaybackStatus {
|
|
IDLE = 'IDLE',
|
|
LOADING_TEXT = 'LOADING_TEXT',
|
|
LOADING_AUDIO = 'LOADING_AUDIO',
|
|
READY = 'READY',
|
|
PLAYING = 'PLAYING',
|
|
PAUSED = 'PAUSED',
|
|
ERROR = 'ERROR',
|
|
COMPLETED = 'COMPLETED'
|
|
}
|
|
|
|
export interface AudioSegment {
|
|
id: string;
|
|
text: string;
|
|
audioUrl?: string;
|
|
isLoading: boolean;
|
|
hasError: boolean;
|
|
}
|
|
|
|
export interface Article {
|
|
id: string;
|
|
url: string;
|
|
title: string;
|
|
text: string;
|
|
segments: AudioSegment[];
|
|
currentSegmentIndex: number;
|
|
status: PlaybackStatus;
|
|
errorMessage?: string;
|
|
// New fields for enhanced features
|
|
summary?: string;
|
|
summaryAudioUrl?: string;
|
|
isSummaryLoading?: boolean;
|
|
complexity?: 'simple' | 'moderate' | 'complex';
|
|
wordCount?: number;
|
|
estimatedReadTime?: number; // in minutes
|
|
addedAt?: number; // timestamp
|
|
fromRssFeed?: string; // RSS feed ID if applicable
|
|
}
|
|
|
|
export interface PlayerState {
|
|
isPlaying: boolean;
|
|
playbackRate: number;
|
|
currentArticleId: string | null;
|
|
selectedVoice: VoiceName;
|
|
voiceMood: VoiceMood;
|
|
smartSpeedEnabled: boolean;
|
|
}
|
|
|
|
export interface ReaderSettings {
|
|
isDarkMode: boolean;
|
|
fontSize: 'sm' | 'base' | 'lg' | 'xl' | '2xl';
|
|
lineHeight: 'normal' | 'relaxed' | 'loose';
|
|
fontFamily: 'sans' | 'serif' | 'mono';
|
|
autoScroll: boolean;
|
|
readingTone: 'clean' | 'sepia' | 'night';
|
|
pageWidth: 'cozy' | 'standard' | 'wide';
|
|
zenMode: boolean;
|
|
}
|
|
|
|
// Voice Moods - preset configurations
|
|
export type VoiceMood = 'neutral' | 'energetic' | 'calm' | 'professional' | 'bedtime';
|
|
|
|
export interface VoiceMoodConfig {
|
|
id: VoiceMood;
|
|
label: string;
|
|
emoji: string;
|
|
description: string;
|
|
recommendedVoice: VoiceName;
|
|
recommendedSpeed: number;
|
|
}
|
|
|
|
// Reading Stats
|
|
export interface ReadingStats {
|
|
totalArticlesRead: number;
|
|
totalMinutesListened: number;
|
|
totalWordsRead: number;
|
|
currentStreak: number; // days
|
|
longestStreak: number;
|
|
lastReadDate: string; // ISO date string
|
|
articlesPerDay: Record<string, number>; // date -> count
|
|
favoriteVoice: VoiceName;
|
|
voiceUsage: Record<VoiceName, number>;
|
|
}
|
|
|
|
// Bookmarks for resume functionality
|
|
export interface Bookmark {
|
|
articleId: string;
|
|
url: string;
|
|
title: string;
|
|
segmentIndex: number;
|
|
savedAt: number; // timestamp
|
|
progress: number; // 0-100 percentage
|
|
}
|
|
|
|
// RSS Feed subscriptions
|
|
export interface RSSFeed {
|
|
id: string;
|
|
url: string;
|
|
title: string;
|
|
description?: string;
|
|
lastFetched?: number;
|
|
articleCount?: number;
|
|
isActive: boolean;
|
|
addedAt: number;
|
|
}
|
|
|
|
export interface RSSArticle {
|
|
title: string;
|
|
url: string;
|
|
description?: string;
|
|
pubDate?: string;
|
|
feedId: string;
|
|
}
|