Skip to content

Commit

Permalink
Merge branch 'new-api' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
JackGruber committed Nov 18, 2020
2 parents 255797c + 9527048 commit bab3c7a
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 149 deletions.
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Joplin tools

Various python tools for Joplin.
For the communication with Joplin the API is used.
Various Python and AutoIt tools for Joplin.
Python use the Joplin API for communication.

## Additional python modules

Expand Down Expand Up @@ -96,10 +96,14 @@ python todo_overview.py --title "Open ToDo's" --as-todo --tag "importend"

### JoplinWinBackup.au3

---

Since there is no possibility for an automatic backup under windows, the required key combinations are sent to joplin via autoit to create a backup.

Rename the `JoplinWinBackup.ini.example` to `JoplinWinBackup.ini` and place it in the same folder es the `JoplinWinBackup.au3` or `JoplinWinBackup.exe`.

The latest JoplinWinBackup.exe can be downloaded from the [latest release](https://github.com/JackGruber/Joplin-Tools/releases/latest/download/JoplinWinBackup.exe).

Options from the JoplinWinBackup.ini

- `JoplinWinBackup` Defines the Path to Joplin exe. Default `C:\Program Files\Joplin\Joplin.exe`
Expand Down
31 changes: 15 additions & 16 deletions add_pdf_previews.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,24 +38,23 @@ def Main(notebook, token, url):
print("Wait for Joplin")
time.sleep(10)

query = "resource:application/pdf"
if notebook is not None:
notebook_id = joplinapi.GetNotebookID(notebook)
if notebook_id == False:
print("Notebook not found")
sys.exit(1)
else:
note_ids = joplinapi.GetFolderNotes(notebook_id)
else:
note_ids = joplinapi.GetNotes(None, "id")
query += ' notebook:"' + notebook + '"'

print("Process 1 of " + str(len(note_ids)) + " notes")
count = 1
for note in note_ids:
if count % 10 == 0:
print("Process " + str(count) + " of " + str(len(note_ids)) + " notes")
joplintools.AddPDFPreviewToNote(note['id'])
count += 1

page = 1
while True:
note_ids = joplinapi.Search(query=query,type="note", fields="id", limit=2, page=page)
count = 1
for note in note_ids['items']:
if count % 10 == 0:
print("Process 1 of " + str(len(note_ids['items'])) + " notes from batch " + str(page))
joplintools.AddPDFPreviewToNote(note['id'])
count += 1

page += page
if note_ids['has_more'] == False:
break;

if __name__ == "__main__":
Main()
109 changes: 39 additions & 70 deletions joplin/joplinapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,33 +54,25 @@ def GetEndpoint():


def GetNotebookID(notebook_name):
""" Find the ID of the destination folder
adapted logic from jhf2442 on Joplin forum
https://discourse.joplin.cozic.net/t/import-txt-files/692
"""
notebook_id = ""
joplin = GetEndpoint()

try:
res = requests.get(joplin['endpoint'] +
"/folders?token=" + joplin['token'])
page = 1
while True:
res = requests.get(joplin['endpoint'] + "/folders?token=" + joplin['token'] + "fields=id,title,parent_id&limit=100&page=" + str(page))
folders = res.json()

for folder in folders['items']:
if folder["title"] == notebook_name:
notebook_id = folder["id"]
break

page += 1

if folders.get('has_more') == None or folders.get('has_more') == False:
break

for folder in folders:
if folder.get("title") == notebook_name:
notebook_id = folder.get("id")
if notebook_id == "":
for folder in folders:
if "children" in folder:
for child in folder.get("children"):
if child.get("title") == notebook_name:
notebook_id = child.get("id")
except requests.ConnectionError as e:
print("Connection Error - Is Joplin Running?")
except Exception as e:
print("Error - on get joplin notebook id")

if notebook_id == "" or notebook_id == "err":
if notebook_id == "":
return False
else:
return notebook_id
Expand Down Expand Up @@ -190,33 +182,14 @@ def EncodeResourceFile(filename, datatype):
img = f"data:{datatype};base64,{encoded.decode()}"
return img


def LoadTags(reload=False):
joplin = GetEndpoint()
global JOPLIN_TAGS
if(reload == True or JOPLIN_TAGS is None):
response = requests.get(joplin['endpoint'] +
"/tags?token=" + joplin['token'])
if response.status_code != 200:
print("Tag load ERROR")
return False
else:
JOPLIN_TAGS = response.json()
return JOPLIN_TAGS


def GetTagID(search_tag):
tags = LoadTags()
search_tag = search_tag.strip()

if tags == False:
tags = Search(search_tag, "tag", limit=10, page=1, fields="id")

if len(tags['items']) == 1:
return tags['items'][0]['id']
else:
return False
for tag in tags:
if tag['title'].lower() == search_tag.lower():
return tag['id']

return False


def AddTagToNote(tag, note_id, create_tag=False):
joplin = GetEndpoint()
Expand Down Expand Up @@ -249,7 +222,6 @@ def CreateTag(tag):
return False
else:
json_response = response.json()
LoadTags(True)
return json_response['id']
return True

Expand All @@ -270,7 +242,7 @@ def Ping():
return True


def GetNotes(note_id=None, fields=None):
def GetNotes(note_id=None, fields=None, limit=10, page=1, order_by="", order_dir="ASC"):
joplin = GetEndpoint()

if fields is None and note_id is not None:
Expand All @@ -279,12 +251,14 @@ def GetNotes(note_id=None, fields=None):
fields = "id,title,is_todo,todo_completed,parent_id,updated_time,user_updated_time,user_created_time,encryption_applied"

if note_id is not None:
note_id = "/" + note_id
response = requests.get(joplin['endpoint'] +
"/notes/" + note_id + "?token=" + joplin['token'] + "&fields=" + fields)
else:
note_id = ""

response = requests.get(joplin['endpoint'] +
"/notes" + note_id + "?token=" + joplin['token'] + "&fields=" + fields)
if order_by != "":
order_by = "&order_by=" + order_by
response = requests.get(joplin['endpoint'] +
"/notes?token=" + joplin['token'] + "&fields=" + fields + "&limit=" + str(limit) + "&page=" + str(page) + "&order_dir=" + order_dir + order_by)

if response.status_code != 200:
print("GetNotes ERROR")
return False
Expand All @@ -294,11 +268,17 @@ def GetNotes(note_id=None, fields=None):
return response.json()


def GetNoteResources(note_id):
def GetNoteResources(note_id, fields, limit=10, page=1, order_by="", order_dir="ASC"):
joplin = GetEndpoint()

if fields is None:
fields = "id,title"

if order_by != "":
order_by = "&order_by=" + order_by

response = requests.get(joplin['endpoint'] +
"/notes/" + note_id + "/resources?token=" + joplin['token'])
"/notes/" + note_id + "/resources?token=" + joplin['token'] + "&fields=" + fields + "&limit=" + str(limit) + "&page=" + str(page) + "&order_dir=" + order_dir + order_by)

if response.status_code != 200:
print("GetResources ERROR")
Expand Down Expand Up @@ -339,27 +319,16 @@ def UpdateNote(note_id, json_properties):
else:
return True


def GetFolderNotes(folder_id):
joplin = GetEndpoint()

response = requests.get(joplin['endpoint'] +
"/folders/" + folder_id + "/notes?token=" + joplin['token'])
if response.status_code != 200:
print("GetFolderNotes ERROR")
return False
else:
return response.json()


def Search(query, type, fields=None):
def Search(query, type, limit=10, page=1, fields=None, order_by="", order_dir="ASC"):
joplin = GetEndpoint()

if fields is None:
fields = "id,title"

if order_by != "":
order_by = "&order_by=" + order_by
response = requests.get(joplin['endpoint'] +
"/search?token=" + joplin['token'] + "&query=" + query + "&type=" + type + "&fields=" + fields)
"/search?token=" + joplin['token'] + "&query=" + query + "&type=" + type + "&fields=" + fields + "&limit=" + str(limit) + "&page=" + str(page) + "&order_dir=" + order_dir + order_by)
if response.status_code != 200:
print("Search ERROR")
return False
Expand Down
96 changes: 52 additions & 44 deletions joplin/joplintools.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,47 +51,55 @@ def AddPDFPreviewToBody(body, pdf_id, preview_id):

def AddPDFPreviewToNote(note_id):
print("AddPDFPreviewToNote: " + note_id, end=" ")
res = joplinapi.GetNoteResources(note_id)
if res is None or res == False:
return True

pdfs = GetAllMimeResources(res, "application/pdf")
if pdfs == False:
print("")
return True

note = joplinapi.GetNotes(note_id, "body, title")
body_new = note['body']

print("\t" + note['title'])

note_update = False
for pdf in pdfs:
print("\tResource: " + pdf['id'] + "\t" + pdf['title'])
tmp = os.path.join(tempfile.gettempdir(), pdf['title'])
png = tmp + ".png"

if re.search(r"!\[" + pdf['id'] + r"\]", body_new) is not None:
print("\talready present")
continue

if re.search(r"!\[.*\]\(:/[\da-z]+\)\n(\[.*\]\(:\/" + pdf['id'] + r"\))", body_new) is not None:
print("\tpossible present")
continue

if joplinapi.GetResourcesFile(pdf['id'], tmp) == False:
return False

if CreatePDFPreview(tmp, png, 1) == True:
img_res = joplinapi.CreateResource(png)
if img_res != False:
body_new = AddPDFPreviewToBody(body_new, pdf['id'], img_res['id'])
note_update = True

if note_update == True:
data = {}
data['body'] = body_new
json_data = json.dumps(data)
joplinapi.UpdateNote(note_id, json_data)

print("")

page = 1
while True:
res = joplinapi.GetNoteResources(note_id, fields="id,title,mime", limit=100, page=page)

if res is None or res == False:
return True
elif len(res['items']) > 0:
pdfs = GetAllMimeResources(res['items'], "application/pdf")

if pdfs == False:
print("")
return True
else:
note = joplinapi.GetNotes(note_id, "body, title")
body_new = note['body']

print("\t" + note['title'])

note_update = False

for pdf in pdfs:
print("\tResource: " + pdf['id'] + "\t" + pdf['title'])
tmp = os.path.join(tempfile.gettempdir(), pdf['title'])
png = tmp + ".png"

if re.search(r"!\[" + pdf['id'] + r"\]", body_new) is not None:
print("\talready present")
continue

if re.search(r"!\[.*\]\(:/[\da-z]+\)\n(\[.*\]\(:\/" + pdf['id'] + r"\))", body_new) is not None:
print("\tpossible present")
continue

if joplinapi.GetResourcesFile(pdf['id'], tmp) == False:
return False

if CreatePDFPreview(tmp, png, 1) == True:
img_res = joplinapi.CreateResource(png)
if img_res != False:
body_new = AddPDFPreviewToBody(body_new, pdf['id'], img_res['id'])
note_update = True

if note_update == True:
data = {}
data['body'] = body_new
json_data = json.dumps(data)
joplinapi.UpdateNote(note_id, json_data)
print("")

if res['has_more'] == False:
break
38 changes: 21 additions & 17 deletions todo_overview.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,11 @@ def Main(notebook, title, token, url, add_tag, as_todo):
add_tag = add_tag.replace(", ", ",")
add_tag = add_tag.split(",")

note = joplinapi.Search('title:"' + title + '"', "note", "id,title,is_todo,body")
note = joplinapi.Search(query='title:"' + title + '"', type="note", fields="id,title,is_todo,body")

if len(note) == 1:
note_id = note[0]['id']
note = joplinapi.GetNotes(note_id,"id,title,is_todo,body")
body_org = note['body']
if len(note['items']) == 1:
note_id = note['items'][0]['id']
body_org = note['items'][0]['body']
elif len(note) > 1:
print("Error multiple matching notes found")
sys.exit(1)
Expand All @@ -90,20 +89,25 @@ def Main(notebook, title, token, url, add_tag, as_todo):
print("No notebook defined and no note with title '" + title + "' found.")
sys.exit(1)

todos = joplinapi.Search("type:todo iscompleted:0",
"note", "id,title,todo_due,todo_completed")
todos.sort(key=lambda r: r['todo_due'])

body = "| Date | Title |\n"
body += "| --- | --- |\n"
for todo in todos:
if note_id != todo['id']:
epoch = int(todo['todo_due'] / 1000)
date = datetime.fromtimestamp(epoch).strftime('%Y-%m-%d %H:%M')
if epoch < int(time.time()):
date += " \U00002757"
body += "|" + date + \
"|[" + todo['title'] + "](:/" + todo['id'] + ")|\n"
page = 1
while True:
todos = joplinapi.Search(query="type:todo iscompleted:0",
type="note", fields="id,title,todo_due,todo_completed",
order_by="todo_due", order_dir="ASC", page=page)
for todo in todos['items']:
if note_id != todo['id']:
epoch = int(todo['todo_due'] / 1000)
date = datetime.fromtimestamp(epoch).strftime('%Y-%m-%d %H:%M')
if epoch < int(time.time()):
date += " \U00002757"
body += "|" + date + \
"|[" + todo['title'] + "](:/" + todo['id'] + ")|\n"

page += 1
if todos['has_more'] == False:
break

if note_id is None:
note_id = joplinapi.CreateNote(title, body, notebook_id)
Expand Down

0 comments on commit bab3c7a

Please sign in to comment.