Skip to content

Instantly share code, notes, and snippets.

@ObjectBoxPC
Created March 26, 2025 07:50
Show Gist options
  • Save ObjectBoxPC/c47736009ac6a1d01ba1ef4c2ffea66b to your computer and use it in GitHub Desktop.
Save ObjectBoxPC/c47736009ac6a1d01ba1ef4c2ffea66b to your computer and use it in GitHub Desktop.
Automatically update Joplin from GitHub
#!/usr/bin/env python3
import hashlib
import json
import re
import shutil
import subprocess
import tempfile
import urllib.request
USER_AGENT = "Joplin-Update/1.0"
GITHUB_RELEASES_API = "https://api.github.com/repos/laurent22/joplin/releases?per_page=10"
ASSET_NAME_REGEX = re.compile(".*\\.AppImage$")
HASH_NAME_REGEX = re.compile(".*\\.AppImage\\.sha512$")
INSTALL_PATH = "/usr/local/bin/joplin"
def request_json(url):
headers = { "User-Agent": USER_AGENT, "Accept": "application/json" }
request = urllib.request.Request(url, headers=headers)
with urllib.request.urlopen(request) as json_result:
return json.load(json_result)
def open_download(url):
headers = { "User-Agent": USER_AGENT }
request = urllib.request.Request(url, headers=headers)
return urllib.request.urlopen(request)
def get_release_from_api():
releases = request_json(GITHUB_RELEASES_API)
version = ""
download_url = ""
hash = ""
for release in releases:
if not release["prerelease"]:
version = release["name"]
assets = release["assets"]
for asset in assets:
if ASSET_NAME_REGEX.match(asset["name"]):
download_url = asset["browser_download_url"]
elif HASH_NAME_REGEX.match(asset["name"]):
with open_download(asset["browser_download_url"]) as hash_file:
hash = hash_file.read().decode()
break
if version and download_url and hash:
return (version, download_url, hash)
else:
return None
api_release = get_release_from_api()
if api_release:
(api_version, download_url, api_hash) = api_release
with open(INSTALL_PATH, "rb") as system_file:
system_hash = hashlib.file_digest(system_file, "sha512")
if system_hash.hexdigest() == api_hash:
print("Joplin appears to be up to date")
else:
print("Installing version: {}".format(api_version))
with open_download(download_url) as download_file, \
tempfile.NamedTemporaryFile(suffix=".AppImage", delete_on_close=False) as temp_file:
shutil.copyfileobj(download_file, temp_file)
temp_file.close()
subprocess.run(["sudo", "mv", temp_file.name, INSTALL_PATH], check=True)
subprocess.run(["sudo", "chmod", "755", INSTALL_PATH], check=True)
else:
print("Could not get version from release feed")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment