notebooklm-py 0.1.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- notebooklm_py-0.1.2/.env.example +35 -0
- notebooklm_py-0.1.2/.github/workflows/nightly.yml +65 -0
- notebooklm_py-0.1.2/.github/workflows/publish.yml +34 -0
- notebooklm_py-0.1.2/.github/workflows/test.yml +83 -0
- notebooklm_py-0.1.2/.github/workflows/verify-artifacts.yml +123 -0
- notebooklm_py-0.1.2/.gitignore +20 -0
- notebooklm_py-0.1.2/.pre-commit-config.yaml +7 -0
- notebooklm_py-0.1.2/AGENTS.md +115 -0
- notebooklm_py-0.1.2/CHANGELOG.md +110 -0
- notebooklm_py-0.1.2/CLAUDE.md +168 -0
- notebooklm_py-0.1.2/CONTRIBUTING.md +156 -0
- notebooklm_py-0.1.2/LICENSE +21 -0
- notebooklm_py-0.1.2/PKG-INFO +200 -0
- notebooklm_py-0.1.2/README.md +153 -0
- notebooklm_py-0.1.2/RELEASING.md +50 -0
- notebooklm_py-0.1.2/SECURITY.md +106 -0
- notebooklm_py-0.1.2/dev/test-versions.sh +202 -0
- notebooklm_py-0.1.2/docs/README.md +35 -0
- notebooklm_py-0.1.2/docs/cli-reference.md +537 -0
- notebooklm_py-0.1.2/docs/configuration.md +389 -0
- notebooklm_py-0.1.2/docs/contributing/adding-rpc-methods.md +379 -0
- notebooklm_py-0.1.2/docs/contributing/architecture.md +249 -0
- notebooklm_py-0.1.2/docs/contributing/debugging.md +325 -0
- notebooklm_py-0.1.2/docs/contributing/testing.md +558 -0
- notebooklm_py-0.1.2/docs/designs/notebooklm-skill.md +137 -0
- notebooklm_py-0.1.2/docs/examples/bulk-import.py +110 -0
- notebooklm_py-0.1.2/docs/examples/quickstart.py +78 -0
- notebooklm_py-0.1.2/docs/examples/research-to-podcast.py +95 -0
- notebooklm_py-0.1.2/docs/getting-started.md +180 -0
- notebooklm_py-0.1.2/docs/python-api.md +783 -0
- notebooklm_py-0.1.2/docs/reference/internals/rpc-capture.md +380 -0
- notebooklm_py-0.1.2/docs/reference/internals/rpc-ui-reference.md +1290 -0
- notebooklm_py-0.1.2/docs/releasing.md +130 -0
- notebooklm_py-0.1.2/docs/stability.md +168 -0
- notebooklm_py-0.1.2/docs/troubleshooting.md +395 -0
- notebooklm_py-0.1.2/examples/chat_and_ask.py +185 -0
- notebooklm_py-0.1.2/examples/file_upload_example.py +53 -0
- notebooklm_py-0.1.2/examples/notes_and_mind_maps.py +256 -0
- notebooklm_py-0.1.2/examples/podcast_generation.py +102 -0
- notebooklm_py-0.1.2/examples/research_workflow.py +158 -0
- notebooklm_py-0.1.2/examples/video_generation.py +157 -0
- notebooklm_py-0.1.2/notebooklm-py.png +0 -0
- notebooklm_py-0.1.2/pyproject.toml +121 -0
- notebooklm_py-0.1.2/scripts/heal_golden_notebook.py +252 -0
- notebooklm_py-0.1.2/scripts/pre_release_check.sh +49 -0
- notebooklm_py-0.1.2/src/notebooklm/__init__.py +108 -0
- notebooklm_py-0.1.2/src/notebooklm/_artifacts.py +1489 -0
- notebooklm_py-0.1.2/src/notebooklm/_chat.py +379 -0
- notebooklm_py-0.1.2/src/notebooklm/_core.py +254 -0
- notebooklm_py-0.1.2/src/notebooklm/_notebooks.py +273 -0
- notebooklm_py-0.1.2/src/notebooklm/_notes.py +298 -0
- notebooklm_py-0.1.2/src/notebooklm/_research.py +246 -0
- notebooklm_py-0.1.2/src/notebooklm/_sources.py +764 -0
- notebooklm_py-0.1.2/src/notebooklm/auth.py +418 -0
- notebooklm_py-0.1.2/src/notebooklm/cli/__init__.py +134 -0
- notebooklm_py-0.1.2/src/notebooklm/cli/artifact.py +464 -0
- notebooklm_py-0.1.2/src/notebooklm/cli/chat.py +235 -0
- notebooklm_py-0.1.2/src/notebooklm/cli/download.py +717 -0
- notebooklm_py-0.1.2/src/notebooklm/cli/download_helpers.py +135 -0
- notebooklm_py-0.1.2/src/notebooklm/cli/generate.py +668 -0
- notebooklm_py-0.1.2/src/notebooklm/cli/grouped.py +83 -0
- notebooklm_py-0.1.2/src/notebooklm/cli/helpers.py +489 -0
- notebooklm_py-0.1.2/src/notebooklm/cli/note.py +222 -0
- notebooklm_py-0.1.2/src/notebooklm/cli/notebook.py +245 -0
- notebooklm_py-0.1.2/src/notebooklm/cli/options.py +93 -0
- notebooklm_py-0.1.2/src/notebooklm/cli/research.py +207 -0
- notebooklm_py-0.1.2/src/notebooklm/cli/session.py +302 -0
- notebooklm_py-0.1.2/src/notebooklm/cli/skill.py +153 -0
- notebooklm_py-0.1.2/src/notebooklm/cli/source.py +696 -0
- notebooklm_py-0.1.2/src/notebooklm/client.py +172 -0
- notebooklm_py-0.1.2/src/notebooklm/data/SKILL.md +402 -0
- notebooklm_py-0.1.2/src/notebooklm/notebooklm_cli.py +112 -0
- notebooklm_py-0.1.2/src/notebooklm/paths.py +105 -0
- notebooklm_py-0.1.2/src/notebooklm/rpc/__init__.py +66 -0
- notebooklm_py-0.1.2/src/notebooklm/rpc/decoder.py +250 -0
- notebooklm_py-0.1.2/src/notebooklm/rpc/encoder.py +98 -0
- notebooklm_py-0.1.2/src/notebooklm/rpc/types.py +274 -0
- notebooklm_py-0.1.2/src/notebooklm/types.py +629 -0
- notebooklm_py-0.1.2/tests/conftest.py +86 -0
- notebooklm_py-0.1.2/tests/e2e/__init__.py +0 -0
- notebooklm_py-0.1.2/tests/e2e/conftest.py +441 -0
- notebooklm_py-0.1.2/tests/e2e/test_artifacts.py +241 -0
- notebooklm_py-0.1.2/tests/e2e/test_downloads.py +137 -0
- notebooklm_py-0.1.2/tests/e2e/test_file_upload.py +102 -0
- notebooklm_py-0.1.2/tests/e2e/test_generation.py +360 -0
- notebooklm_py-0.1.2/tests/e2e/test_notebooks.py +140 -0
- notebooklm_py-0.1.2/tests/e2e/test_notes.py +107 -0
- notebooklm_py-0.1.2/tests/e2e/test_research.py +260 -0
- notebooklm_py-0.1.2/tests/e2e/test_sources.py +247 -0
- notebooklm_py-0.1.2/tests/integration/conftest.py +73 -0
- notebooklm_py-0.1.2/tests/integration/test_artifacts.py +807 -0
- notebooklm_py-0.1.2/tests/integration/test_chat.py +157 -0
- notebooklm_py-0.1.2/tests/integration/test_core.py +25 -0
- notebooklm_py-0.1.2/tests/integration/test_download_multi_artifact.py +295 -0
- notebooklm_py-0.1.2/tests/integration/test_notebooks.py +493 -0
- notebooklm_py-0.1.2/tests/integration/test_notes.py +241 -0
- notebooklm_py-0.1.2/tests/integration/test_research_api.py +240 -0
- notebooklm_py-0.1.2/tests/integration/test_sources.py +585 -0
- notebooklm_py-0.1.2/tests/unit/cli/__init__.py +1 -0
- notebooklm_py-0.1.2/tests/unit/cli/conftest.py +194 -0
- notebooklm_py-0.1.2/tests/unit/cli/test_artifact.py +571 -0
- notebooklm_py-0.1.2/tests/unit/cli/test_download.py +384 -0
- notebooklm_py-0.1.2/tests/unit/cli/test_generate.py +463 -0
- notebooklm_py-0.1.2/tests/unit/cli/test_grouped.py +128 -0
- notebooklm_py-0.1.2/tests/unit/cli/test_helpers.py +566 -0
- notebooklm_py-0.1.2/tests/unit/cli/test_note.py +294 -0
- notebooklm_py-0.1.2/tests/unit/cli/test_notebook.py +708 -0
- notebooklm_py-0.1.2/tests/unit/cli/test_resolve.py +361 -0
- notebooklm_py-0.1.2/tests/unit/cli/test_session.py +350 -0
- notebooklm_py-0.1.2/tests/unit/cli/test_skill.py +167 -0
- notebooklm_py-0.1.2/tests/unit/cli/test_source.py +625 -0
- notebooklm_py-0.1.2/tests/unit/test_api_coverage.py +306 -0
- notebooklm_py-0.1.2/tests/unit/test_artifact_downloads.py +391 -0
- notebooklm_py-0.1.2/tests/unit/test_auth.py +682 -0
- notebooklm_py-0.1.2/tests/unit/test_client.py +304 -0
- notebooklm_py-0.1.2/tests/unit/test_conversation.py +96 -0
- notebooklm_py-0.1.2/tests/unit/test_decoder.py +402 -0
- notebooklm_py-0.1.2/tests/unit/test_download_helpers.py +189 -0
- notebooklm_py-0.1.2/tests/unit/test_encoder.py +192 -0
- notebooklm_py-0.1.2/tests/unit/test_notes_unit.py +637 -0
- notebooklm_py-0.1.2/tests/unit/test_paths.py +127 -0
- notebooklm_py-0.1.2/tests/unit/test_research.py +88 -0
- notebooklm_py-0.1.2/tests/unit/test_rpc_types.py +88 -0
- notebooklm_py-0.1.2/tests/unit/test_source_status.py +257 -0
- notebooklm_py-0.1.2/tests/unit/test_sources_upload.py +514 -0
- notebooklm_py-0.1.2/tests/unit/test_types.py +489 -0
- notebooklm_py-0.1.2/tests/unit/test_youtube_extraction.py +69 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# NotebookLM Configuration
|
|
2
|
+
# Copy this file to .env and fill in your values
|
|
3
|
+
|
|
4
|
+
# =============================================================================
|
|
5
|
+
# Configuration Environment Variables
|
|
6
|
+
# =============================================================================
|
|
7
|
+
|
|
8
|
+
# Custom home directory for all config files (optional)
|
|
9
|
+
# Default: ~/.notebooklm
|
|
10
|
+
# NOTEBOOKLM_HOME=/custom/path
|
|
11
|
+
|
|
12
|
+
# Inline authentication JSON for CI/CD (optional)
|
|
13
|
+
# When set, authentication is read from this variable instead of a file
|
|
14
|
+
# Get the value from: cat $NOTEBOOKLM_HOME/storage_state.json (default: ~/.notebooklm)
|
|
15
|
+
# NOTEBOOKLM_AUTH_JSON='{"cookies":[...]}'
|
|
16
|
+
|
|
17
|
+
# Enable RPC debug logging (optional)
|
|
18
|
+
# NOTEBOOKLM_DEBUG_RPC=1
|
|
19
|
+
|
|
20
|
+
# =============================================================================
|
|
21
|
+
# E2E Testing Configuration
|
|
22
|
+
# =============================================================================
|
|
23
|
+
|
|
24
|
+
# Required for E2E tests: Your READ-ONLY test notebook ID
|
|
25
|
+
# Create a notebook at https://notebooklm.google.com with:
|
|
26
|
+
# - Multiple sources (text, URL, PDF, etc.)
|
|
27
|
+
# - Some pre-generated artifacts (audio, quiz, etc.)
|
|
28
|
+
# Copy the notebook ID from the URL: notebooklm.google.com/notebook/YOUR_ID
|
|
29
|
+
# This notebook is used for READ-ONLY tests (list, get, download operations)
|
|
30
|
+
NOTEBOOKLM_READ_ONLY_NOTEBOOK_ID=your-notebook-id-here
|
|
31
|
+
|
|
32
|
+
# Optional: Generation test notebook ID
|
|
33
|
+
# If not set, a notebook will be auto-created and its ID stored in
|
|
34
|
+
# NOTEBOOKLM_HOME/generation_notebook_id for reuse across test runs.
|
|
35
|
+
# NOTEBOOKLM_GENERATION_NOTEBOOK_ID=your-generation-notebook-id
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
name: Nightly E2E Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
schedule:
|
|
5
|
+
# Run at 6 AM UTC daily (10 PM PST / 1 AM EST)
|
|
6
|
+
- cron: '0 6 * * *'
|
|
7
|
+
workflow_dispatch: # Allow manual trigger
|
|
8
|
+
|
|
9
|
+
concurrency:
|
|
10
|
+
group: ${{ github.workflow }}
|
|
11
|
+
cancel-in-progress: true
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
e2e:
|
|
15
|
+
name: E2E Tests
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
# Only run on main repo (not forks) due to secrets requirement
|
|
18
|
+
if: github.repository == 'teng-lin/notebooklm-py'
|
|
19
|
+
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v4
|
|
22
|
+
|
|
23
|
+
- name: Set up Python
|
|
24
|
+
uses: actions/setup-python@v5
|
|
25
|
+
with:
|
|
26
|
+
python-version: "3.12"
|
|
27
|
+
cache: 'pip'
|
|
28
|
+
|
|
29
|
+
- name: Install dependencies
|
|
30
|
+
run: |
|
|
31
|
+
python -m pip install --upgrade pip
|
|
32
|
+
pip install -e ".[all]"
|
|
33
|
+
|
|
34
|
+
- name: Get Playwright version
|
|
35
|
+
id: playwright-version
|
|
36
|
+
run: |
|
|
37
|
+
echo "version=$(pip show playwright | grep '^Version:' | cut -d' ' -f2)" >> $GITHUB_OUTPUT
|
|
38
|
+
|
|
39
|
+
- name: Cache Playwright browsers
|
|
40
|
+
uses: actions/cache@v4
|
|
41
|
+
with:
|
|
42
|
+
path: ~/.cache/ms-playwright
|
|
43
|
+
key: playwright-ubuntu-latest-${{ steps.playwright-version.outputs.version }}
|
|
44
|
+
|
|
45
|
+
- name: Install Playwright browsers and dependencies
|
|
46
|
+
run: |
|
|
47
|
+
playwright install chromium
|
|
48
|
+
playwright install-deps
|
|
49
|
+
|
|
50
|
+
- name: Debug - Print notebook IDs
|
|
51
|
+
env:
|
|
52
|
+
NOTEBOOKLM_READ_ONLY_NOTEBOOK_ID: ${{ secrets.NOTEBOOKLM_READ_ONLY_NOTEBOOK_ID }}
|
|
53
|
+
NOTEBOOKLM_GENERATION_NOTEBOOK_ID: ${{ secrets.NOTEBOOKLM_GENERATION_NOTEBOOK_ID }}
|
|
54
|
+
run: |
|
|
55
|
+
echo "READ_ONLY_NOTEBOOK_ID: $NOTEBOOKLM_READ_ONLY_NOTEBOOK_ID"
|
|
56
|
+
echo "GENERATION_NOTEBOOK_ID: $NOTEBOOKLM_GENERATION_NOTEBOOK_ID"
|
|
57
|
+
echo "READ_ONLY length: ${#NOTEBOOKLM_READ_ONLY_NOTEBOOK_ID}"
|
|
58
|
+
echo "GENERATION length: ${#NOTEBOOKLM_GENERATION_NOTEBOOK_ID}"
|
|
59
|
+
|
|
60
|
+
- name: Run E2E tests
|
|
61
|
+
env:
|
|
62
|
+
NOTEBOOKLM_AUTH_JSON: ${{ secrets.NOTEBOOKLM_AUTH_JSON }}
|
|
63
|
+
NOTEBOOKLM_READ_ONLY_NOTEBOOK_ID: ${{ secrets.NOTEBOOKLM_READ_ONLY_NOTEBOOK_ID }}
|
|
64
|
+
NOTEBOOKLM_GENERATION_NOTEBOOK_ID: ${{ secrets.NOTEBOOKLM_GENERATION_NOTEBOOK_ID }}
|
|
65
|
+
run: pytest tests/e2e -m "not variants" -s -v --tb=short
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
build-and-publish:
|
|
10
|
+
name: Build and publish to PyPI
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
permissions:
|
|
13
|
+
id-token: write
|
|
14
|
+
contents: read
|
|
15
|
+
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- name: Set up Python 3.12
|
|
20
|
+
uses: actions/setup-python@v5
|
|
21
|
+
with:
|
|
22
|
+
python-version: "3.12"
|
|
23
|
+
|
|
24
|
+
- name: Install build tools
|
|
25
|
+
run: |
|
|
26
|
+
python -m pip install --upgrade pip
|
|
27
|
+
pip install build
|
|
28
|
+
|
|
29
|
+
- name: Build package
|
|
30
|
+
run: |
|
|
31
|
+
python -m build
|
|
32
|
+
|
|
33
|
+
- name: Publish to PyPI
|
|
34
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
name: Test
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
concurrency:
|
|
10
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
11
|
+
cancel-in-progress: true
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
quality:
|
|
15
|
+
name: Code Quality
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
|
|
20
|
+
- name: Set up Python
|
|
21
|
+
uses: actions/setup-python@v5
|
|
22
|
+
with:
|
|
23
|
+
python-version: "3.12"
|
|
24
|
+
cache: 'pip'
|
|
25
|
+
|
|
26
|
+
- name: Install dependencies
|
|
27
|
+
run: |
|
|
28
|
+
python -m pip install --upgrade pip
|
|
29
|
+
pip install -e ".[all]"
|
|
30
|
+
|
|
31
|
+
- name: Run linting
|
|
32
|
+
run: ruff check src/ tests/
|
|
33
|
+
|
|
34
|
+
- name: Check formatting
|
|
35
|
+
run: ruff format --check src/ tests/
|
|
36
|
+
|
|
37
|
+
- name: Run type checking
|
|
38
|
+
run: mypy src/notebooklm --ignore-missing-imports
|
|
39
|
+
|
|
40
|
+
test:
|
|
41
|
+
name: Test (${{ matrix.os }}, Python ${{ matrix.python-version }})
|
|
42
|
+
runs-on: ${{ matrix.os }}
|
|
43
|
+
needs: quality
|
|
44
|
+
strategy:
|
|
45
|
+
fail-fast: false
|
|
46
|
+
matrix:
|
|
47
|
+
os: [ubuntu-latest, macos-latest]
|
|
48
|
+
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
|
|
49
|
+
|
|
50
|
+
steps:
|
|
51
|
+
- uses: actions/checkout@v4
|
|
52
|
+
|
|
53
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
54
|
+
uses: actions/setup-python@v5
|
|
55
|
+
with:
|
|
56
|
+
python-version: ${{ matrix.python-version }}
|
|
57
|
+
cache: 'pip'
|
|
58
|
+
|
|
59
|
+
- name: Install dependencies
|
|
60
|
+
run: |
|
|
61
|
+
python -m pip install --upgrade pip
|
|
62
|
+
pip install -e ".[all]"
|
|
63
|
+
|
|
64
|
+
- name: Get Playwright version
|
|
65
|
+
id: playwright-version
|
|
66
|
+
run: |
|
|
67
|
+
echo "version=$(pip show playwright | grep '^Version:' | cut -d' ' -f2)" >> $GITHUB_OUTPUT
|
|
68
|
+
|
|
69
|
+
- name: Cache Playwright browsers
|
|
70
|
+
uses: actions/cache@v4
|
|
71
|
+
with:
|
|
72
|
+
path: ~/.cache/ms-playwright
|
|
73
|
+
key: playwright-${{ matrix.os }}-${{ steps.playwright-version.outputs.version }}
|
|
74
|
+
|
|
75
|
+
- name: Install Playwright browsers
|
|
76
|
+
run: playwright install chromium
|
|
77
|
+
|
|
78
|
+
- name: Install Playwright system dependencies (Linux)
|
|
79
|
+
if: runner.os == 'Linux'
|
|
80
|
+
run: playwright install-deps
|
|
81
|
+
|
|
82
|
+
- name: Run tests with coverage
|
|
83
|
+
run: pytest --cov=src/notebooklm --cov-report=term-missing --cov-fail-under=70
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
name: Verify Generated Artifacts
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
schedule:
|
|
5
|
+
# Run at 8 AM UTC daily (2 hours after nightly e2e tests)
|
|
6
|
+
- cron: '0 8 * * *'
|
|
7
|
+
workflow_dispatch: # Allow manual trigger
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
verify:
|
|
11
|
+
name: Verify Artifacts
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
if: github.repository == 'teng-lin/notebooklm-py'
|
|
14
|
+
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- name: Set up Python
|
|
19
|
+
uses: actions/setup-python@v5
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.12"
|
|
22
|
+
cache: 'pip'
|
|
23
|
+
|
|
24
|
+
- name: Install dependencies
|
|
25
|
+
run: |
|
|
26
|
+
python -m pip install --upgrade pip
|
|
27
|
+
pip install -e "."
|
|
28
|
+
|
|
29
|
+
- name: Verify artifacts exist
|
|
30
|
+
env:
|
|
31
|
+
NOTEBOOKLM_AUTH_JSON: ${{ secrets.NOTEBOOKLM_AUTH_JSON }}
|
|
32
|
+
NOTEBOOKLM_GENERATION_NOTEBOOK_ID: ${{ secrets.NOTEBOOKLM_GENERATION_NOTEBOOK_ID }}
|
|
33
|
+
run: |
|
|
34
|
+
python -c "
|
|
35
|
+
import asyncio
|
|
36
|
+
import os
|
|
37
|
+
import sys
|
|
38
|
+
from notebooklm import NotebookLMClient
|
|
39
|
+
|
|
40
|
+
# Type ID to display name mapping
|
|
41
|
+
TYPE_NAMES = {
|
|
42
|
+
1: 'Audio',
|
|
43
|
+
2: 'Report', # Study Guide, Briefing Doc, Blog Post
|
|
44
|
+
3: 'Video',
|
|
45
|
+
4: 'Quiz/Flashcards',
|
|
46
|
+
5: 'Mind Map',
|
|
47
|
+
7: 'Infographic',
|
|
48
|
+
8: 'Slide Deck',
|
|
49
|
+
9: 'Data Table',
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
# Expected type IDs from generation tests
|
|
53
|
+
# Note: Type 2 is Reports (study guide), Type 4 is Quiz+Flashcards
|
|
54
|
+
EXPECTED_TYPES = {1, 2, 3, 4, 5, 7, 8, 9}
|
|
55
|
+
|
|
56
|
+
async def verify():
|
|
57
|
+
async with await NotebookLMClient.from_storage() as client:
|
|
58
|
+
nb_id = os.environ['NOTEBOOKLM_GENERATION_NOTEBOOK_ID']
|
|
59
|
+
print(f'Checking notebook: {nb_id}')
|
|
60
|
+
|
|
61
|
+
# List artifacts
|
|
62
|
+
artifacts = await client.artifacts.list(nb_id)
|
|
63
|
+
print(f'\nTotal artifacts: {len(artifacts)}')
|
|
64
|
+
|
|
65
|
+
# Group by type and status
|
|
66
|
+
by_type = {}
|
|
67
|
+
for a in artifacts:
|
|
68
|
+
key = a.artifact_type
|
|
69
|
+
if key not in by_type:
|
|
70
|
+
by_type[key] = []
|
|
71
|
+
by_type[key].append(a)
|
|
72
|
+
|
|
73
|
+
print('\nArtifacts by type:')
|
|
74
|
+
for t in sorted(by_type.keys()):
|
|
75
|
+
items = by_type[t]
|
|
76
|
+
type_name = TYPE_NAMES.get(t, f'Unknown({t})')
|
|
77
|
+
print(f' {type_name} (type {t}): {len(items)}')
|
|
78
|
+
for a in items:
|
|
79
|
+
status = a.status or 'unknown'
|
|
80
|
+
variant_info = f', variant={a.variant}' if a.variant else ''
|
|
81
|
+
print(f' - {a.title} ({status}{variant_info})')
|
|
82
|
+
|
|
83
|
+
# Check expected types
|
|
84
|
+
found = set(by_type.keys())
|
|
85
|
+
missing = EXPECTED_TYPES - found
|
|
86
|
+
|
|
87
|
+
print(f'\nExpected types: {len(EXPECTED_TYPES)}')
|
|
88
|
+
print(f'Found types: {len(found)}')
|
|
89
|
+
|
|
90
|
+
if missing:
|
|
91
|
+
missing_names = [TYPE_NAMES.get(t, str(t)) for t in missing]
|
|
92
|
+
print(f'\nWARNING: Missing artifact types: {missing_names}')
|
|
93
|
+
|
|
94
|
+
# Check for completed artifacts
|
|
95
|
+
completed = sum(1 for a in artifacts if a.status == 'completed')
|
|
96
|
+
processing = sum(1 for a in artifacts if a.status == 'processing')
|
|
97
|
+
failed = sum(1 for a in artifacts if a.status == 'failed')
|
|
98
|
+
|
|
99
|
+
print(f'\nStatus summary:')
|
|
100
|
+
print(f' Completed: {completed}')
|
|
101
|
+
print(f' Processing: {processing}')
|
|
102
|
+
print(f' Failed: {failed}')
|
|
103
|
+
|
|
104
|
+
# List notes
|
|
105
|
+
notes = await client.notes.list(nb_id)
|
|
106
|
+
print(f'\nTotal notes: {len(notes)}')
|
|
107
|
+
for n in notes[:10]:
|
|
108
|
+
print(f' - {n.title or \"(untitled)\"}')
|
|
109
|
+
if len(notes) > 10:
|
|
110
|
+
print(f' ... and {len(notes) - 10} more')
|
|
111
|
+
|
|
112
|
+
# Fail if too many failures or no artifacts at all
|
|
113
|
+
if len(artifacts) == 0:
|
|
114
|
+
print('\nERROR: No artifacts found!')
|
|
115
|
+
sys.exit(1)
|
|
116
|
+
if failed > len(artifacts) // 2:
|
|
117
|
+
print(f'\nERROR: Too many failed artifacts ({failed}/{len(artifacts)})')
|
|
118
|
+
sys.exit(1)
|
|
119
|
+
|
|
120
|
+
print('\nVerification complete!')
|
|
121
|
+
|
|
122
|
+
asyncio.run(verify())
|
|
123
|
+
"
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
*.class
|
|
4
|
+
.venv/
|
|
5
|
+
env/
|
|
6
|
+
venv/
|
|
7
|
+
.pytest_cache/
|
|
8
|
+
.coverage
|
|
9
|
+
htmlcov/
|
|
10
|
+
dist/
|
|
11
|
+
build/
|
|
12
|
+
*.egg-info/
|
|
13
|
+
.DS_Store
|
|
14
|
+
.env
|
|
15
|
+
.notebooklm/
|
|
16
|
+
captured_rpcs/
|
|
17
|
+
.worktrees/
|
|
18
|
+
.worktree/
|
|
19
|
+
.sisyphus/
|
|
20
|
+
.claude/
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
Guidelines for AI agents working on `notebooklm-py`.
|
|
4
|
+
|
|
5
|
+
**IMPORTANT:** Follow documentation rules in [CONTRIBUTING.md](CONTRIBUTING.md) - especially the file creation and naming conventions.
|
|
6
|
+
|
|
7
|
+
## Quick Reference
|
|
8
|
+
|
|
9
|
+
See [CLAUDE.md](CLAUDE.md) for full project context. Essential commands:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
source .venv/bin/activate # Always activate venv first
|
|
13
|
+
pytest # Run tests
|
|
14
|
+
pip install -e ".[all]" # Install in dev mode
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Code Style Guidelines
|
|
18
|
+
|
|
19
|
+
### Type Annotations (Python 3.10+)
|
|
20
|
+
```python
|
|
21
|
+
def process(items: list[str]) -> dict[str, Any]: ...
|
|
22
|
+
async def query(notebook_id: str, source_ids: Optional[list[str]] = None): ...
|
|
23
|
+
|
|
24
|
+
# Use TYPE_CHECKING for circular imports
|
|
25
|
+
from typing import TYPE_CHECKING
|
|
26
|
+
if TYPE_CHECKING:
|
|
27
|
+
from ..api_client import NotebookLMClient
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Async Patterns
|
|
31
|
+
```python
|
|
32
|
+
# All client methods are async - use namespaced APIs
|
|
33
|
+
async with await NotebookLMClient.from_storage() as client:
|
|
34
|
+
notebooks = await client.notebooks.list()
|
|
35
|
+
await client.sources.add_url(nb_id, url)
|
|
36
|
+
result = await client.chat.ask(nb_id, question)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Data Structures
|
|
40
|
+
```python
|
|
41
|
+
@dataclass
|
|
42
|
+
class Notebook:
|
|
43
|
+
id: str
|
|
44
|
+
title: str
|
|
45
|
+
created_at: Optional[datetime] = None
|
|
46
|
+
|
|
47
|
+
@classmethod
|
|
48
|
+
def from_api_response(cls, data: list[Any]) -> "Notebook": ...
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Enums for Constants
|
|
52
|
+
```python
|
|
53
|
+
class RPCMethod(str, Enum):
|
|
54
|
+
LIST_NOTEBOOKS = "wXbhsf"
|
|
55
|
+
|
|
56
|
+
class AudioFormat(int, Enum):
|
|
57
|
+
DEEP_DIVE = 1
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Error Handling
|
|
61
|
+
```python
|
|
62
|
+
class RPCError(Exception):
|
|
63
|
+
def __init__(self, message: str, rpc_id: Optional[str] = None, code: Optional[Any] = None):
|
|
64
|
+
self.rpc_id, self.code = rpc_id, code
|
|
65
|
+
super().__init__(message)
|
|
66
|
+
|
|
67
|
+
raise RPCError(f"No result found for RPC ID: {rpc_id}", rpc_id=rpc_id)
|
|
68
|
+
raise ValueError(f"Invalid YouTube URL: {url}") # For validation
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Docstrings
|
|
72
|
+
```python
|
|
73
|
+
def decode_response(raw_response: str, rpc_id: str, allow_null: bool = False) -> Any:
|
|
74
|
+
"""Complete decode pipeline: strip prefix -> parse chunks -> extract result.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
raw_response: Raw response text from batchexecute
|
|
78
|
+
rpc_id: RPC method ID to extract result for
|
|
79
|
+
allow_null: If True, return None instead of raising when null
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
Decoded result data
|
|
83
|
+
|
|
84
|
+
Raises:
|
|
85
|
+
RPCError: If RPC returned an error or result not found
|
|
86
|
+
"""
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Testing Patterns
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
# Class-based for related tests
|
|
93
|
+
class TestDecodeResponse:
|
|
94
|
+
def test_full_decode_pipeline(self): ...
|
|
95
|
+
|
|
96
|
+
# Markers
|
|
97
|
+
@pytest.mark.e2e # End-to-end (requires auth)
|
|
98
|
+
@pytest.mark.slow # Long-running (audio/video)
|
|
99
|
+
@pytest.mark.asyncio # Async tests
|
|
100
|
+
|
|
101
|
+
# Async tests
|
|
102
|
+
@pytest.mark.asyncio
|
|
103
|
+
async def test_list_notebooks(self, client):
|
|
104
|
+
notebooks = await client.notebooks.list()
|
|
105
|
+
assert isinstance(notebooks, list)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Do NOT
|
|
109
|
+
|
|
110
|
+
- Suppress type errors with `# type: ignore`
|
|
111
|
+
- Commit `.env` files or credentials
|
|
112
|
+
- Add dependencies without updating `pyproject.toml`
|
|
113
|
+
- Change RPC method IDs without verifying via network capture
|
|
114
|
+
- Delete or modify e2e tests without running them
|
|
115
|
+
- Create documentation files without following CONTRIBUTING.md rules
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.1.2] - 2026-01-10
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- **Ruff linter/formatter** - Added to development workflow with pre-commit hooks and CI integration
|
|
14
|
+
- **Multi-version testing** - Docker-based test runner script for Python 3.10-3.14 (`/matrix` skill)
|
|
15
|
+
- **Artifact verification workflow** - New CI workflow runs 2 hours after nightly tests to verify generated artifacts
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
- **Python version support** - Now supports Python 3.10-3.14 (dropped 3.9)
|
|
19
|
+
- **CI authentication** - Use `NOTEBOOKLM_AUTH_JSON` environment variable (inline JSON, no file writes)
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
- **E2E test cleanup** - Generation notebook fixture now only cleans artifacts once per session (was deleting artifacts between tests)
|
|
23
|
+
- **Nightly CI** - Fixed pytest marker from `-m e2e` to `-m "not variants"` (e2e marker didn't exist)
|
|
24
|
+
- macOS CI fix for Playwright version extraction (grep pattern anchoring)
|
|
25
|
+
- Python 3.10 test compatibility with mock.patch resolution
|
|
26
|
+
|
|
27
|
+
### Documentation
|
|
28
|
+
- Claude Code skill: parallel agent safety guidance
|
|
29
|
+
- Claude Code skill: timeout recommendations for all artifact types
|
|
30
|
+
- Claude Code skill: clarified `-n` vs `--notebook` flag availability
|
|
31
|
+
|
|
32
|
+
## [0.1.1] - 2026-01-08
|
|
33
|
+
|
|
34
|
+
### Added
|
|
35
|
+
- `NOTEBOOKLM_HOME` environment variable for custom storage location
|
|
36
|
+
- `NOTEBOOKLM_AUTH_JSON` environment variable for inline authentication (CI/CD friendly)
|
|
37
|
+
- Claude Code skill installation via `notebooklm skill install`
|
|
38
|
+
|
|
39
|
+
### Fixed
|
|
40
|
+
- Infographic generation parameter structure
|
|
41
|
+
- Mind map artifacts now persist as notes after generation
|
|
42
|
+
- Artifact export with proper ExportType enum handling
|
|
43
|
+
- Skill install path resolution for package data
|
|
44
|
+
|
|
45
|
+
### Documentation
|
|
46
|
+
- PyPI release checklist
|
|
47
|
+
- Streamlined README
|
|
48
|
+
- E2E test fixture documentation
|
|
49
|
+
|
|
50
|
+
## [0.1.0] - 2026-01-06
|
|
51
|
+
|
|
52
|
+
### Added
|
|
53
|
+
- Initial release of `notebooklm-py` - unofficial Python client for Google NotebookLM
|
|
54
|
+
- Full notebook CRUD operations (create, list, rename, delete)
|
|
55
|
+
- **Research polling CLI commands** for LLM agent workflows:
|
|
56
|
+
- `notebooklm research status` - Check research progress (non-blocking)
|
|
57
|
+
- `notebooklm research wait --import-all` - Wait for completion and import sources
|
|
58
|
+
- `notebooklm source add-research --no-wait` - Start deep research without blocking
|
|
59
|
+
- **Multi-artifact downloads** with intelligent selection:
|
|
60
|
+
- `download audio`, `download video`, `download infographic`, `download slide-deck`
|
|
61
|
+
- Multiple artifact selection (--all flag)
|
|
62
|
+
- Smart defaults and intelligent filtering (--latest, --earliest, --name, --artifact-id)
|
|
63
|
+
- File/directory conflict handling (--force, --no-clobber, auto-rename)
|
|
64
|
+
- Preview mode (--dry-run) and structured output (--json)
|
|
65
|
+
- Source management:
|
|
66
|
+
- Add URL sources (with YouTube transcript support)
|
|
67
|
+
- Add text sources
|
|
68
|
+
- Add file sources (PDF, TXT, MD, DOCX) via native upload
|
|
69
|
+
- Delete sources
|
|
70
|
+
- Rename sources
|
|
71
|
+
- Studio artifact generation:
|
|
72
|
+
- Audio overviews (podcasts) with 4 formats and 3 lengths
|
|
73
|
+
- Video overviews with 9 visual styles
|
|
74
|
+
- Quizzes and flashcards
|
|
75
|
+
- Infographics, slide decks, and data tables
|
|
76
|
+
- Study guides, briefing docs, and reports
|
|
77
|
+
- Query/chat interface with conversation history support
|
|
78
|
+
- Research agents (Fast and Deep modes)
|
|
79
|
+
- Artifact downloads (audio, video, infographics, slides)
|
|
80
|
+
- CLI with 27 commands
|
|
81
|
+
- Comprehensive documentation (API, RPC, examples)
|
|
82
|
+
- 96 unit tests (100% passing)
|
|
83
|
+
- E2E tests for all major features
|
|
84
|
+
|
|
85
|
+
### Fixed
|
|
86
|
+
- Audio overview instructions parameter now properly supported at RPC position [6][1][0]
|
|
87
|
+
- Quiz and flashcard distinction via title-based filtering
|
|
88
|
+
- Package renamed from `notebooklm-automation` to `notebooklm`
|
|
89
|
+
- CLI module renamed from `cli.py` to `notebooklm_cli.py`
|
|
90
|
+
- Removed orphaned `cli_query.py` file
|
|
91
|
+
|
|
92
|
+
### ⚠️ Beta Release Notice
|
|
93
|
+
|
|
94
|
+
This is the initial public release of `notebooklm-py`. While core functionality is tested and working, please note:
|
|
95
|
+
|
|
96
|
+
- **RPC Protocol Fragility**: This library uses undocumented Google APIs. Method IDs can change without notice, potentially breaking functionality. See [Troubleshooting](docs/troubleshooting.md) for debugging guidance.
|
|
97
|
+
- **Unofficial Status**: This is not affiliated with or endorsed by Google.
|
|
98
|
+
- **API Stability**: The Python API may change in future releases as we refine the interface.
|
|
99
|
+
|
|
100
|
+
### Known Issues
|
|
101
|
+
|
|
102
|
+
- **RPC method IDs may change**: Google can update their internal APIs at any time, breaking this library. Check the [RPC Capture](docs/reference/internals/rpc-capture.md) for how to identify and update method IDs.
|
|
103
|
+
- **Rate limiting**: Heavy usage may trigger Google's rate limits. Add delays between bulk operations.
|
|
104
|
+
- **Authentication expiry**: CSRF tokens expire after some time. Re-run `notebooklm login` if you encounter auth errors.
|
|
105
|
+
- **Large file uploads**: Files over 50MB may fail or timeout. Split large documents if needed.
|
|
106
|
+
|
|
107
|
+
[Unreleased]: https://github.com/teng-lin/notebooklm-py/compare/v0.1.2...HEAD
|
|
108
|
+
[0.1.2]: https://github.com/teng-lin/notebooklm-py/compare/v0.1.1...v0.1.2
|
|
109
|
+
[0.1.1]: https://github.com/teng-lin/notebooklm-py/compare/v0.1.0...v0.1.1
|
|
110
|
+
[0.1.0]: https://github.com/teng-lin/notebooklm-py/releases/tag/v0.1.0
|