diff --git a/.github/workflows/create_release.yml b/.github/workflows/create_release.yml index 2795b12..f9aefb4 100644 --- a/.github/workflows/create_release.yml +++ b/.github/workflows/create_release.yml @@ -45,7 +45,7 @@ jobs: run: | latest_tag=${{ env.latest_tag }} if [ -z "$latest_tag" ]; then - new_version="v1.4.3" + new_version="v1.5" else IFS='.' read -r -a version_parts <<< "${latest_tag#v}" new_version="v${version_parts[0]}.$((version_parts[1] + 1)).0" diff --git a/.github/workflows/create_release_arm64.yml b/.github/workflows/create_release_arm64.yml new file mode 100644 index 0000000..4d3e577 --- /dev/null +++ b/.github/workflows/create_release_arm64.yml @@ -0,0 +1,38 @@ +name: Docker Build and Release for arm64 + +on: + push: + branches: + - main + +jobs: + build-and-push-on-docker-hub: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + with: + platforms: arm64 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + with: + install: true + + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Build and push Docker image + uses: docker/build-push-action@v6 + with: + context: . + push: true + platforms: linux/arm64 + tags: ${{ secrets.DOCKER_USERNAME }}/github-ntfy:arm64 \ No newline at end of file diff --git a/.github/workflows/create_release_armv7.yml b/.github/workflows/create_release_armv7.yml new file mode 100644 index 0000000..13ea5d9 --- /dev/null +++ b/.github/workflows/create_release_armv7.yml @@ -0,0 +1,38 @@ +name: Docker Build and Release for armv7 + +on: + push: + branches: + - main + +jobs: + build-and-push-on-docker-hub: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + with: + platforms: arm/v7 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + with: + install: true + + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Build and push Docker image + uses: docker/build-push-action@v6 + with: + context: . + push: true + platforms: linux/arm/v7 + tags: ${{ secrets.DOCKER_USERNAME }}/github-ntfy:armv7 \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index afd2b41..6397f54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,4 @@ **New features**: -- Change database struct to be able to handle docker hub repos -- Now you can add docker hub repo to your watch list -- You can connect your docker account to bypass the rate limit of the docker hub API +- Add gotify compatibility please Read the README.md -**Breaking changes**: -- Change in the docker-compose file, you need to add the DOCKER_USERNAME and DOCKER_PASSWORD environment variables - -**Full Changelog**: https://github.com/BreizhHardware/ntfy_alerts/compare/v1.3...v1.4.3 \ No newline at end of file +**Full Changelog**: https://github.com/BreizhHardware/ntfy_alerts/compare/v1.4.3...v1.5 \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 0e57811..74385d6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,6 +21,8 @@ ENV USERNAME="" \ GHNTFY_TOKEN="" \ DOCKER_USERNAME="" \ DOCKER_PASSWORD="" \ + GOTIFY_URL="" \ + GOTIFY_TOKEN="" \ FLASK_ENV=production # Exposer le port 5000 pour l'API et le port 80 pour le serveur web diff --git a/README.md b/README.md index 124fd93..1c97ccc 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ ntfy_url: the url of the ntfy server including the topic python ntfy.py ```` ## Docker: -If you want to use the docker image you can use the following docker-compose file: +If you want to use the docker image you can use the following docker-compose file for x86_64: ````yaml services: github-ntfy: @@ -28,11 +28,57 @@ services: environment: - USERNAME=username # Required - PASSWORD=password # Required - - NTFY_URL=ntfy_url # Required + - NTFY_URL=ntfy_url # Required if ntfy is used - GHNTFY_TIMEOUT=timeout # Default is 3600 (1 hour) - GHNTFY_TOKEN= # Default is empty (Github token) - DOCKER_USERNAME= # Default is empty (Docker Hub username) - DOCKER_PASSWORD= # Default is empty (Docker Hub password) + - GOTIFY_URL=gotify_url # Required if gotify is used + - GOTIFY_TOKEN= # Required if gotify is used + volumes: + - /path/to/github-ntfy:/github-ntfy/ + ports: + - 80:80 + restart: unless-stopped +```` +For arm64 this docker compose file is ok: +````yaml +services: + github-ntfy: + image: breizhhardware/github-ntfy:arm64 + container_name: github-ntfy + environment: + - USERNAME=username # Required + - PASSWORD=password # Required + - NTFY_URL=ntfy_url # Required if ntfy is used + - GHNTFY_TIMEOUT=timeout # Default is 3600 (1 hour) + - GHNTFY_TOKEN= # Default is empty (Github token) + - DOCKER_USERNAME= # Default is empty (Docker Hub username) + - DOCKER_PASSWORD= # Default is empty (Docker Hub password) + - GOTIFY_URL=gotify_url # Required if gotify is used + - GOTIFY_TOKEN= # Required if gotify is used + volumes: + - /path/to/github-ntfy:/github-ntfy/ + ports: + - 80:80 + restart: unless-stopped +```` +For armV7 this docker compose is ok: +````yaml +services: + github-ntfy: + image: breizhhardware/github-ntfy:armv7 + container_name: github-ntfy + environment: + - USERNAME=username # Required + - PASSWORD=password # Required + - NTFY_URL=ntfy_url # Required if ntfy is used + - GHNTFY_TIMEOUT=timeout # Default is 3600 (1 hour) + - GHNTFY_TOKEN= # Default is empty (Github token) + - DOCKER_USERNAME= # Default is empty (Docker Hub username) + - DOCKER_PASSWORD= # Default is empty (Docker Hub password) + - GOTIFY_URL=gotify_url # Required if gotify is used + - GOTIFY_TOKEN= # Required if gotify is used volumes: - /path/to/github-ntfy:/github-ntfy/ ports: @@ -49,9 +95,9 @@ Docker Hub repo: https://hub.docker.com/r/breizhhardware/github-ntfy - [x] Add the watched repos list as a web interface - [x] Add Docker Hub compatibility - [ ] Rework of the web interface -- [ ] Compatibility with Gotify +- [x] Compatibility with Gotify - [ ] Compatibility with Discord Webhook -- [ ] Compatibility and distribution for arm64 and armv7 +- [x] Compatibility and distribution for arm64 and armv7 # Bash setup-notify.sh ## Description: This script is used to setup the ntfy notification system on ssh login for a new server. diff --git a/ntfy.py b/ntfy.py index eef583e..a5e26a3 100644 --- a/ntfy.py +++ b/ntfy.py @@ -5,18 +5,29 @@ import logging import sqlite3 import subprocess import json +from send_ntfy import ( + github_send_to_ntfy, + docker_send_to_ntfy, +) +from send_gotify import ( + github_send_to_gotify, + docker_send_to_gotify, +) # Configuring the logger -logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') +logging.basicConfig( + level=logging.INFO, + format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", +) logger = logging.getLogger(__name__) -github_token = os.environ.get('GHNTFY_TOKEN') +github_token = os.environ.get("GHNTFY_TOKEN") github_headers = {} if github_token: - github_headers['Authorization'] = f"token {github_token}" + github_headers["Authorization"] = f"token {github_token}" -docker_username = os.environ.get('DOCKER_USERNAME') -docker_password = os.environ.get('DOCKER_PASSWORD') +docker_username = os.environ.get("DOCKER_USERNAME") +docker_password = os.environ.get("DOCKER_PASSWORD") def create_dockerhub_token(username, password): @@ -40,31 +51,42 @@ def create_dockerhub_token(username, password): docker_token = create_dockerhub_token(docker_username, docker_password) docker_header = {} if docker_token: - docker_header['Authorization'] = f"Bearer {docker_token}" + docker_header["Authorization"] = f"Bearer {docker_token}" # Connecting to the database to store previous versions -conn = sqlite3.connect('/github-ntfy/ghntfy_versions.db', check_same_thread=False) +conn = sqlite3.connect( + "/github-ntfy/ghntfy_versions.db", + check_same_thread=False, +) cursor = conn.cursor() # Creating the table if it does not exist -cursor.execute('''CREATE TABLE IF NOT EXISTS versions - (repo TEXT PRIMARY KEY, version TEXT, changelog TEXT)''') +cursor.execute( + """CREATE TABLE IF NOT EXISTS versions + (repo TEXT PRIMARY KEY, version TEXT, changelog TEXT)""" +) conn.commit() -cursor.execute('''CREATE TABLE IF NOT EXISTS docker_versions - (repo TEXT PRIMARY KEY, digest TEXT, changelog TEXT)''') +cursor.execute( + """CREATE TABLE IF NOT EXISTS docker_versions + (repo TEXT PRIMARY KEY, digest TEXT)""" +) conn.commit() logger.info("Starting version monitoring...") -conn2 = sqlite3.connect('/github-ntfy/watched_repos.db', check_same_thread=False) +conn2 = sqlite3.connect("/github-ntfy/watched_repos.db", check_same_thread=False) cursor2 = conn2.cursor() -cursor2.execute('''CREATE TABLE IF NOT EXISTS watched_repos - (id INTEGER PRIMARY KEY, repo TEXT)''') +cursor2.execute( + """CREATE TABLE IF NOT EXISTS watched_repos + (id INTEGER PRIMARY KEY, repo TEXT)""" +) conn2.commit() -cursor2.execute('''CREATE TABLE IF NOT EXISTS docker_watched_repos - (id INTEGER PRIMARY KEY, repo TEXT)''') +cursor2.execute( + """CREATE TABLE IF NOT EXISTS docker_watched_repos + (id INTEGER PRIMARY KEY, repo TEXT)""" +) conn2.commit() @@ -98,36 +120,41 @@ def get_latest_releases(watched_repos): if response.status_code == 200: release_info = response.json() changelog = get_changelog(repo) - release_date = release_info.get('published_at', 'Release date not available') - releases.append({ - "repo": repo, - "name": release_info["name"], - "tag_name": release_info["tag_name"], - "html_url": release_info["html_url"], - "changelog": changelog, - "published_at": release_date - }) + release_date = release_info.get("published_at", "Release date not available") + releases.append( + { + "repo": repo, + "name": release_info["name"], + "tag_name": release_info["tag_name"], + "html_url": release_info["html_url"], + "changelog": changelog, + "published_at": release_date, + } + ) else: logger.error(f"Failed to fetch release info for {repo}") return releases + def get_latest_docker_releases(watched_repos): releases = [] for repo in watched_repos: - url = f"https://hub.docker.com/v2/repositories/{repo_name}/tags/latest" + url = f"https://hub.docker.com/v2/repositories/{repo}/tags/latest" response = requests.get(url, headers=docker_header) if response.status_code == 200: release_info = response.json() - release_date=release_info["last_upated"] + release_date = release_info["last_upated"] digest = release_date["digest"] - releases.append({ - "repo": repo, - "digest": digest, - "html_url": "https://hub.docker.com/r/" + repo, - "published_at": release_date - }) + releases.append( + { + "repo": repo, + "digest": digest, + "html_url": "https://hub.docker.com/r/" + repo, + "published_at": release_date, + } + ) else: - logger.error(f"Failed to fetch Docker Hub info for {repo_name}") + logger.error(f"Failed to fetch Docker Hub info for {repo}") return releases @@ -138,103 +165,50 @@ def get_changelog(repo): releases = response.json() if releases: latest_release_list = releases[0] - if 'body' in latest_release_list: - return latest_release_list['body'] + if "body" in latest_release_list: + return latest_release_list["body"] return "Changelog not available" -def github_send_to_ntfy(releases, auth, url): - for release in releases: - app_name = release['repo'].split('/')[-1] # Getting the application name from the repo - version_number = release['tag_name'] # Getting the version number - app_url = release['html_url'] # Getting the application URL - changelog = release['changelog'] # Getting the changelog - release_date = release['published_at'] # Getting the release date - release_date = release_date.replace("T", " ").replace("Z", "") # Formatting the release date - - # Checking if the version has changed since the last time - cursor.execute("SELECT version FROM versions WHERE repo=?", (app_name,)) - previous_version = cursor.fetchone() - if previous_version and previous_version[0] == version_number: - logger.info(f"The version of {app_name} has not changed. No notification sent.") - continue # Move on to the next application - - message = f"New version: {version_number}\nFor: {app_name}\nPublished on: {release_date}\nChangelog:\n{changelog}\n{app_url}" - # Updating the previous version for this application - cursor.execute("INSERT OR REPLACE INTO versions (repo, version, changelog) VALUES (?, ?, ?)", - (app_name, version_number, changelog)) - conn.commit() - - headers = { - "Authorization": f"Basic {auth}", - "Title": f"New version for {app_name}", - "Priority": "urgent", - "Markdown": "yes", - "Actions": f"view, Update {app_name}, {app_url}, clear=true"} - response = requests.post(f"{url}", headers=headers, data=message) - if response.status_code == 200: - logger.info(f"Message sent to Ntfy for {app_name}") - continue - else: - logger.error(f"Failed to send message to Ntfy. Status code: {response.status_code}") - -def docker_send_to_ntfy(releases, auth, url): - for release in releases: - app_name = release['repo'].split('/')[-1] # Getting the application name from the repo - digest_number = release['digest'] - app_url = release['html_url'] # Getting the application URL - release_date = release['published_at'] # Getting the release date - release_date = release_date.replace("T", " ").replace("Z", "") # Formatting the release date - - # Checking if the version has changed since the last time - cursor.execute("SELECT digest FROM docker_versions WHERE repo=?", (app_name,)) - previous_digest = cursor.fetchone() - if previous_digest and previous_digest[0] == digest_number: - logger.info(f"The digest of {app_name} has not changed. No notification sent.") - continue # Move on to the next application - - message = f"New version: {digest_number}\nFor: {app_name}\nPublished on: {release_date}\nChangelog:\n{changelog}\n{app_url}" - # Updating the previous digest for this application - cursor.execute("INSERT OR REPLACE INTO docker_versions (repo, digest, changelog) VALUES (?, ?, ?)", - (app_name, digest_number, changelog)) - conn.commit() - - headers = { - "Authorization": f"Basic {auth}", - "Title": f"New version for {app_name}", - "Priority": "urgent", - "Markdown": "yes", - "Actions": f"view, Update {app_name}, {app_url}, clear=true"} - response = requests.post(f"{url}", headers=headers, data=message) - if response.status_code == 200: - logger.info(f"Message sent to Ntfy for {app_name}") - continue - else: - logger.error(f"Failed to send message to Ntfy. Status code: {response.status_code}") - - if __name__ == "__main__": start_api() - with open('/auth.txt', 'r') as f: + with open("/auth.txt", "r") as f: auth = f.read().strip() - ntfy_url = os.environ.get('NTFY_URL') - timeout = float(os.environ.get('GHNTFY_TIMEOUT')) + ntfy_url = os.environ.get("NTFY_URL") + gotify_url = os.environ.get("GOTIFY_URL") + gotify_token = os.environ.get("GOTIFY_TOKEN") + timeout = float(os.environ.get("GHNTFY_TIMEOUT")) if auth and ntfy_url: while True: github_watched_repos_list = get_watched_repos() github_latest_release = get_latest_releases(github_watched_repos_list) - if github_latest_release: - github_send_to_ntfy(github_latest_release, auth, ntfy_url) docker_watched_repos_list = get_docker_watched_repos() docker_latest_release = get_latest_docker_releases(docker_watched_repos_list) - if docker_latest_release: - docker_send_to_ntfy(docker_latest_release, auth, ntfy_url) + if ntfy_url != "": + if github_latest_release: + github_send_to_ntfy(github_latest_release, auth, ntfy_url) + if docker_latest_release: + docker_send_to_ntfy(docker_latest_release, auth, ntfy_url) + + if gotify_url != "" and gotify_token != "": + if github_latest_release: + github_send_to_gotify(github_latest_release, gotify_token, gotify_url) + if docker_latest_release: + docker_send_to_gotify(docker_latest_release, gotify_token, gotify_url) + time.sleep(timeout) # Wait an hour before checking again else: logger.error("Usage: python ntfy.py") logger.error( "auth: can be generataed by the folowing command: echo -n 'username:password' | base64 and need to be " - "stored in a file named auth.txt") + "stored in a file named auth.txt" + ) logger.error("NTFY_URL: the url of the ntfy server need to be stored in an environment variable named NTFY_URL") - + logger.error( + "GOTIFY_URL: the url of the gotify server need to be stored in an environment variable named GOTIFY_URL" + ) + logger.error( + "GOTIFY_TOKEN: the token of the gotify server need to be stored in an environment variable named GOTIFY_TOKEN" + ) + logger.error("GHNTFY_TIMEOUT: the time interval between each check") diff --git a/ntfy_api.py b/ntfy_api.py index ad995dd..5abe8eb 100644 --- a/ntfy_api.py +++ b/ntfy_api.py @@ -6,8 +6,9 @@ app = Flask(__name__) CORS(app) app.logger.setLevel("WARNING") + def get_db_connection(): - conn = sqlite3.connect('/github-ntfy/watched_repos.db') + conn = sqlite3.connect("/github-ntfy/watched_repos.db") conn.row_factory = sqlite3.Row return conn @@ -16,14 +17,17 @@ def close_db_connection(conn): conn.close() -@app.route('/app_repo', methods=['POST']) +@app.route("/app_repo", methods=["POST"]) def app_repo(): data = request.json - repo = data.get('repo') + repo = data.get("repo") # Vérifier si le champ 'repo' est présent dans les données JSON if not repo: - return jsonify({"error": "The repo field is required."}), 400 + return ( + jsonify({"error": "The repo field is required."}), + 400, + ) # Établir une connexion à la base de données conn = get_db_connection() @@ -31,13 +35,22 @@ def app_repo(): try: # Vérifier si le dépôt existe déjà dans la base de données - cursor.execute("SELECT * FROM watched_repos WHERE repo=?", (repo,)) + cursor.execute( + "SELECT * FROM watched_repos WHERE repo=?", + (repo,), + ) existing_repo = cursor.fetchone() if existing_repo: - return jsonify({"error": f"The GitHub repo {repo} is already in the database."}), 409 + return ( + jsonify({"error": f"The GitHub repo {repo} is already in the database."}), + 409, + ) # Ajouter le dépôt à la base de données - cursor.execute("INSERT INTO watched_repos (repo) VALUES (?)", (repo,)) + cursor.execute( + "INSERT INTO watched_repos (repo) VALUES (?)", + (repo,), + ) conn.commit() return jsonify({"message": f"The GitHub repo {repo} as been added to the watched repos."}) finally: @@ -45,14 +58,17 @@ def app_repo(): close_db_connection(conn) -@app.route('/app_docker_repo', methods=['POST']) +@app.route("/app_docker_repo", methods=["POST"]) def app_docker_repo(): data = request.json - repo = data.get('repo') + repo = data.get("repo") # Vérifier si le champ 'repo' est présent dans les données JSON if not repo: - return jsonify({"error": "The repo field is required."}), 400 + return ( + jsonify({"error": "The repo field is required."}), + 400, + ) # Établir une connexion à la base de données conn = get_db_connection() @@ -60,13 +76,22 @@ def app_docker_repo(): try: # Vérifier si le dépôt existe déjà dans la base de données - cursor.execute("SELECT * FROM docker_watched_repos WHERE repo=?", (repo,)) + cursor.execute( + "SELECT * FROM docker_watched_repos WHERE repo=?", + (repo,), + ) existing_repo = cursor.fetchone() if existing_repo: - return jsonify({"error": f"The Docker repo {repo} is already in the database."}), 409 + return ( + jsonify({"error": f"The Docker repo {repo} is already in the database."}), + 409, + ) # Ajouter le dépôt à la base de données - cursor.execute("INSERT INTO docker_watched_repos (repo) VALUES (?)", (repo,)) + cursor.execute( + "INSERT INTO docker_watched_repos (repo) VALUES (?)", + (repo,), + ) conn.commit() return jsonify({"message": f"The Docker repo {repo} as been added to the watched repos."}) finally: @@ -74,7 +99,7 @@ def app_docker_repo(): close_db_connection(conn) -@app.route('/watched_repos', methods=['GET']) +@app.route("/watched_repos", methods=["GET"]) def get_watched_repos(): db = get_db_connection() cursor = db.cursor() @@ -85,7 +110,7 @@ def get_watched_repos(): return jsonify(watched_repos) -@app.route('/watched_docker_repos', methods=['GET']) +@app.route("/watched_docker_repos", methods=["GET"]) def get_watched_docker_repos(): db = get_db_connection() cursor = db.cursor() @@ -96,14 +121,17 @@ def get_watched_docker_repos(): return jsonify(watched_repos) -@app.route('/delete_repo', methods=['POST']) +@app.route("/delete_repo", methods=["POST"]) def delete_repo(): data = request.json - repo = data.get('repo') + repo = data.get("repo") # Vérifier si le champ 'repo' est présent dans les données JSON if not repo: - return jsonify({"error": "The repo field is required."}), 400 + return ( + jsonify({"error": "The repo field is required."}), + 400, + ) # Établir une connexion à la base de données conn = get_db_connection() @@ -111,13 +139,22 @@ def delete_repo(): try: # Vérifier si le dépôt existe dans la base de données - cursor.execute("SELECT * FROM watched_repos WHERE repo=?", (repo,)) + cursor.execute( + "SELECT * FROM watched_repos WHERE repo=?", + (repo,), + ) existing_repo = cursor.fetchone() if not existing_repo: - return jsonify({"error": f"The GitHub repo {repo} is not in the database."}), 404 + return ( + jsonify({"error": f"The GitHub repo {repo} is not in the database."}), + 404, + ) # Supprimer le dépôt de la base de données - cursor.execute("DELETE FROM watched_repos WHERE repo=?", (repo,)) + cursor.execute( + "DELETE FROM watched_repos WHERE repo=?", + (repo,), + ) conn.commit() return jsonify({"message": f"The GitHub repo {repo} as been deleted from the watched repos."}) finally: @@ -125,14 +162,17 @@ def delete_repo(): close_db_connection(conn) -@app.route('/delete_docker_repo', methods=['POST']) +@app.route("/delete_docker_repo", methods=["POST"]) def delete_docker_repo(): data = request.json - repo = data.get('repo') + repo = data.get("repo") # Vérifier si le champ 'repo' est présent dans les données JSON if not repo: - return jsonify({"error": "The repo field is required."}), 400 + return ( + jsonify({"error": "The repo field is required."}), + 400, + ) # Établir une connexion à la base de données conn = get_db_connection() @@ -140,13 +180,22 @@ def delete_docker_repo(): try: # Vérifier si le dépôt existe dans la base de données - cursor.execute("SELECT * FROM docker_watched_repos WHERE repo=?", (repo,)) + cursor.execute( + "SELECT * FROM docker_watched_repos WHERE repo=?", + (repo,), + ) existing_repo = cursor.fetchone() if not existing_repo: - return jsonify({"error": f"The Docker repo {repo} is not in the database."}), 404 + return ( + jsonify({"error": f"The Docker repo {repo} is not in the database."}), + 404, + ) # Supprimer le dépôt de la base de données - cursor.execute("DELETE FROM docker_watched_repos WHERE repo=?", (repo,)) + cursor.execute( + "DELETE FROM docker_watched_repos WHERE repo=?", + (repo,), + ) conn.commit() return jsonify({"message": f"The Docker repo {repo} as been deleted from the watched repos."}) finally: diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..e34796e --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,2 @@ +[tool.black] +line-length = 120 \ No newline at end of file diff --git a/send_gotify.py b/send_gotify.py new file mode 100644 index 0000000..6aa015f --- /dev/null +++ b/send_gotify.py @@ -0,0 +1,98 @@ +import requests +import sqlite3 +import logging + +conn = sqlite3.connect( + "/github-ntfy/ghntfy_versions.db", + check_same_thread=False, +) +cursor = conn.cursor() + +logging.basicConfig( + level=logging.INFO, + format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", +) +logger = logging.getLogger(__name__) + + +def github_send_to_gotify(releases, token, url): + url = url + "/message" + url = url + "?token=" + token + for release in releases: + app_name = release["repo"].split("/")[-1] # Getting the application name from the repo + version_number = release["tag_name"] # Getting the version number + app_url = release["html_url"] # Getting the application URL + changelog = release["changelog"] # Getting the changelog + release_date = release["published_at"] # Getting the release date + release_date = release_date.replace("T", " ").replace("Z", "") # Formatting the release date + + # Checking if the version has changed since the last time + cursor.execute( + "SELECT version FROM versions WHERE repo=?", + (app_name,), + ) + previous_version = cursor.fetchone() + if previous_version and previous_version[0] == version_number: + logger.info(f"The version of {app_name} has not changed. No notification sent.") + continue # Move on to the next application + + message = f"New version: {version_number}\nFor: {app_name}\nPublished on: {release_date}\nChangelog:\n{changelog}\n{app_url}" + # Updating the previous version for this application + cursor.execute( + "INSERT OR REPLACE INTO versions (repo, version, changelog) VALUES (?, ?, ?)", + (app_name, version_number, changelog), + ) + conn.commit() + + content = { + "title": f"New version for {app_name}", + "message": message, + "priority": "2", + } + response = requests.post(url, json=content) + if response.status_code == 200: + logger.info(f"Message sent to Gotify for {app_name}") + continue + else: + logger.error(f"Failed to send message to Gotify. Status code: {response.status_code}") + + +def docker_send_to_ntfy(releases, token, url): + url = url + "/message" + url = url + "?token=" + token + for release in releases: + app_name = release["repo"].split("/")[-1] # Getting the application name from the repo + digest_number = release["digest"] + app_url = release["html_url"] # Getting the application URL + release_date = release["published_at"] # Getting the release date + release_date = release_date.replace("T", " ").replace("Z", "") # Formatting the release date + + # Checking if the version has changed since the last time + cursor.execute( + "SELECT digest FROM docker_versions WHERE repo=?", + (app_name,), + ) + previous_digest = cursor.fetchone() + if previous_digest and previous_digest[0] == digest_number: + logger.info(f"The digest of {app_name} has not changed. No notification sent.") + continue # Move on to the next application + + message = f"New version: {digest_number}\nFor: {app_name}\nPublished on: {release_date}\n{app_url}" + # Updating the previous digest for this application + cursor.execute( + "INSERT OR REPLACE INTO docker_versions (repo, digest) VALUES (?, ?, ?)", + (app_name, digest_number), + ) + conn.commit() + + content = { + "title": f"New version for {app_name}", + "message": message, + "priority": "2", + } + response = requests.post(url, json=content) + if response.status_code == 200: + logger.info(f"Message sent to Gotify for {app_name}") + continue + else: + logger.error(f"Failed to send message to Gotify. Status code: {response.status_code}") diff --git a/send_ntfy.py b/send_ntfy.py new file mode 100644 index 0000000..cd3be10 --- /dev/null +++ b/send_ntfy.py @@ -0,0 +1,98 @@ +import requests +import sqlite3 +import logging + +conn = sqlite3.connect( + "/github-ntfy/ghntfy_versions.db", + check_same_thread=False, +) +cursor = conn.cursor() + +logging.basicConfig( + level=logging.INFO, + format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", +) +logger = logging.getLogger(__name__) + + +def github_send_to_ntfy(releases, auth, url): + for release in releases: + app_name = release["repo"].split("/")[-1] # Getting the application name from the repo + version_number = release["tag_name"] # Getting the version number + app_url = release["html_url"] # Getting the application URL + changelog = release["changelog"] # Getting the changelog + release_date = release["published_at"] # Getting the release date + release_date = release_date.replace("T", " ").replace("Z", "") # Formatting the release date + + # Checking if the version has changed since the last time + cursor.execute( + "SELECT version FROM versions WHERE repo=?", + (app_name,), + ) + previous_version = cursor.fetchone() + if previous_version and previous_version[0] == version_number: + logger.info(f"The version of {app_name} has not changed. No notification sent.") + continue # Move on to the next application + + message = f"New version: {version_number}\nFor: {app_name}\nPublished on: {release_date}\nChangelog:\n{changelog}\n{app_url}" + # Updating the previous version for this application + cursor.execute( + "INSERT OR REPLACE INTO versions (repo, version, changelog) VALUES (?, ?, ?)", + (app_name, version_number, changelog), + ) + conn.commit() + + headers = { + "Authorization": f"Basic {auth}", + "Title": f"New version for {app_name}", + "Priority": "urgent", + "Markdown": "yes", + "Actions": f"view, Update {app_name}, {app_url}, clear=true", + } + response = requests.post(f"{url}", headers=headers, data=message) + if response.status_code == 200: + logger.info(f"Message sent to Ntfy for {app_name}") + continue + else: + logger.error(f"Failed to send message to Ntfy. Status code: {response.status_code}") + + +def docker_send_to_ntfy(releases, auth, url): + for release in releases: + app_name = release["repo"].split("/")[-1] # Getting the application name from the repo + digest_number = release["digest"] + app_url = release["html_url"] # Getting the application URL + release_date = release["published_at"] # Getting the release date + release_date = release_date.replace("T", " ").replace("Z", "") # Formatting the release date + + # Checking if the version has changed since the last time + cursor.execute( + "SELECT digest FROM docker_versions WHERE repo=?", + (app_name,), + ) + previous_digest = cursor.fetchone() + if previous_digest and previous_digest[0] == digest_number: + logger.info(f"The digest of {app_name} has not changed. No notification sent.") + continue # Move on to the next application + + message = f"New version: {digest_number}\nFor: {app_name}\nPublished on: {release_date}\n{app_url}" + # Updating the previous digest for this application + cursor.execute( + "INSERT OR REPLACE INTO docker_versions (repo, digest) VALUES (?, ?, ?)", + (app_name, digest_number), + ) + conn.commit() + + headers = { + "Authorization": f"Basic {auth}", + "Title": f"New version for {app_name}", + "Priority": "urgent", + "Markdown": "yes", + "Actions": f"view, Update {app_name}, {app_url}, clear=true", + } + response = requests.post(f"{url}", headers=headers, data=message) + if response.status_code == 200: + logger.info(f"Message sent to Ntfy for {app_name}") + continue + else: + logger.error(f"Failed to send message to Ntfy. Status code: {response.status_code}")