Joplin API - Python

Its because, before the api was released i wrapped the terminal command line which allow to rename folder, so i didnt remove it :nerd_face:

1 Like

Hello!
I have a problem with API with sample from docs:

Python 3.7.4 (tags/v3.7.4:e09359112e, Jul  8 2019, 19:29:22) [MSC v.1916 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from joplin_api import JoplinApi
>>> joplin = JoplinApi(token='MY_TOKEN')
>>> joplin.ping()
<coroutine object JoplinApi.ping at 0x0373A810>
>>> folder = joplin.create_folder('folder_title')
>>> folder_id = folder.json()['id']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'coroutine' object has no attribute 'json'
>>>

After that got error and in Jolpin not exist new folder.
Version: Joplin 1.0.161, Win10 x64, Python 3.7.4. In Jolpin enabled clipper.

What I am doing wrong ?

You made a mistake.
Doc says

>>> from joplin_api import JoplinApi
>>> joplin = JoplinApi(token='the token provided by Joplin in the WebClipper menu:P'))
>>> ping = await joplin.ping()  # to check if the service is up
>>> print(ping.text)

You will notice the await keyword

If I add await, i have another error:

Python 3.7.4 (tags/v3.7.4:e09359112e, Jul  8 2019, 19:29:22) [MSC v.1916 32 bit (Intel)] on win32
>>> from joplin_api import JoplinApi
>>> joplin = JoplinApi(token=MY_TOKEN)
>>> ping = await joplin.ping()
  File "<stdin>", line 1
SyntaxError: 'await' outside function

Search in internet: when use ‘async’, ‘await’ needed ‘event loop’.
I am confused, what i need to do

This should answer your questions https://github.com/foxmask/joplin-api/issues/4
I will improve the doc with the event loop

@foxmask I somehow doubt that using an event loop for a request API makes sense. while this could be great for your web project, it’s rather awkward for using the API in a simple python script or on the command line. Maybe I’m wrong, but this seems excessive to me.

@tessus this is how asyncio works

@mrkingmidas with python 3.7+ you can use

asyncio.run(main())

instead of using the event loop by hand.
run is like a shortcut for it.

1 Like

I underatand that, but what I'm saying is that it is not necessary to use asyncio for this API. At least not when using it in a script or when I quickly want to fire off a quick python code on the command line.

In that case it’s better to wrap the Joplin command line

Hello!
Please, make example how to use create_resource method ?
I am put full filename as described, file or base64 => anyway error:

{"error":"Resource cannot be created without a file"}

And in get_resource error:

path = f'/resource_id/{resource_id}'

not work and work

path = f'/resources/{resource_id}'

Also I am try access by requests module:

import requests as requests
host = 'http://127.0.0.1:41184'
res = requests.post(host + '/resources/', files={'data':data}, params={'token':JoplinToken})

OR

res = requests.post(host + '/resources/', files={'data':(data)}, params={'token':JoplinToken})

where data is:

  • data=open(‘image.png’, ‘rb’)
  • data=string “123”
  • data=base64 encoded

And anyway error:

{"error":"Internal Server Error: Unexpected end of JSON input"}

What I am doing wrong ?
Global task: make script that import Markdown file with embeding images (by resources in Joplin termins)
Environment: Windows 10 x64, Joplin 1.0.165, Python 3.7

You can try with joplin import command line. I will make a try with your example

i could deal with resources with curl but not with requests
I’m digging that issue, as I use httpx

i’ve update the lib of the api, to update

pip install -U joplin-api 

or clone the github project if you prefer

One of my scripts using joplin-api broke when upgrading from 1.4.6 to 1.6.6, but I'm not smart enough to fix it. I suppose it is related to the recent breaking changes in the API. Are you planning on updating this python wrapper? :heart:

No,
I don't use joplin anymore so I couldnt test.
May be someone else could fork the project to add the missing stuff to make it compatible.

@mrkingmidas @Prinplup: If you are still looking for a python interface of the Joplin API, you could try GitHub - marph91/joppy: Python interface for the Joplin data API. I only tested it with Joplin 2.4.9 and Python 3.8 on Ubuntu, but maybe it works in your environment. I would be happy about feedback.

6 Likes

Marph, big thanks to you !

I tested API with win10 + Python 3.10.1x64 and Joplin 2.6.10 (prod, win32) - getting and modify notes works great!

Here script, that fills notes with only "URL" (from mobile Joplin) with readability text.
Used: joppy pypandoc readability-lxml

import pypandoc
import requests

from readability import Document as ReadabilityDocument
from joppy.api import Api


def replace_body2(api, note):
    id = note["id"]
    url = note["body"]
    title = note["title"]

    print(url)

    res = requests.get(url, headers={'User-Agent': 'Chrome'}, timeout=30)
    doc = ReadabilityDocument(res.text ,url=url)
    body_html = doc.summary(html_partial=True)

    if title==url:
        title=doc.title()
        api.modify_note(id, title=title)

    body_md = pypandoc.convert_text(body_html,
                          format='html-native_divs',
                          to='gfm',
                          extra_args=['--wrap=none', '--quiet']
                          )
    new_body = "# [{}]({})\n".format(title, url) + body_md

    api.modify_note(id, source_url=url, body=new_body)

def main():
    api = Api(token="YOUR TOKEN !")

    print("Getting notes...")

    all_notes = api.get_all_notes(fields="id,parent_id,title,source_url,body")

    print("Notes: {}".format(len(all_notes)))
    print("Finding notes...")

    for note in all_notes:
        body = note["body"]
        if body[0:4]=="http" and body.find(" ") <= 0:
            try:
                replace_body2(api, note)
            except:
                print("Error at id={}, title={}".format(note["id"], note["title"]))
    print("Done.")

if __name__ == "__main__":
    main()
2 Likes