{"id":39440023,"url":"https://github.com/prizz/apple-notes-exporter-rs","last_synced_at":"2026-01-20T16:55:48.469Z","repository":{"id":332241161,"uuid":"1133150840","full_name":"pRizz/apple-notes-exporter-rs","owner":"pRizz","description":"A Rust Crate for bulk exporting of documents in Apple Notes","archived":false,"fork":false,"pushed_at":"2026-01-13T04:34:15.000Z","size":11,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-13T05:08:17.017Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pRizz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-13T00:32:38.000Z","updated_at":"2026-01-13T04:34:19.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/pRizz/apple-notes-exporter-rs","commit_stats":null,"previous_names":["prizz/apple-notes-exporter-rs"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/pRizz/apple-notes-exporter-rs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pRizz%2Fapple-notes-exporter-rs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pRizz%2Fapple-notes-exporter-rs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pRizz%2Fapple-notes-exporter-rs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pRizz%2Fapple-notes-exporter-rs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pRizz","download_url":"https://codeload.github.com/pRizz/apple-notes-exporter-rs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pRizz%2Fapple-notes-exporter-rs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28561842,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-19T03:31:16.861Z","status":"ssl_error","status_checked_at":"2026-01-19T03:31:15.069Z","response_time":67,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-01-18T04:18:50.276Z","updated_at":"2026-01-19T05:00:32.758Z","avatar_url":"https://github.com/pRizz.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Apple Notes Exporter\n\n[![crates.io](https://img.shields.io/crates/v/apple-notes-exporter-rs.svg)](https://crates.io/crates/apple-notes-exporter-rs)\n[![docs.rs](https://docs.rs/apple-notes-exporter-rs/badge.svg)](https://docs.rs/apple-notes-exporter-rs)\n[![Repository](https://img.shields.io/badge/repo-github-blue)](https://github.com/pRizz/apple-notes-exporter-rs)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nA library and CLI tool for recursively exporting Apple Notes folders to the file system via AppleScript. This Rust-based tool allows you to export entire folder hierarchies from Apple Notes, creating a mirrored directory structure with each note saved as an HTML file.\n\n## Quick Install\n\nInstall from [crates.io](https://crates.io/crates/apple-notes-exporter-rs) using Cargo:\n\n```bash\ncargo install apple-notes-exporter-rs\n```\n\nOr install directly from GitHub:\n\n```bash\ncargo install --git https://github.com/pRizz/apple-notes-exporter-rs.git\n```\n\n## Features\n\n- Recursive export of Apple Notes folders (including all subfolders and notes)\n- **Automatic image extraction** - embedded base64 images are extracted to separate files\n- List all available folders across all accounts\n- Creates a mirrored directory tree structure\n- Exports each note as an HTML file with images in a companion folder\n- Breadth-first search (BFS) to find folders at any level\n- Support for multiple Apple Notes accounts\n- Simple command-line interface with subcommands\n- Library API for programmatic access\n\n## CLI Installation\n\n### Install from crates.io (Recommended)\n\n```bash\ncargo install apple-notes-exporter-rs\n```\n\n### Install from GitHub\n\nInstall directly from the GitHub repository:\n\n```bash\ncargo install --git https://github.com/pRizz/apple-notes-exporter-rs.git\n```\n\n### Build from Source\n\n```bash\ngit clone --recursive https://github.com/pRizz/apple-notes-exporter-rs.git\ncd apple-notes-exporter-rs\ncargo build --release\n```\n\nThe binary will be available at `target/release/apple-notes-exporter`.\n\n## CLI Usage\n\nThe tool provides three subcommands: `list` (or `ls`), `export`, and `extract-attachments`.\n\n### List Available Folders\n\nList all top-level folders across all Apple Notes accounts:\n\n```bash\napple-notes-exporter list\n# or\napple-notes-exporter ls\n```\n\n### Export a Folder\n\nExport a folder recursively to HTML files. By default, embedded images are automatically extracted to separate files:\n\n```bash\napple-notes-exporter export \u003cFOLDER\u003e \u003cOUTPUT_DIR\u003e\n```\n\nThis creates a structure like:\n\n```\nexports/\n├── My Notes/\n│   ├── Note Title -- abc123.html\n│   ├── Note Title -- abc123-attachments/\n│   │   ├── attachment-001.jpg\n│   │   └── attachment-002.png\n│   └── Another Note -- def456.html\n```\n\nTo skip image extraction (keep images as embedded base64):\n\n```bash\napple-notes-exporter export \"My Notes\" ./exports --no-extract-attachments\n```\n\n### Extract Attachments from Existing Exports\n\nIf you have previously exported notes without extracting images, you can extract them later:\n\n```bash\napple-notes-exporter extract-attachments ./exports\n```\n\n### Examples\n\nList all available folders:\n\n```bash\napple-notes-exporter list   # or: apple-notes-exporter ls\n```\n\nExport a folder (searches all accounts):\n\n```bash\napple-notes-exporter export \"My Notes\" ./exports\n```\n\nExport a folder from a specific account (useful when folder names exist in multiple accounts):\n\n```bash\napple-notes-exporter export \"iCloud:My Notes\" ./exports\napple-notes-exporter export \"Google:Work Notes\" ./exports\n```\n\nExport without extracting images:\n\n```bash\napple-notes-exporter export \"My Notes\" ./exports --no-extract-attachments\n```\n\n## Running from Source\n\nIf you want to run the tool directly from the source code without installing:\n\n```bash\n# Clone the repository with submodules\ngit clone --recursive https://github.com/pRizz/apple-notes-exporter-rs.git\ncd apple-notes-exporter-rs\n\n# List folders\ncargo run -- list   # or: cargo run -- ls\n\n# Export a folder\ncargo run -- export \"My Notes\" ./exports\n```\n\nIf you already cloned without `--recursive`, initialize the submodules:\n\n```bash\ngit submodule update --init --recursive\n```\n\n## Library Usage\n\nAdd the dependency to your `Cargo.toml`:\n\n```toml\n[dependencies]\napple-notes-exporter-rs = \"1.0\"\n```\n\n### Quick Start\n\n```rust\nuse apple_notes_exporter_rs::{list_folders, export_folder, export_folder_from_account};\n\nfn main() -\u003e apple_notes_exporter_rs::Result\u003c()\u003e {\n    // List all available folders (prints to stdout)\n    list_folders()?;\n\n    // Export a folder to a directory (searches all accounts)\n    export_folder(\"My Notes\", \"./exports\")?;\n\n    // Export from a specific account (useful when folder names are duplicated)\n    export_folder_from_account(\"iCloud\", \"Work\", \"./exports\")?;\n    export_folder_from_account(\"Google\", \"Work\", \"./google_exports\")?;\n\n    Ok(())\n}\n```\n\n### Using the Exporter Struct\n\nFor more control, use the `Exporter` struct:\n\n```rust\nuse apple_notes_exporter_rs::Exporter;\n\nfn main() -\u003e apple_notes_exporter_rs::Result\u003c()\u003e {\n    // Create an exporter with the embedded AppleScript\n    let exporter = Exporter::new();\n\n    exporter.list_folders()?;\n\n    // Export and extract images (recommended)\n    let results = exporter.export_folder_with_attachments(\"My Notes\", \"./exports\")?;\n    println!(\"Extracted {} images\", results.iter().map(|r| r.attachments.len()).sum::\u003cusize\u003e());\n\n    // Or export without extracting images\n    exporter.export_folder(\"Work\", \"./work_exports\")?;\n\n    Ok(())\n}\n```\n\n### Using a Custom AppleScript\n\nIf you need to use a modified AppleScript:\n\n```rust\nuse apple_notes_exporter_rs::Exporter;\n\nfn main() -\u003e apple_notes_exporter_rs::Result\u003c()\u003e {\n    let exporter = Exporter::with_script_path(\"./custom_script.applescript\")?;\n\n    exporter.list_folders()?;\n    exporter.export_folder(\"My Notes\", \"./exports\")?;\n\n    Ok(())\n}\n```\n\n### Extracting Attachments from Existing Exports\n\nYou can also extract images from previously exported HTML files:\n\n```rust\nuse apple_notes_exporter_rs::{extract_attachments_from_html, extract_attachments_from_directory};\n\nfn main() -\u003e apple_notes_exporter_rs::Result\u003c()\u003e {\n    // Extract from a single HTML file\n    let result = extract_attachments_from_html(\"./exports/My Note -- abc123.html\")?;\n    println!(\"Extracted {} images\", result.attachments.len());\n\n    // Extract from all HTML files in a directory (recursive)\n    let results = extract_attachments_from_directory(\"./exports\")?;\n    let total: usize = results.iter().map(|r| r.attachments.len()).sum();\n    println!(\"Extracted {total} images from {} files\", results.len());\n\n    Ok(())\n}\n```\n\n### Error Handling\n\nThe library provides a custom `ExportError` type:\n\n```rust\nuse apple_notes_exporter_rs::{export_folder, ExportError};\n\nfn main() {\n    match export_folder(\"My Notes\", \"./exports\") {\n        Ok(()) =\u003e println!(\"Export successful!\"),\n        Err(ExportError::ScriptNotFound(path)) =\u003e {\n            eprintln!(\"Script not found: {}\", path.display());\n        }\n        Err(ExportError::ScriptFailed(code)) =\u003e {\n            eprintln!(\"AppleScript failed with exit code: {}\", code);\n        }\n        Err(e) =\u003e eprintln!(\"Error: {}\", e),\n    }\n}\n```\n\n## How It Works\n\n1. **Folder Search**: The tool uses breadth-first search (BFS) to find the specified folder at any level in your Apple Notes hierarchy (not just top-level folders).\n\n2. **Export Process**: Once found, it recursively exports that folder and all its subfolders, creating a mirrored directory tree.\n\n3. **Output Format**: Each note is exported as an HTML file, preserving the folder structure in the output directory.\n\n4. **Image Extraction**: By default, embedded base64 images in the HTML are extracted to separate files in a companion `\u003cnote-name\u003e-attachments/` folder. The HTML is updated to reference the local files. Supported formats: PNG, JPEG, GIF, WebP, SVG, BMP, TIFF.\n\n5. **Account Handling**: By default, the folder search looks in all accounts. If a folder name exists in multiple accounts, you can specify the account using the `AccountName:FolderName` format.\n\n## Requirements\n\n### macOS Only\n\nThis tool is macOS-specific as it relies on AppleScript to interact with the Notes app. While the library can be compiled on any platform, running it on non-macOS systems will return an error at runtime.\n\n### Automation Permissions\n\n**Important**: This tool requires Automation permissions for the Notes app. You'll need to grant these permissions when you first run the tool:\n\n1. Go to **System Settings** \u003e **Privacy \u0026 Security** \u003e **Automation**\n2. Find the application that invoked the script (e.g., Terminal, iTerm, or Script Editor)\n3. Enable permissions for the **Notes** app\n\nIf permissions are not granted, the export will fail.\n\n## Project Structure\n\n```\napple-notes-exporter-rs/\n├── src/\n│   ├── lib.rs               # Library: export API + attachment extraction\n│   └── main.rs              # CLI application\n├── vendor/\n│   └── apple-notes-exporter/\n│       └── scripts/\n│           └── export_notes.applescript  # AppleScript used for export\n├── Cargo.toml\n└── README.md\n```\n\n## See Also\n\n- [apple-notes-exporter-ts](https://github.com/pRizz/apple-notes-exporter-ts) - A TypeScript/Node.js version of this tool\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.\n\n## Acknowledgments\n\nThis tool uses the AppleScript from the [apple-notes-exporter](https://github.com/pRizz/apple-notes-exporter) project, which is included as a git submodule.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprizz%2Fapple-notes-exporter-rs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fprizz%2Fapple-notes-exporter-rs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprizz%2Fapple-notes-exporter-rs/lists"}