Metadata-Version: 2.4 Name: trilium-py Version: 1.3.9 Summary: Python client for ETAPI of Trilium Note. With some extra features powered by Python :) Home-page: https://github.com/nriver/trilium-py Author: Nriver Author-email: Project-URL: Bug Reports, https://github.com/nriver/trilium-py/issues Project-URL: Funding, https://github.com/nriver/trilium-py Project-URL: Say Thanks!, https://github.com/nriver/trilium-py Project-URL: Source, https://github.com/nriver/trilium-py/ Keywords: trilium,etapi,api client Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: Topic :: Software Development :: Build Tools Classifier: License :: OSI Approved :: GNU Affero General Public License v3 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 Classifier: Programming Language :: Python :: 3.13 Classifier: Programming Language :: Python :: 3 :: Only Requires-Python: >=3.9, <4 Description-Content-Type: text/markdown License-File: LICENSE.txt Requires-Dist: BeautifulSoup4 Requires-Dist: requests Requires-Dist: markdown2[all] Requires-Dist: natsort Requires-Dist: loguru Requires-Dist: pillow Requires-Dist: python-dateutil Requires-Dist: tqdm Dynamic: author Dynamic: classifier Dynamic: description Dynamic: description-content-type Dynamic: home-page Dynamic: keywords Dynamic: license-file Dynamic: project-url Dynamic: requires-dist Dynamic: requires-python Dynamic: summary # ๐ trilium-py
English | ็ฎไฝไธญๆ
Python client for Trilium Note's ETAPI and Web API, with additional advanced features :) [](https://pepy.tech/project/trilium-py) [](https://pypi.org/project/trilium-py) [](https://pypi.org/project/trilium-py) [](https://pypi.python.org/pypi/trilium-py/) [](https://GitHub.com/Naereen/StrapDown.js/graphs/commit-activity) ## ๐ฆฎ Table of Contents * [๐ trilium-py](#-trilium-py) * [๐ฆฎ Table of Contents](#-table-of-contents) * [๐ง Installation](#-installation) * [๐ Initialization](#-initialization) * [ETAPI initialization](#etapi-initialization) * [Web API initialization](#web-api-initialization) * [๐ (Basic) ETAPI Usage](#-basic-etapi-usage) * [๐ Application Information](#-application-information) * [๐ Search note](#-search-note) * [๐ญ Create Note](#-create-note) * [๐ผ๏ธ Create Image note](#๏ธ-create-image-note) * [๐ Get note](#-get-note) * [๐ Update note](#-update-note) * [๐๏ธ Delete note](#๏ธ-delete-note) * [๐ Create note clone/branch](#-create-note-clonebranch) * [๐ Get note clone info](#-get-note-clone-info) * [โ๏ธ Modify note clone info](#๏ธ-modify-note-clone-info) * [โ Delete note clone](#-delete-note-clone) * [๐ Day note](#-day-note) * [๐ค Export note](#-export-note) * [๐ฅ import note](#-import-note) * [๐พ Save revision](#-save-revision) * [๐พ Create data backup](#-create-data-backup) * [๐ท Create attribute](#-create-attribute) * [Get attachment list](#get-attachment-list) * [Get attachment info](#get-attachment-info) * [Update attachment info](#update-attachment-info) * [Get attachment content](#get-attachment-content) * [Update attachment content](#update-attachment-content) * [Create attachment](#create-attachment) * [(Advanced Usage) โ TODO List](#advanced-usage--todo-list) * [Add TODO item](#add-todo-item) * [Check/Uncheck a TODO item](#checkuncheck-a-todo-item) * [Update a TODO item](#update-a-todo-item) * [Delete a TODO item](#delete-a-todo-item) * [Move yesterday's unfinished todo to today](#move-yesterdays-unfinished-todo-to-today) * [Sort todo](#sort-todo) * [(Advanced Usage) ๐ Upload Markdown files](#advanced-usage--upload-markdown-files) * [Upload single Markdown file with images](#upload-single-markdown-file-with-images) * [Disable math formula parsing](#disable-math-formula-parsing) * [Bulk upload Markdown files in a folder](#bulk-upload-markdown-files-in-a-folder) * [Import from VNote](#import-from-vnote) * [Import from Joplin](#import-from-joplin) * [Import from Logseq](#import-from-logseq) * [Import from Obsidian](#import-from-obsidian) * [Import from Youdao Note/ๆ้ไบ็ฌ่ฎฐ](#import-from-youdao-noteๆ้ไบ็ฌ่ฎฐ) * [Import from Turtl](#import-from-turtl) * [Import from other markdown software](#import-from-other-markdown-software) * [Disable math formula parsing for folder import](#disable-math-formula-parsing-for-folder-import) * [(Advanced Usage) ๐จ Beautify notes](#advanced-usage--beautify-notes) * [Beautify a note](#beautify-a-note) * [Beautify a note and its child notes](#beautify-a-note-and-its-child-notes) * [(Advanced Usage) ๐งน Sort note content](#advanced-usage--sort-note-content) * [(Advanced Usage) ๐งน Delete empty new note](#advanced-usage--delete-empty-new-note) * [(Advanced Usage) ๐๏ธ Optimize image size](#advanced-usage-๏ธ-optimize-image-size) * [(Advanced Usage) ๐ Automatically Add Internal Links](#advanced-usage--automatically-add-internal-links) * [Example](#example) * [Excluding Notes from Internal Linking](#excluding-notes-from-internal-linking) * [Special Case: Duplicate Titles](#special-case-duplicate-titles) * [Final Rule: No Self-Linking](#final-rule-no-self-linking) * [Code Samples](#code-samples) * [(Advanced Usage) ๐๐ณ Traverse Note Tree](#advanced-usage--traverse-note-tree) * [(Advanced Usage) ๐๏ธ๐ Periodic TODOs](#advanced-usage-๏ธ-periodic-todos) * [(Basic) Web API Usage](#basic-web-api-usage) * [๐ Get note content](#-get-note-content) * [๐ Protected session / encrypted notes](#-protected-session--encrypted-notes) * [๐ Update note content](#-update-note-content) * [๐ฃ Share note & cancel share note](#-share-note--cancel-share-note) * [๐ ๏ธ Develop](#๏ธ-develop) * [๐ Original OpenAPI Documentation](#-original-openapi-documentation) * [๐ฐ Donation](#-donation) * [๐ Thanks](#-thanks) ## ๐ง Installation ```bash python3 -m pip install trilium-py --user ``` ## ๐ Initialization In the following code example, `ea` stands for ETAPI, and `wa` stands for Web API. Please perform the corresponding initialization process based on whether you need to use the ETAPI or the Web API. ### ETAPI initialization If you have a ETAPI token, change the `server_url` and `token` to yours. ```python from trilium_py.client import ETAPI server_url = 'http://localhost:8080' token = 'YOUR_TOKEN' ea = ETAPI(server_url, token) ``` If you haven't created ETAPI token, you can create one with your password. Please note, you can only see this token once, please save it if you want to reuse the token. ```python from trilium_py.client import ETAPI server_url = 'http://localhost:8080' password = '1234' ea = ETAPI(server_url) token = ea.login(password) print(token) ``` After initialization, you can use Trilium ETAPI with python now. ### Web API initialization You need to login every time you use the web API due to the CSRF limit. ``` from trilium_py.src.trilium_py.web_client import WEBAPI server_url = 'http://localhost:8080' password = '1234' wa = WEBAPI(server_url) wa.login(password) ``` After initialization, you can use Trilium web API with python now. ## ๐ (Basic) ETAPI Usage These are basic function that Trilium's ETAPI provides. Down below are some simple example code to use this package. ### ๐ Application Information To start with, you can get the application information like this. ```python print(ea.app_info()) ``` It should give you the version of your server application and some extra information. ### ๐ Search note Search note with keyword. ```python res = ea.search_note( search="python", ) for x in res['results']: print(x['noteId'], x['title']) ``` Search with regular expression. For example, search and get all child notes under certain note: ```python res = ea.search_note( # regular expression search for note title search="note.title %= '.*'", ancestorNoteId="Parent Note ID", fastSearch=False, orderBy=["title"], limit=100, ) ``` Note: `limit` will not work without `orderBy`. ### ๐ญ Create Note You can create a simple note like this. ```python res = ea.create_note( parentNoteId="root", title="Simple note 1", type="text", content="Simple note example", noteId="note1", dateCreated="2026-01-01 12:34:56.000+0900", ) ``` The `noteId` is not mandatory, if not provided, Trilium will generate a random one. You can retrieve it in the return. `dateCreated` is also not mandatory. It can be used to assist importing notes from other apps, preserving creation date. ```python noteId = res['note']['noteId'] ``` #### ๐ผ๏ธ Create Image note Image note is a special kind of note. You can create an image note with minimal information like this. The `image_file` refers to the path of image. ```python res = ea.create_image_note( parentNoteId="root", title="Image note 1", image_file="shield.png", ) ``` ### ๐ Get note To retrieve the note's content. ```python ea.get_note_content("noteid") ``` You can get a note metadata by its id. ```python ea.get_note(note_id) ``` ### ๐ Update note Update note content ```python ea.update_note_content("noteid", "updated by python") ``` Modify note title ```python ea.patch_note( noteId="noteid", title="Python client moded", ) ``` ### ๐๏ธ Delete note Simply delete a note by id. ```python ea.delete_note("noteid") ``` ### ๐ Create note clone/branch In the ETAPI, this is called a branch, but in the Trilium UI it represents a note clone. Here is an example to create a clone of `note2` under `note1`. ``` res = ea.create_branch( noteId="note2", parentNoteId="note1", ) ``` It will return the note clone info like this: ``` { 'branchId': 'note1_note2', 'noteId': 'note2', 'parentNoteId': 'note1', 'prefix': None, 'notePosition': 10, 'isExpanded': False, 'utcDateModified': '2025-10-21T03:25:16.397Z' } ``` ### ๐ Get note clone info Retrieve details about a specific note clone (branch) by its branchId ``` res = ea.get_branch(branchId="note1_note2") ``` ### โ๏ธ Modify note clone info Update an existing note cloneโs display attributes such as prefix, position, or expansion state ``` res = ea.patch_branch(branchId="note1_note2", notePosition=0, prefix="patched", isExpanded=False) ``` ### โ Delete note clone Remove a note clone (branch) from the tree. ``` res = ea.delete_branch(branchId="note1_note2") ``` ### ๐ Day note You can get the content of a certain date with `get_day_note`. The date string should be in format of "%Y-%m-%d", e.g. " 2022-02-25". ```python ea.get_day_note("2022-02-25") ``` Then set/update a day note with `set_day_note`. The content should be a (html) string. ```python ea.set_day_note(date, new_content) ``` ### ๐ค Export note Export note comes in two formats `html` or `markdown`/`md`. Setting `noteId` to `root` will export all notes. ```python res = ea.export_note( noteId='sK5fn4T6yZRI', format='md', save_path='/home/nate/data/1/test.zip', ) ``` ### ๐ฅ import note This is the built-in feature in trilium. The input file should be a zip file. ```python res = ea.import_note( noteId='sK5fn4T6yZRI', file_path='/home/nate/data/1/test.zip', ) ``` ### ๐พ Save revision Save note revision manually. ``` res = ea.save_revision( noteId='MJzyFRXAVaC9', ) ``` ### ๐พ Create data backup This example will create a database backup file like this `trilium-data/backup/backup-test.db`. ```python res = ea.backup("test") ``` You can use the cron utility in Linux to schedule regular automatic backups. For example, to set up a daily backup at 3: 00 AM, you would use the following cron expression: ```bash 0 3 * * * python /path/to/backup-script.py ``` ### ๐ท Create attribute You can create a tag for a note ```python res = ea.create_attribute( noteId='noteid', type='label', name='name_of_the_tag', value='value_of_the_tag', isInheritable=True ) ``` The `noteId` is not mandatory, if not provided, Trilium will generate a random one. You can retrieve it in the return. ```python noteId = res['note']['noteId'] ``` ### Get attachment list Get all attachments of a single note. ``` res = ea.get_attachments('uMJt0Ajr1CuC') ``` ### Get attachment info Get image title and etc. ```python res = ea.get_attachment('Y5V6pYq6nwXo') ``` ### Update attachment info Change image title and etc. ```python res = ea.update_attachment( attachmentId='2b7pPzqocS1s', title='hello etapi', role='image', mime='image/png' ) ``` ### Get attachment content Get the real image file ```python res = ea.get_attachment_content('icpDE4orQxlI') with open('1.png', 'wb') as f: f.write(res) ``` ### Update attachment content Replace the image with new one ```python res = ea.update_attachment_content('icWqV6zFtE0V', '/home/nate/data/1.png') ``` ### Create attachment Upload a image file as attachment of a note. ```python res = ea.create_attachment( ownerId='8m8luXym5LxT', file_path='/home/nate/data/ksnip_20230630-103509.png', ) ``` ## (Advanced Usage) โ TODO List With the power of Python, I have expanded the basic usage of ETAPI. You can do something with todo list now. ### Add TODO item You can use `add_todo` to add a TODO item, param is the TODO description ```python ea.add_todo("ไนฐๆๅฎๅฎ") ``` ### Check/Uncheck a TODO item param is the index of the TODO item ```python ea.todo_check(0) ea.todo_uncheck(1) ``` ### Update a TODO item Use `update_todo` to update a TODO item description at certain index. ```python ea.update_todo(0, "ๅป็ ๅคดๆด็น่ฏๆก") ``` ### Delete a TODO item Remove a TODO item by its index. ```python ea.delete_todo(1) ``` ### Move yesterday's unfinished todo to today As the title suggests, you can move yesterday's unfinished things to today. Unfinished todo's will be deleted from yesterday's note. ```python ea.move_yesterday_unfinished_todo_to_today() ``` ### Sort todo Sort today's todos, put finished todos to the bottom and keep relative order ``` ea.sort_todo() ``` Sort for some day ``` ea.sort_todo(date="2026-05-26") ``` Sort and push newly finished items to the bottom ``` ea.sort_todo(append_new_done=True) ``` Sort for certain note by note id ``` ea.sort_todo(noteId="fn1DVZBsiQBG") ``` ## (Advanced Usage) ๐ Upload Markdown files ### Upload single Markdown file with images You can import Markdown file with images into Trilium now! Trilium-py will help you to upload the images and fix the links for you! ```python res = ea.upload_md_file( parentNoteId="root", file="./md-demo/manjaro ไฟฎๆนcaps lock.md", hasFrontMatter=False, cleanText=False ) ``` `hasFrontMatter` is optional. If set to true, it is expected that the markdown file has front matter block such as: ```markdown --- title: NoteTitle updated: 2026-01-01 12:45:56Z created: 2026-01-01 12:34:56Z latitude: 10.1234 longitude: 100.1234 altitude: 0.0000 --- ``` `cleanText` is optional. If set to true, it will tidy up the note import, including adding paragraph breaks. ### Disable math formula parsing When uploading Markdown files that contain dollar signs ($) which are not meant to be interpreted as math formulas, you can disable the math formula parsing: ```python res = ea.upload_md_file( parentNoteId="root", file="./md-demo/document_with_dollar_signs.md", parse_math=False, # Disable math formula parsing ) ``` ### Bulk upload Markdown files in a folder You can upload a folder with lots of Markdown files to Trilium and preserve the folder structure! #### Import from VNote Say, upload all the notes from [VNote](https://github.com/vnotex/vnote), simply do this: ```python res = ea.upload_md_folder( parentNoteId="root", mdFolder="~/data/vnotebook/", ignoreFolder=['vx_notebook', 'vx_recycle_bin', 'vx_images', '_v_images'], ) ``` #### Import from Joplin To import from Joplin, first extract your Joplin notes to Markdown + Front Matter: `File > Export All > MD - Markdown + Front Matter` Then run the following snippet, replacing `mdFolder` to your actual exported notes location. ```python res = ea.upload_md_folder( parentNoteId="root", mdFolder="/home/nate/data/joplin_data/", ignoreFolder=['_resources', ], hasFrontMatter=True, cleanText=True ) ``` Importing with Front Matter will ensure consistent note creation time. #### Import from Logseq ```python res = ea.upload_md_folder( parentNoteId="root", mdFolder="/home/nate/data/logseq_data/", ignoreFolder=['assets', 'logseq'], ) ``` #### Import from Obsidian Obsidian has a very unique linking system for files. You should use [obsidian-export ](https://github.com/zoni/obsidian-export) to convert a Obsidian vault to regular Markdown files. Then you should be able to import the note into Trilium with trilium-py. Convert it first. ```bash obsidian-export /path/to/your/vault /out ``` Then import just like a normal markdown, trilium-py will handle the images for you. ```python res = ea.upload_md_folder( parentNoteId="root", mdFolder="E:/data/out", ) ``` #### Import from Youdao Note/ๆ้ไบ็ฌ่ฎฐ Youdao does not provide an export feature anymore. Luckily, you can useprotected note content updated by trilium-py :)
') ``` ### ๐ฃ Share note & cancel share note ```python wa.share_note('your_note_id') wa.cancel_share_note('RfhYrtyQLU8o') ``` ## ๐ ๏ธ Develop Install with pip egg link to make package change without reinstall. ```python python -m pip install --user -e . ``` ## ๐ Original OpenAPI Documentation The original OpenAPI document is [here](https://github.com/zadam/trilium/blob/master/src/etapi/etapi.openapi.yaml). You can open it with [swagger editor](https://editor.swagger.io/). # ๐ฐ Donation If you enjoy using **Trilium-py**, your support would mean a lot! **Ko-fi** [](https://ko-fi.com/nriver) **Alipay**  **WeChat Pay**  # ๐ Thanks Thanks `Matt Wilkie` for donating 10.0 USD!