joppy
joppy copied to clipboard
Python interface for the Joplin data API
joppy
Python interface for the Joplin data API.
:computer: Installation
From pypi:
pip install joppy
From source:
git clone https://github.com/marph91/joppy.git
cd joppy
pip install .
:wrench: Usage
General function description
-
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.
:bulb: Example snippets
Start joplin and get your API token. Click to expand the examples.
Get all notes
from joppy.api import Api
# Create a new Api instance.
api = Api(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()
Add a tag to a note
from joppy.api import Api
# Create a new Api instance.
api = Api(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)
Add a resource to a note
from joppy.api import Api
from joppy import tools
# Create a new Api instance.
api = Api(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)
Bulk remove tags
Inspired by https://discourse.joplinapp.org/t/bulk-tag-delete-python-script/5497/1.
import re
from joppy.api import Api
# Create a new Api instance.
api = Api(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)
Remove unused tags
Reference: https://discourse.joplinapp.org/t/prune-empty-tags-from-web-clipper/36194
from joppy.api import Api
# Create a new Api instance.
api = Api(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)
Remove spaces from tags
Reference: https://www.reddit.com/r/joplinapp/comments/pozric/batch_remove_spaces_from_all_tags/
import re
from joppy.api import Api
# Create a new Api instance.
api = Api(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))
Remove orphaned resources
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.api import Api
# Create a new Api instance.
api = Api(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.
:newspaper: Example scripts
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. Below are example scripts to showcase how joppy can be used.
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. |
https://github.com/marph91/joplin-ui-tests | System tests for the joplin desktop app. Based on selenium. |
https://github.com/gri38/django-joplin_vieweb | Web viewer for joplin. |
https://github.com/BeneKurz/Toodledo2Joplin | Import notes from https://www.toodledo.com to Joplin. |
:sunny: Tests
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.
:book: Changelog
0.2.3
- Don't use the root logger for logging.
- Add support for revisions.
0.2.2
- Fix adding non-image ressources (https://github.com/marph91/joppy/issues/24).
- Cast
markup_language
to an appropriate enum type. - Add changelog.
0.2.1
- Fix PDF output example (https://github.com/marph91/joppy/issues/19).
- :warning: Drop tests for python 3.6, since it's EOL. It may still work.
- Fix the type of
todo_completed
andtodo_due
. They are a unix timestamp, not a bool.
0.1.1
- Add typing support to the pypi module.
0.1.0
- Use a requests session for speedup (https://github.com/marph91/joppy/issues/15).
- :warning: Convert the API responses to data objects (https://github.com/marph91/joppy/pull/17). Main difference is to use
note.id
instead ofnote["id"]
for example.
0.0.7
- Fix getting the binary resource file (https://github.com/marph91/joppy/issues/13).
0.0.6
- Add convenience method for deleting all notes.
- Add example scripts.
0.0.5
- Fix package publishing workflow.
0.0.4
- Add support for python 3.6 and 3.7.
0.0.3
- Fix search with special characters (https://github.com/marph91/joppy/issues/5).
- Remove arbitrary arguments from the internal base requests, since they aren't needed and may cause bugs.
0.0.2
- CI and test improvements.
- Move complete setup to
setup.cfg
.
0.0.1
- Initial release.