"""Notes service — shared business logic for note CRUD operations.""" from ..core.client import NotebookLMClient from ._compat import TypedDict from .errors import ServiceError, ValidationError class NoteInfo(TypedDict): """Note details.""" id: str title: str preview: str class NoteListResult(TypedDict): """Result of listing notes.""" notebook_id: str notes: list[NoteInfo] count: int class NoteCreateResult(TypedDict): """Result of creating a note.""" note_id: str title: str content_preview: str message: str class NoteUpdateResult(TypedDict): """Result of updating a note.""" note_id: str updated: bool message: str class NoteDeleteResult(TypedDict): """Result of deleting a note.""" note_id: str message: str def list_notes(client: NotebookLMClient, notebook_id: str) -> NoteListResult: """List all notes in a notebook. Args: client: Authenticated NotebookLM client notebook_id: Notebook UUID Returns: NoteListResult with note list and count Raises: ServiceError: If the API call fails """ try: notes = client.list_notes(notebook_id) return { "notebook_id": notebook_id, "notes": notes, "count": len(notes), } except Exception as e: raise ServiceError(f"Failed to list notes: {e}") from e def create_note( client: NotebookLMClient, notebook_id: str, content: str, title: str | None = None, ) -> NoteCreateResult: """Create a new note in a notebook. Args: client: Authenticated NotebookLM client notebook_id: Notebook UUID content: Note content (required) title: Note title (defaults to "New Note") Returns: NoteCreateResult with note ID and preview Raises: ValidationError: If content is empty ServiceError: If creation fails """ if not content or not content.strip(): raise ValidationError( "Content is required to create a note.", user_message="Note content cannot be empty.", ) effective_title = title or "New Note" try: result = client.create_note(notebook_id, content, effective_title) except Exception as e: raise ServiceError(f"Failed to create note: {e}") from e if result and result.get("id"): preview = content[:100] + ("..." if len(content) > 100 else "") return { "note_id": result["id"], "title": result.get("title", effective_title), "content_preview": preview, "message": f"Note '{result.get('title', effective_title)}' created.", } raise ServiceError( "Note creation returned no ID", user_message="Failed to create note — no confirmation from API.", ) def update_note( client: NotebookLMClient, notebook_id: str, note_id: str, content: str | None = None, title: str | None = None, ) -> NoteUpdateResult: """Update a note's content and/or title. Args: client: Authenticated NotebookLM client notebook_id: Notebook UUID note_id: Note UUID content: New content (optional) title: New title (optional) Returns: NoteUpdateResult Raises: ValidationError: If neither content nor title is provided ServiceError: If update fails """ if content is None and title is None: raise ValidationError( "Must provide content or title to update.", user_message="Provide at least --content or --title to update.", ) try: result = client.update_note(note_id, content, title, notebook_id) except Exception as e: raise ServiceError(f"Failed to update note: {e}") from e if result: parts = [] if title: parts.append(f"title → '{title}'") if content: parts.append(f"content ({len(content)} chars)") detail = ", ".join(parts) if parts else "updated" return { "note_id": note_id, "updated": True, "message": f"Note updated: {detail}.", } raise ServiceError( "Note update returned falsy result", user_message="Failed to update note — no confirmation from API.", ) def delete_note( client: NotebookLMClient, notebook_id: str, note_id: str, ) -> NoteDeleteResult: """Delete a note permanently. Args: client: Authenticated NotebookLM client notebook_id: Notebook UUID note_id: Note UUID Returns: NoteDeleteResult Raises: ServiceError: If deletion fails """ try: result = client.delete_note(note_id, notebook_id) except Exception as e: raise ServiceError(f"Failed to delete note: {e}") from e if result: return { "note_id": note_id, "message": f"Note {note_id} deleted permanently.", } raise ServiceError( "Note deletion returned falsy result", user_message="Failed to delete note — no confirmation from API.", )