Python interface for the Joplin client and server API
MPL-2.0 License
Python interface for the Joplin data API (client) and the Joplin server API.
Client API Wrapper | Server API Wrapper | |
---|---|---|
Supported | All functions from the data API | Some reverse engineered functions with a similar interface like the client API wrapper. See the example below and the source code for details. |
Not Supported | - | - Encryption - Some functions that were either to complex or I didn't see a use for automation. |
From pypi:
pip install joppy
From source:
git clone https://github.com/marph91/joppy.git
cd joppy
pip install .
Please backup your data before use!
add_<type>()
: Create a new element.delete_<type>()
: Delete an element by ID.get_<type>()
: Get an element by ID.get_all_<type>()
: Get all elements of a kind.modify_<type>()
: Modify an elements property by ID.search_all()
: Search elements using joplins search engine.For details, consult the implementation, joplin documentation or create an issue.
Start joplin and get your API token. Click to expand the examples.
from joppy.client_api import ClientApi
# Create a new Api instance.
api = ClientApi(token=YOUR_TOKEN)
# Get all notes. Note that this method calls get_notes() multiple times to assemble the unpaginated result.
notes = api.get_all_notes()
from joppy.client_api import ClientApi
# Create a new Api instance.
api = ClientApi(token=YOUR_TOKEN)
# Add a notebook.
notebook_id = api.add_notebook(title="My first notebook")
# Add a note in the previously created notebook.
note_id = api.add_note(title="My first note", body="With some content", parent_id=notebook_id)
# Add a tag, that is not yet attached to a note.
tag_id = api.add_tag(title="introduction")
# Link the tag to the note.
api.add_tag_to_note(tag_id=tag_id, note_id=note_id)
from joppy.client_api import ClientApi
from joppy import tools
# Create a new Api instance.
api = ClientApi(token=YOUR_TOKEN)
# Add a notebook.
notebook_id = api.add_notebook(title="My first notebook")
# Option 1: Add a note with an image data URL. This works only for images.
image_data = tools.encode_base64("path/to/image.png")
api.add_note(
title="My first note",
image_data_url=f"data:image/png;base64,{image_data}",
)
# Option 2: Create note and resource separately. Link them later. This works for arbitrary attachments.
note_id = api.add_note(title="My second note")
resource_id = api.add_resource(filename="path/to/image.png", title="My first resource")
api.add_resource_to_note(resource_id=resource_id, note_id=note_id)
Inspired by https://discourse.joplinapp.org/t/bulk-tag-delete-python-script/5497/1.
import re
from joppy.client_api import ClientApi
# Create a new Api instance.
api = ClientApi(token=YOUR_TOKEN)
# Iterate through all tags.
for tag in api.get_all_tags():
# Delete all tags that match the regex. I. e. start with "!".
if re.search("^!", tag.title) is not None:
api.delete_tag(tag.id)
Reference: https://discourse.joplinapp.org/t/prune-empty-tags-from-web-clipper/36194
from joppy.client_api import ClientApi
# Create a new Api instance.
api = ClientApi(token=YOUR_TOKEN)
for tag in api.get_all_tags():
notes_for_tag = api.get_all_notes(tag_id=tag.id)
if len(notes_for_tag) == 0:
print("Deleting tag:", tag.title)
api.delete_tag(tag.id)
Reference: https://www.reddit.com/r/joplinapp/comments/pozric/batch_remove_spaces_from_all_tags/
import re
from joppy.client_api import ClientApi
# Create a new Api instance.
api = ClientApi(token=YOUR_TOKEN)
# Define the conversion function.
def to_camel_case(name: str) -> str:
name = re.sub(r"(_|-)+", " ", name).title().replace(" ", "")
return "".join([name[0].lower(), name[1:]])
# Iterate through all tags and apply the conversion.
for tag in api.get_all_tags():
api.modify_tag(id_=tag.id, title=to_camel_case(tag.title))
Inspired by https://discourse.joplinapp.org/t/joplin-vacuum-a-python-script-to-remove-orphaned-resources/19742. Note: The note history is not considered. See: https://discourse.joplinapp.org/t/joplin-vacuum-a-python-script-to-remove-orphaned-resources/19742/13.
import re
from joppy.client_api import ClientApi
# Create a new Api instance.
api = ClientApi(token=YOUR_TOKEN)
# Getting the referenced resource directly doesn't work:
# https://github.com/laurent22/joplin/issues/4535
# So we have to find the referenced resources by regex.
# Iterate through all notes and find the referenced resources.
referenced_resources = set()
for note in api.get_all_notes(fields="id,body"):
matches = re.findall(r"\[.*\]\(:.*\/([A-Za-z0-9]{32})\)", note.body)
referenced_resources.update(matches)
assert len(referenced_resources) > 0, "sanity check"
for resource in api.get_all_resources():
if resource.id not in referenced_resources:
print("Deleting resource:", resource.title)
api.delete_resource(resource.id)
For more usage examples, check the example scripts or tests.
The server API should work similarly to the client API in most cases. Be aware that the server API is experimental and may break at any time. I can't provide any help at sync issues or lost data. Make sure you have a backup and know how to restore it.
from joppy.server_api import ServerApi
# Create a new Api instance.
api = ServerApi(user="admin@localhost", password="admin", url="http://localhost:22300")
# Acquire a lock.
with api.sync_lock():
# Add a notebook.
notebook_id = api.add_notebook(title="My first notebook")
# Add a note in the previously created notebook.
note_id = api.add_note(title="My first note", body="With some content", parent_id=notebook_id)
Before using joppy, you should check the Joplin plugins. They are probably more convenient. However, if you need a new feature or just want to code in python, you can use joppy.
App | Description |
---|---|
jimmy | A tool to import your notes to Joplin |
joplin-sticky-notes | Stick your Joplin notes to the desktop |
joplin-vieweb | A simple web viewer for Joplin |
Script | Description |
---|---|
custom_export.py | Export resources next to notes, instead of a separate folder. |
note_export.py | Export notes to any format supported by pandoc. |
note_stats.py | Get some simple statistics about your notes, based on nltk. |
note_tree_export.py | Joplin only supports PDF export of a single note. This script allows to export one, multiple or all notebooks to PDF or TXT. |
visualize_note_locations.py | Visualize the locations of your notes. |
joplin-ui-tests | System tests for the joplin desktop app. Based on selenium. |
To run the tests, some additional system packages and python modules are needed. After installing them, just run:
python -m unittest
It's possible to configure the test run via some environment variables:
SLOW_TESTS
: Set this variable to run the slow tests. Default not set.API_TOKEN
: Set this variable if there is already a joplin instance running. Don't use your default joplin profile! By default, a joplin instance is started inside xvfb. This takes some time, but works for CI.from joppy.client_api import ClientApi
instead of from joppy.client_api import ClientApi
now.from joppy.server_api import ServerApi
.markup_language
to an appropriate enum type.todo_completed
and todo_due
. They are a unix timestamp, not a bool.note.id
instead of note["id"]
for example.setup.cfg
.