From 7372cbc7ffbdfba305feb15ce2663213a8b91847 Mon Sep 17 00:00:00 2001 From: Storm Dragon Date: Wed, 22 Oct 2025 17:03:09 -0400 Subject: [PATCH] Messages are much less verbose now. --- bookstorm.py | 105 ++++++--------------------------- src/audiobookshelf_client.py | 13 ---- src/audiobookshelf_menu.py | 29 ++------- src/folder_audiobook_parser.py | 6 -- 4 files changed, 23 insertions(+), 130 deletions(-) diff --git a/bookstorm.py b/bookstorm.py index 466a22f..05150ff 100755 --- a/bookstorm.py +++ b/bookstorm.py @@ -204,9 +204,7 @@ class BookReader: """Load and parse the book""" # Check if bookPath is a directory (folder audiobook) if self.bookPath.is_dir(): - message = f"Loading audiobook folder {self.bookPath.name}" - print(message) - self.speechEngine.speak(message) + self.speechEngine.speak(f"Loading audiobook folder {self.bookPath.name}") # Use folder audiobook parser self.parser = FolderAudiobookParser() @@ -238,9 +236,6 @@ class BookReader: else: raise ValueError(f"Unsupported book format: {self.bookPath.suffix}") - print(f"Loaded: {self.book.title}") - print(f"Chapters: {self.book.get_total_chapters()}") - # If it's an audio book, load it into the player if hasattr(self.book, 'isAudioBook') and self.book.isAudioBook: # Get saved playback speed from config @@ -262,11 +257,8 @@ class BookReader: # Inform user about navigation capabilities if self.book.get_total_chapters() == 1: - print("\nNote: This audio file has no chapter markers.") - print("Navigation: Only play/pause/stop supported (no chapter jumping)") self.speechEngine.speak("Audio book loaded. No chapter markers found. Only basic playback controls available.") else: - print(f"\nChapter navigation: Enabled ({self.book.get_total_chapters()} chapters)") self.speechEngine.speak(f"Audio book loaded with {self.book.get_total_chapters()} chapters. Chapter navigation enabled.") # Check if this book is linked to Audiobookshelf server @@ -282,10 +274,6 @@ class BookReader: if serverProgress: progressTime = serverProgress.get('currentTime', 0.0) if progressTime > 0: - minutes = int(progressTime // 60) - seconds = int(progressTime % 60) - print(f"Resuming from server progress: {minutes}m {seconds}s") - # For audio books, save exact position if hasattr(self.book, 'isAudioBook') and self.book.isAudioBook: self.savedAudioPosition = progressTime @@ -303,8 +291,8 @@ class BookReader: pass serverProgressLoaded = True - except Exception as e: - print(f"Could not load server progress: {e}") + except: + pass # Fall back to local bookmark if no server progress if not serverProgressLoaded: @@ -313,16 +301,7 @@ class BookReader: self.currentChapter = bookmark['chapterIndex'] self.currentParagraph = bookmark['paragraphIndex'] self.savedAudioPosition = bookmark.get('audioPosition', 0.0) - - # For audio books, show resume position - if hasattr(self.book, 'isAudioBook') and self.book.isAudioBook and self.savedAudioPosition > 0: - minutes = int(self.savedAudioPosition // 60) - seconds = int(self.savedAudioPosition % 60) - print(f"Resuming from local bookmark: chapter {self.currentChapter + 1} at {minutes}m {seconds}s") - else: - print(f"Resuming from chapter {self.currentChapter + 1}, paragraph {self.currentParagraph + 1}") else: - print("Starting from beginning") self.currentChapter = 0 self.currentParagraph = 0 self.savedAudioPosition = 0.0 @@ -349,10 +328,8 @@ class BookReader: # Generate and play audio (unless muted for Braille-only mode) if not self.brailleOutput.muteVoice: try: - print("Generating speech...") wavData = self.ttsEngine.text_to_wav_data(paragraph) if wavData: - print("Playing...") completed = self.audioPlayer.play_wav_data(wavData, blocking=True) return completed except Exception as e: @@ -601,14 +578,14 @@ class BookReader: if self.book: self.displayText = "Press SPACE to start reading" self.statusText = f"Book: {self.book.title}" - print(f"\n{self.book.title} - {self.book.get_total_chapters()} chapters") - print("Press SPACE to start reading") - self.speechEngine.speak("BookStorm ready. Press SPACE to start reading. Press i for info. Press h for help.") + + # Determine book type for message + isAudioBook = hasattr(self.book, 'isAudioBook') and self.book.isAudioBook + bookType = "Audio book" if isAudioBook else "Book" + self.speechEngine.speak(f"{bookType} loaded, press h for help.") else: self.displayText = "No book loaded" self.statusText = "Press A for Audiobookshelf, B for local books, R for recent books" - print("\nNo book loaded") - print("Press A for Audiobookshelf, B for local books, R for recent books") # Speech message already given earlier # Cached rendered surfaces to prevent memory leak from re-rendering 30 FPS @@ -835,18 +812,14 @@ class BookReader: gc.collect() # Full collection every 20 seconds else: gc.collect(generation=0) # Fast collection every 10 seconds - # Debug: Print memory usage every 10 seconds + # Memory watchdog: warn if exceeding 2GB (50% on Pi 4GB) try: import resource # pylint: disable=no-member memUsage = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss / 1024 # MB - print(f"DEBUG: Memory usage: {memUsage:.1f} MB") - - # Memory watchdog: warn if exceeding 2GB (50% on Pi 4GB) if memUsage > 2048 and not memoryWarningShown: memoryWarningShown = True self.speechEngine.speak("Warning: High memory usage detected. Consider restarting BookStorm soon.") - print("WARNING: Memory usage exceeds 2GB - consider restarting") except: pass gcCounter = 0 @@ -912,9 +885,6 @@ class BookReader: # Common commands (from brltty documentation): # FWINRT (forward) and FWINLT (backward) for panning - # For debugging, print the key code - print(f"DEBUG: Braille key pressed: {keyCode}") - # Check if it's a panning command # The key format varies by device, but we can check ranges # Typically: 0x04000000 range for panning commands @@ -928,18 +898,13 @@ class BookReader: if command == CMD_FWINRT or (keyCode & 0xFF) == 0x01: # Forward panning - print("DEBUG: Braille pan forward") self.brailleOutput.pan_forward() elif command == CMD_FWINLT or (keyCode & 0xFF) == 0x02: # Backward panning - print("DEBUG: Braille pan backward") self.brailleOutput.pan_backward() - else: - # Unknown key - just log it for now - print(f"DEBUG: Unknown Braille key: 0x{keyCode:08x}") - except Exception as e: - print(f"DEBUG: Error handling Braille key: {e}") + except: + pass def _handle_pygame_key(self, event): """Handle pygame key event""" @@ -993,8 +958,6 @@ class BookReader: readerEngine = self.config.get_reader_engine() if not self.isPlaying: - # Speak UI feedback (always safe with separate sessions) - self.speechEngine.speak("Starting playback") self.isPlaying = True self._start_paragraph_playback() else: @@ -1002,26 +965,20 @@ class BookReader: if isAudioBook: # Handle audio book pause/resume if self.audioPlayer.is_paused(): - self.speechEngine.speak("Resuming") self.audioPlayer.resume_audio_file() else: - self.speechEngine.speak("Paused") self.audioPlayer.pause_audio_file() elif readerEngine == 'speechd': # Handle speech-dispatcher pause/resume if self.readingEngine.is_reading_paused(): - self.speechEngine.speak("Resuming") self.readingEngine.resume_reading() else: - self.speechEngine.speak("Paused") self.readingEngine.pause_reading() else: # Handle piper-tts pause/resume (now uses audio file methods) if self.audioPlayer.is_paused(): - self.speechEngine.speak("Resuming") self.audioPlayer.resume_audio_file() else: - self.speechEngine.speak("Paused") self.audioPlayer.pause_audio_file() elif event.key == pygame.K_n: @@ -1043,8 +1000,6 @@ class BookReader: self._stop_playback() if self.next_chapter(): - # Just say "Next chapter" without title to avoid confusion - self.speechEngine.speak("Next chapter") if wasPlaying: self.isPlaying = True self._start_paragraph_playback() @@ -1081,8 +1036,6 @@ class BookReader: self._stop_playback() if self.previous_chapter(): - # Just say "Previous chapter" without title to avoid confusion - self.speechEngine.speak("Previous chapter") if wasPlaying: self.isPlaying = True self._start_paragraph_playback() @@ -1339,7 +1292,6 @@ class BookReader: # Shift+Left: Previous chapter self._stop_playback() if self.previous_chapter(): - self.speechEngine.speak("Previous chapter") if self.isPlaying: self._start_paragraph_playback() else: @@ -1372,7 +1324,6 @@ class BookReader: # Shift+Right: Next chapter self._stop_playback() if self.next_chapter(): - self.speechEngine.speak("Next chapter") if self.isPlaying: self._start_paragraph_playback() else: @@ -1837,8 +1788,6 @@ class BookReader: author = metadata.get('authorName', '') duration = media.get('duration', 0.0) - print(f"\nDEBUG: Streaming book ID: {serverId}") - print(f"DEBUG: Title from metadata: {title}") # Get streaming URL (pass full book details to avoid re-fetching) self.speechEngine.speak(f"Loading stream for {title}. Please wait.") @@ -1894,7 +1843,6 @@ class BookReader: # Save server book reference for resume on restart # Use special format: abs://{server_id} so we can detect and resume self.config.set_last_book(f"abs://{serverId}") - print(f"DEBUG: Saved last_book as: abs://{serverId}") # Create listening session (only if we don't already have one from resume) if not self.sessionId: @@ -1925,7 +1873,6 @@ class BookReader: progressTime = serverProgress.get('currentTime', 0.0) minutes = int(progressTime // 60) seconds = int(progressTime % 60) - print(f"Resuming from server progress: {minutes}m {seconds}s ({progressTime:.1f}s)") # Save the exact position for playback resume self.savedAudioPosition = progressTime @@ -2027,8 +1974,6 @@ class BookReader: duration = media.get('duration', 0.0) numChapters = media.get('numChapters', 0) - print(f"\nDEBUG: Downloading book ID: {serverId}") - print(f"DEBUG: Title from metadata: {title}") # Create sanitized filename safeTitle = "".join(c for c in title if c.isalnum() or c in (' ', '-', '_')).strip() @@ -2150,31 +2095,19 @@ class BookReader: if not isAudioBook: return False + # Check if audio is actually loaded/playing + if not self.audioPlayer.is_audio_file_loaded(): + self.speechEngine.speak("Nothing playing") + return False + # Get current position currentPos = self.audioPlayer.get_audio_position() # Calculate new position newPos = max(0.0, currentPos + seconds) - # Seek to new position - if self.audioPlayer.seek_audio(newPos): - # Format time for speech feedback - absSeconds = abs(seconds) - if absSeconds >= 60: - minutes = int(absSeconds // 60) - secs = int(absSeconds % 60) - if secs > 0: - timeStr = f"{minutes} minutes {secs} seconds" - else: - timeStr = f"{minutes} minutes" - else: - timeStr = f"{int(absSeconds)} seconds" - - direction = "forward" if seconds > 0 else "backward" - self.speechEngine.speak(f"Seek {timeStr} {direction}") - return True - - return False + # Seek to new position silently (audio feedback is enough) + return self.audioPlayer.seek_audio(newPos) def _load_new_book(self, bookPath): """ @@ -2359,7 +2292,6 @@ class BookReader: self.savedAudioPosition = 0.0 minutes = int(startTime // 60) seconds = int(startTime % 60) - print(f"Resuming playback at {minutes}m {seconds}s") else: # Get start time from audio chapter if hasattr(chapter, 'startTime'): @@ -2591,7 +2523,6 @@ def main(): if lastBook and lastBook.startswith('abs://'): # Extract server book ID serverId = lastBook[6:] # Remove 'abs://' prefix - print(f"Resuming Audiobookshelf book: {serverId}") # Try to restore from cached server link from src.server_link_manager import ServerLinkManager diff --git a/src/audiobookshelf_client.py b/src/audiobookshelf_client.py index cd91a28..e188cea 100644 --- a/src/audiobookshelf_client.py +++ b/src/audiobookshelf_client.py @@ -294,8 +294,6 @@ class AudiobookshelfClient: downloadUrl = f"{self.serverUrl}/api/items/{itemId}/file" headers = {'Authorization': f'Bearer {self.authToken}'} - print(f"DEBUG: Downloading from: {downloadUrl}") - # Download with streaming to handle large files # Use context manager to ensure response cleanup with requests.get(downloadUrl, headers=headers, stream=True, timeout=30) as response: @@ -348,14 +346,9 @@ class AudiobookshelfClient: # Validate item exists and has audio content (optional check) if itemDetails: media = itemDetails.get('media', {}) - numAudioFiles = media.get('numAudioFiles', 0) - duration = media.get('duration', 0.0) - print(f"DEBUG: Item has {numAudioFiles} audio files, duration {duration}s") - # Use the /play endpoint which creates a playback session and returns stream info # This is what the web player uses playUrl = f"{self.serverUrl}/api/items/{itemId}/play" - print(f"DEBUG: Requesting play session from: {playUrl}") response = requests.post( playUrl, @@ -378,7 +371,6 @@ class AudiobookshelfClient: return None playData = response.json() - print(f"DEBUG: Play response keys: {list(playData.keys())}") # Extract the actual stream URL from the play response # The response contains either 'audioTracks' or direct 'url' @@ -389,15 +381,12 @@ class AudiobookshelfClient: # Multi-file audiobook - use first track or concatenated stream audioTrack = playData['audioTracks'][0] streamUrl = audioTrack.get('contentUrl') - print(f"DEBUG: Using audioTrack URL") elif 'url' in playData: # Direct URL streamUrl = playData.get('url') - print(f"DEBUG: Using direct URL") elif 'contentUrl' in playData: # Alternative format streamUrl = playData.get('contentUrl') - print(f"DEBUG: Using contentUrl") if not streamUrl: print(f"ERROR: No stream URL found in play response") @@ -408,7 +397,6 @@ class AudiobookshelfClient: if streamUrl.startswith('/'): streamUrl = f"{self.serverUrl}{streamUrl}" - print(f"DEBUG: Stream URL: {streamUrl[:100]}...") return streamUrl except Exception as e: @@ -551,7 +539,6 @@ class AudiobookshelfClient: if response.status_code == 200: data = response.json() sessionId = data.get('id') - print(f"DEBUG: Session created successfully: {sessionId}") return sessionId else: # Session creation not critical, just log and continue diff --git a/src/audiobookshelf_menu.py b/src/audiobookshelf_menu.py index c85a8ba..a1e5a62 100644 --- a/src/audiobookshelf_menu.py +++ b/src/audiobookshelf_menu.py @@ -177,15 +177,6 @@ class AudiobookshelfMenu: elif direction == 'down': self.currentSelection = (self.currentSelection + 1) % len(self.items) - # Debug output - print(f"DEBUG NAV: {direction} - moved from {oldSelection} to {self.currentSelection} (total items: {len(self.items)})") - if self.currentSelection < len(self.items): - item = self.items[self.currentSelection] - media = item.get('media', {}) - metadata = media.get('metadata', {}) - title = metadata.get('title', 'Unknown') - print(f"DEBUG NAV: Current item title: {title}") - self._speak_current_item() def change_view(self, direction): @@ -375,31 +366,21 @@ class AudiobookshelfMenu: # Book selected self.selectedBook = item - # Debug: what book did user select? - media = item.get('media', {}) - metadata = media.get('metadata', {}) - title = metadata.get('title', 'Unknown') - print(f"\nDEBUG SELECT: User pressed ENTER on item {self.currentSelection}") - print(f"DEBUG SELECT: Book title: {title}") - print(f"DEBUG SELECT: Book ID: {item.get('id', 'NO ID')}") - # For books from series/collections, fetch full details if needed # (they might have incomplete metadata) if not item.get('media'): # Book doesn't have full media details, fetch them bookId = item.get('id') or item.get('libraryItemId') if bookId: - print(f"\nFetching full details for book ID: {bookId}") fullDetails = self.absClient.get_library_item_details(bookId) if fullDetails: self.selectedBook = fullDetails item = fullDetails - print("Full book details loaded") - # Re-extract metadata from full details - media = item.get('media', {}) - metadata = media.get('metadata', {}) - title = metadata.get('title', 'Unknown') - print(f"DEBUG SELECT: After fetch, title is: {title}") + + # Get metadata for later use + media = item.get('media', {}) + metadata = media.get('metadata', {}) + title = metadata.get('title', 'Unknown') # Check if local copy exists isLocal = self._check_if_local(item) diff --git a/src/folder_audiobook_parser.py b/src/folder_audiobook_parser.py index c022647..a08a600 100644 --- a/src/folder_audiobook_parser.py +++ b/src/folder_audiobook_parser.py @@ -54,8 +54,6 @@ class FolderAudiobookParser: if not audioFiles: raise ValueError(f"No audio files found in: {folderPath}") - print(f"Found {len(audioFiles)} audio files in folder") - # Extract metadata from each file fileMetadata = [] for audioFile in audioFiles: @@ -98,10 +96,6 @@ class FolderAudiobookParser: book.audioFiles = [fileData['path'] for fileData in sortedFiles] book.isMultiFile = True - print(f"Loaded: {book.title} by {book.author}") - print(f"Total duration: {totalDuration / 60:.1f} minutes") - print(f"Chapters: {len(book.chapters)}") - return book def _find_audio_files(self, folderPath):