mirror of
https://github.com/BreizhHardware/ntfy_alerts.git
synced 2026-01-19 00:47:33 +01:00
Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
66e22f6788 | ||
|
|
71cf7baa32 | ||
|
|
8d26c2821c | ||
|
|
3e59106fa6 | ||
|
|
d6c0e4e08e | ||
|
|
4bfc6e254a | ||
| e863be9dc0 | |||
| e4f2ca9e49 | |||
| 996aad9c5e | |||
| b958689318 | |||
| 8800902bf1 | |||
| 8f50debb0a | |||
| c55b3f871e | |||
| 63594b910f | |||
| 6297ce14fd | |||
|
|
7a48c3da50 | ||
| 7c2b4e545c | |||
| d218c7a0bc | |||
| 694bfcaf6b | |||
|
|
b11bc64e52 | ||
|
|
d796d5b24f | ||
|
|
0be8d008c5 | ||
|
|
a14cc1848f | ||
|
|
350ad9bf6a | ||
|
|
76de8af42b | ||
|
|
3cfa54248f | ||
| a270978728 | |||
| 2a7305a4cf | |||
| f5fc6e38da | |||
| 4a57e9e2e1 | |||
| 1ef3dfa49d | |||
| 0e72fd80cc | |||
| 3b6f55e703 | |||
| 5b113d725b | |||
| 9b2cf22892 | |||
|
|
34b314d40f | ||
|
|
7a1808569e | ||
|
|
063c2db3a9 | ||
|
|
f68bc12902 | ||
| c728183bf4 | |||
| 6da0b5dac0 | |||
| 6c714abedd | |||
|
|
ecf162f6ed |
73
.github/workflows/create_release.yml
vendored
Normal file
73
.github/workflows/create_release.yml
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
name: Docker Build and Release
|
||||
|
||||
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 Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- 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
|
||||
tags: ${{ secrets.DOCKER_USERNAME }}/github-ntfy:latest
|
||||
|
||||
release-on-github:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Get the latest tag
|
||||
id: get_latest_tag
|
||||
run: echo "latest_tag=$(git describe --tags `git rev-list --tags --max-count=1`)" >> $GITHUB_ENV
|
||||
|
||||
- name: Increment version
|
||||
id: increment_version
|
||||
run: |
|
||||
latest_tag=${{ env.latest_tag }}
|
||||
if [ -z "$latest_tag" ]; then
|
||||
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"
|
||||
fi
|
||||
echo "new_version=$new_version" >> $GITHUB_ENV
|
||||
|
||||
- name: Read changelog
|
||||
id: read_changelog
|
||||
run: echo "changelog=$(base64 -w 0 CHANGELOG.md)" >> $GITHUB_ENV
|
||||
|
||||
- name: Decode changelog
|
||||
id: decode_changelog
|
||||
run: echo "${{ env.changelog }}" | base64 -d > decoded_changelog.txt
|
||||
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ env.new_version }}
|
||||
release_name: Release ${{ env.new_version }}
|
||||
body: ${{ steps.decode_changelog.outputs.changelog }}
|
||||
draft: false
|
||||
prerelease: false
|
||||
38
.github/workflows/create_release_arm64.yml
vendored
Normal file
38
.github/workflows/create_release_arm64.yml
vendored
Normal file
@@ -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
|
||||
38
.github/workflows/create_release_armv7.yml
vendored
Normal file
38
.github/workflows/create_release_armv7.yml
vendored
Normal file
@@ -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
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -400,3 +400,9 @@ _deps
|
||||
.nfs*
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/c++,linux,clion,cmake,clion+all
|
||||
|
||||
docker-compose.yml
|
||||
github-ntfy/
|
||||
github-ntfy/*
|
||||
|
||||
*.db
|
||||
4
CHANGELOG.md
Normal file
4
CHANGELOG.md
Normal file
@@ -0,0 +1,4 @@
|
||||
**New features**:
|
||||
- Add gotify compatibility please Read the README.md
|
||||
|
||||
**Full Changelog**: https://github.com/BreizhHardware/ntfy_alerts/compare/v1.4.3...v1.5
|
||||
19
Dockerfile
19
Dockerfile
@@ -1,18 +1,33 @@
|
||||
FROM python:3.11.8-alpine3.19
|
||||
|
||||
LABEL maintainer="BreizhHardware"
|
||||
LABEL version_number="1.4"
|
||||
|
||||
ADD ntfy.py /
|
||||
ADD ntfy_api.py /
|
||||
ADD requirements.txt /
|
||||
ADD entrypoint.sh /
|
||||
RUN apk add --no-cache sqlite-dev sqlite-libs gcc musl-dev
|
||||
ADD index.html /var/www/html/index.html
|
||||
ADD script.js /var/www/html/script.js
|
||||
RUN apk add --no-cache sqlite-dev sqlite-libs gcc musl-dev nginx
|
||||
RUN pip install -r requirements.txt
|
||||
RUN chmod 700 /entrypoint.sh
|
||||
|
||||
# Définir les variables d'environnement pour username et password
|
||||
ENV USERNAME="" \
|
||||
PASSWORD="" \
|
||||
NTFY_URL="" \
|
||||
GHNTFY_TIMEOUT="3600" \
|
||||
GHREPO=""
|
||||
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
|
||||
EXPOSE 5000 80
|
||||
|
||||
COPY nginx.conf /etc/nginx/nginx.conf
|
||||
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
|
||||
71
README.md
71
README.md
@@ -1,10 +1,13 @@
|
||||
# ntfy_alerts
|
||||
Personal ntfy alerts system
|
||||
|
||||
Feel free to contribute and to fork !
|
||||
|
||||
# Python ntfy.py
|
||||
## Description:
|
||||
This script is used to watch the github repos and send a notification to the ntfy server when a new release is published.
|
||||
|
||||
It can aloso watch Docker Hub repos and do the same as github.
|
||||
## Utilisation:
|
||||
auth and ntfy_url are required to be set as environment variables.
|
||||
|
||||
@@ -16,9 +19,8 @@ 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
|
||||
version: '3'
|
||||
services:
|
||||
github-ntfy:
|
||||
image: breizhhardware/github-ntfy:latest
|
||||
@@ -26,17 +28,76 @@ 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)
|
||||
- GHREPO=["username/repo1", "username/repo2"] # Default is empty
|
||||
- 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:
|
||||
- 80:80
|
||||
restart: unless-stopped
|
||||
````
|
||||
GHNTFY_TOKEN, need to have repo, read:org and read:user
|
||||
|
||||
Docker Hub repo: https://hub.docker.com/r/breizhhardware/github-ntfy
|
||||
## TODO:
|
||||
- [x] Dockerize the ntfy.py
|
||||
- [x] Add the watched repos list as a parameter
|
||||
- [x] Add the application version as a database
|
||||
- [ ] Add the watched repos list as a web interface
|
||||
- [x] Add the watched repos list as a web interface
|
||||
- [x] Add Docker Hub compatibility
|
||||
- [ ] Rework of the web interface
|
||||
- [x] Compatibility with Gotify
|
||||
- [ ] Compatibility with Discord Webhook
|
||||
- [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.
|
||||
|
||||
@@ -3,5 +3,8 @@
|
||||
# Génère le contenu du fichier auth.txt à partir des variables d'environnement
|
||||
echo -n "$USERNAME:$PASSWORD" | base64 > /auth.txt
|
||||
|
||||
# Démarrer nginx en arrière-plan
|
||||
nginx -g 'daemon off;' &
|
||||
|
||||
# Exécute le script Python
|
||||
exec python ./ntfy.py
|
||||
|
||||
76
index.html
Normal file
76
index.html
Normal file
@@ -0,0 +1,76 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Github-Ntfy Add a repo</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<script src="./script.js" defer></script>
|
||||
</head>
|
||||
<body class="bg-gradient-to-b from-stone-500 to-green-700">
|
||||
<h1 class="text-4xl font-semibold leading-10 text-gray-900 text-center">Github-Ntfy</h1>
|
||||
<div class="flex flex-row gap-2 justify-center items-center my-2 h-screen">
|
||||
<div class="flex flex-col gap-2 justify-center items-center my-2 h-screen border-double border-2 border-white p-2" id="github">
|
||||
<h1>Add a github repo</h1>
|
||||
<form id="addRepoForm">
|
||||
<div class="space-y-12">
|
||||
<div class="border-b border-gray-900/10 pb-12">
|
||||
<h2 class="text-base font-semibold leading-7 text-gray-900">Name of the github repo</h2>
|
||||
<div class="mt-10 grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
|
||||
<div class="sm:col-span-4">
|
||||
<div class="mt-2">
|
||||
<div class="flex rounded-md shadow-sm ring-1 ring-inset ring-gray-300 focus-within:ring-2 focus-within:ring-inset focus-within:ring-indigo-600 sm:max-w-md">
|
||||
<span class="flex select-none items-center pl-3 sm:text-sm">github.com/</span>
|
||||
<input type="text" name="repo" id="repo" autocomplete="repo" class="block flex-1 border-0 bg-transparent py-1.5 pl-1 placeholder:text-gray-600 focus:ring-0 sm:text-sm sm:leading-6" placeholder="BreizhHardware/ntfy_alerts">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-6 flex items-center justify-end gap-x-6">
|
||||
<button type="button" class="text-sm font-semibold leading-6 text-gray-900">Cancel</button>
|
||||
<button type="submit" class="rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
<div class="mt-8">
|
||||
<h2 class="text-base font-semibold leading-7 text-gray-900">Watched Github Repositories</h2>
|
||||
<ul id="watchedReposList" class="mt-4">
|
||||
<!-- Dynamically populated with JavaScript -->
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2 justify-center items-center my-2 h-screen border-double border-2 border-white p-2" id="docker">
|
||||
<h1>Add a docker repo</h1>
|
||||
<form id="addDockerRepoForm">
|
||||
<div class="space-y-12">
|
||||
<div class="border-b border-gray-900/10 pb-12">
|
||||
<h2 class="text-base font-semibold leading-7 text-gray-900">Name of the docker repo</h2>
|
||||
<div class="mt-10 grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
|
||||
<div class="sm:col-span-4">
|
||||
<div class="mt-2">
|
||||
<div class="flex rounded-md shadow-sm ring-1 ring-inset ring-gray-300 focus-within:ring-2 focus-within:ring-inset focus-within:ring-indigo-600 sm:max-w-md">
|
||||
<span class="flex select-none items-center pl-3 sm:text-sm">hub.docker.com/r/</span>
|
||||
<input type="text" name="dockerRepo" id="dockerRepo" autocomplete="dockerRepo" class="block flex-1 border-0 bg-transparent py-1.5 pl-1 placeholder:text-gray-600 focus:ring-0 sm:text-sm sm:leading-6" placeholder="breizhhardware/github-ntfy">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-6 flex items-center justify-end gap-x-6">
|
||||
<button type="button" class="text-sm font-semibold leading-6 text-gray-900">Cancel</button>
|
||||
<button type="submit" class="rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
<div class="mt-8">
|
||||
<h2 class="text-base font-semibold leading-7 text-gray-900">Watched Docker Repositories</h2>
|
||||
<ul id="watchedDockerReposList" class="mt-4">
|
||||
<!-- Dynamically populated with JavaScript -->
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="font-semibold leading-10 text-gray-900 text-center">I know this web interface is awfull but I'm not a web designer ^^.</p>
|
||||
</body>
|
||||
</html>
|
||||
60
nginx.conf
Normal file
60
nginx.conf
Normal file
@@ -0,0 +1,60 @@
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
include mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
|
||||
location / {
|
||||
root /var/www/html;
|
||||
index index.html;
|
||||
}
|
||||
|
||||
location /app_repo {
|
||||
proxy_pass http://127.0.0.1:5000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
location /watched_repos {
|
||||
proxy_pass http://127.0.0.1:5000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
location /delete_repo {
|
||||
proxy_pass http://127.0.0.1:5000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
location /app_docker_repo {
|
||||
proxy_pass http://127.0.0.1:5000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
location /watched_docker_repos {
|
||||
proxy_pass http://127.0.0.1:5000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
location /delete_docker_repo {
|
||||
proxy_pass http://127.0.0.1:5000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
}
|
||||
}
|
||||
231
ntfy.py
231
ntfy.py
@@ -2,36 +2,114 @@ import requests
|
||||
import time
|
||||
import os
|
||||
import logging
|
||||
import json
|
||||
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,
|
||||
)
|
||||
|
||||
# Configurer le logger
|
||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||
# Configuring the logger
|
||||
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}"
|
||||
|
||||
repo_list_env = os.environ.get('GHREPO')
|
||||
watched_repos_list = json.loads(repo_list_env) if repo_list_env else []
|
||||
docker_username = os.environ.get("DOCKER_USERNAME")
|
||||
docker_password = os.environ.get("DOCKER_PASSWORD")
|
||||
|
||||
if not watched_repos_list:
|
||||
logger.error("Aucun dépôt n'a été spécifié. Veuillez spécifier les dépôts à surveiller dans l'environnement GHREPO")
|
||||
exit(1)
|
||||
|
||||
# Connexion à la base de données pour stocker les versions précédentes
|
||||
db_path = 'ghntfy_versions.db'
|
||||
conn = sqlite3.connect(db_path)
|
||||
def create_dockerhub_token(username, password):
|
||||
url = "https://hub.docker.com//v2/users/login"
|
||||
headers = {"Content-Type": "application/json"}
|
||||
data = json.dumps({"username": username, "password": password})
|
||||
|
||||
response = requests.post(url, headers=headers, data=data)
|
||||
|
||||
if response.status_code == 200:
|
||||
token = response.json().get("token")
|
||||
if token:
|
||||
return token
|
||||
else:
|
||||
logger.error("Failed to get Docker Hub token.")
|
||||
else:
|
||||
logger.error(f"Failed to get Docker Hub token. Status code: {response.status_code}")
|
||||
return None
|
||||
|
||||
|
||||
docker_token = create_dockerhub_token(docker_username, docker_password)
|
||||
docker_header = {}
|
||||
if 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,
|
||||
)
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Création de la table si elle n'existe pas
|
||||
cursor.execute('''CREATE TABLE IF NOT EXISTS versions
|
||||
(repo TEXT PRIMARY KEY, version TEXT, changelog TEXT)''')
|
||||
# Creating the table if it does not exist
|
||||
cursor.execute(
|
||||
"""CREATE TABLE IF NOT EXISTS versions
|
||||
(repo TEXT PRIMARY KEY, version TEXT, changelog TEXT)"""
|
||||
)
|
||||
conn.commit()
|
||||
|
||||
logger.info("Démarrage de la surveillance des versions...")
|
||||
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)
|
||||
cursor2 = conn2.cursor()
|
||||
|
||||
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)"""
|
||||
)
|
||||
conn2.commit()
|
||||
|
||||
|
||||
def get_watched_repos():
|
||||
cursor2.execute("SELECT * FROM watched_repos")
|
||||
watched_repos_rows = cursor2.fetchall()
|
||||
watched_repos = []
|
||||
for repo in watched_repos_rows:
|
||||
watched_repos.append(repo[1])
|
||||
return watched_repos
|
||||
|
||||
|
||||
def get_docker_watched_repos():
|
||||
cursor2.execute("SELECT * FROM docker_watched_repos")
|
||||
watched_repos_rows = cursor2.fetchall()
|
||||
watched_repos = []
|
||||
for repo in watched_repos_rows:
|
||||
watched_repos.append(repo[1])
|
||||
return watched_repos
|
||||
|
||||
|
||||
def start_api():
|
||||
subprocess.Popen(["python", "ntfy_api.py"])
|
||||
|
||||
|
||||
def get_latest_releases(watched_repos):
|
||||
@@ -42,72 +120,95 @@ def get_latest_releases(watched_repos):
|
||||
if response.status_code == 200:
|
||||
release_info = response.json()
|
||||
changelog = get_changelog(repo)
|
||||
releases.append({
|
||||
"repo": repo,
|
||||
"name": release_info["name"],
|
||||
"tag_name": release_info["tag_name"],
|
||||
"html_url": release_info["html_url"],
|
||||
"changelog": changelog
|
||||
})
|
||||
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}/tags/latest"
|
||||
response = requests.get(url, headers=docker_header)
|
||||
if response.status_code == 200:
|
||||
release_info = response.json()
|
||||
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,
|
||||
}
|
||||
)
|
||||
else:
|
||||
logger.error(f"Failed to fetch Docker Hub info for {repo}")
|
||||
return releases
|
||||
|
||||
|
||||
def get_changelog(repo):
|
||||
url = f"https://api.github.com/repos/{repo}/releases"
|
||||
response = requests.get(url, headers=github_headers)
|
||||
if response.status_code == 200:
|
||||
releases = response.json()
|
||||
if releases:
|
||||
latest_release = releases[0]
|
||||
if 'body' in latest_release:
|
||||
return latest_release['body']
|
||||
return "Changelog non disponible"
|
||||
|
||||
|
||||
def send_to_ntfy(releases, auth, url):
|
||||
for release in releases:
|
||||
app_name = release['repo'].split('/')[-1] # Obtenir le nom de l'application à partir du repo
|
||||
version_number = release['tag_name'] # Obtenir le numéro de version
|
||||
app_url = release['html_url'] # Obtenir l'URL de l'application
|
||||
changelog = release['changelog'] # Obtenir le changelog
|
||||
|
||||
# Vérifier si la version a changé depuis la dernière fois
|
||||
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"La version de {app_name} n'a pas changé. Pas de notification envoyée.")
|
||||
continue # Passer à l'application suivante
|
||||
|
||||
message = f"Nouvelle version: {version_number}\nPour: {app_name}\nChangelog:\n{changelog}\n{app_url}"
|
||||
# Mettre à jour la version précédente pour cette application
|
||||
cursor.execute("INSERT OR REPLACE INTO versions (repo, version, changelog) VALUES (?, ?, ?)",
|
||||
(app_name, version_number, changelog))
|
||||
conn.commit()
|
||||
|
||||
headers = {"Authorization": f"Basic {auth}", "Content-Type": "text/plain"}
|
||||
response = requests.post(f"{url}", headers=headers, data=message)
|
||||
if response.status_code == 200:
|
||||
logger.info(f"Message envoyé à Ntfy pour {app_name}")
|
||||
continue
|
||||
else:
|
||||
logger.error(f"Échec de l'envoi du message à Ntfy. Code d'état : {response.status_code}")
|
||||
latest_release_list = releases[0]
|
||||
if "body" in latest_release_list:
|
||||
return latest_release_list["body"]
|
||||
return "Changelog not available"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
with open('/auth.txt', 'r') as f:
|
||||
start_api()
|
||||
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:
|
||||
latest_release = get_latest_releases(watched_repos_list)
|
||||
if latest_release:
|
||||
send_to_ntfy(latest_release, auth, ntfy_url)
|
||||
time.sleep(timeout) # Attendre une heure avant de vérifier à nouveau
|
||||
github_watched_repos_list = get_watched_repos()
|
||||
github_latest_release = get_latest_releases(github_watched_repos_list)
|
||||
docker_watched_repos_list = get_docker_watched_repos()
|
||||
docker_latest_release = get_latest_docker_releases(docker_watched_repos_list)
|
||||
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")
|
||||
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"
|
||||
)
|
||||
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")
|
||||
|
||||
207
ntfy_api.py
Normal file
207
ntfy_api.py
Normal file
@@ -0,0 +1,207 @@
|
||||
from flask import Flask, request, jsonify
|
||||
from flask_cors import CORS
|
||||
import sqlite3
|
||||
|
||||
app = Flask(__name__)
|
||||
CORS(app)
|
||||
app.logger.setLevel("WARNING")
|
||||
|
||||
|
||||
def get_db_connection():
|
||||
conn = sqlite3.connect("/github-ntfy/watched_repos.db")
|
||||
conn.row_factory = sqlite3.Row
|
||||
return conn
|
||||
|
||||
|
||||
def close_db_connection(conn):
|
||||
conn.close()
|
||||
|
||||
|
||||
@app.route("/app_repo", methods=["POST"])
|
||||
def app_repo():
|
||||
data = request.json
|
||||
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,
|
||||
)
|
||||
|
||||
# Établir une connexion à la base de données
|
||||
conn = get_db_connection()
|
||||
cursor = conn.cursor()
|
||||
|
||||
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,),
|
||||
)
|
||||
existing_repo = cursor.fetchone()
|
||||
if existing_repo:
|
||||
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,),
|
||||
)
|
||||
conn.commit()
|
||||
return jsonify({"message": f"The GitHub repo {repo} as been added to the watched repos."})
|
||||
finally:
|
||||
# Fermer la connexion à la base de données
|
||||
close_db_connection(conn)
|
||||
|
||||
|
||||
@app.route("/app_docker_repo", methods=["POST"])
|
||||
def app_docker_repo():
|
||||
data = request.json
|
||||
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,
|
||||
)
|
||||
|
||||
# Établir une connexion à la base de données
|
||||
conn = get_db_connection()
|
||||
cursor = conn.cursor()
|
||||
|
||||
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,),
|
||||
)
|
||||
existing_repo = cursor.fetchone()
|
||||
if existing_repo:
|
||||
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,),
|
||||
)
|
||||
conn.commit()
|
||||
return jsonify({"message": f"The Docker repo {repo} as been added to the watched repos."})
|
||||
finally:
|
||||
# Fermer la connexion à la base de données
|
||||
close_db_connection(conn)
|
||||
|
||||
|
||||
@app.route("/watched_repos", methods=["GET"])
|
||||
def get_watched_repos():
|
||||
db = get_db_connection()
|
||||
cursor = db.cursor()
|
||||
cursor.execute("SELECT repo FROM watched_repos")
|
||||
watched_repos = [repo[0] for repo in cursor.fetchall()]
|
||||
cursor.close()
|
||||
db.close()
|
||||
return jsonify(watched_repos)
|
||||
|
||||
|
||||
@app.route("/watched_docker_repos", methods=["GET"])
|
||||
def get_watched_docker_repos():
|
||||
db = get_db_connection()
|
||||
cursor = db.cursor()
|
||||
cursor.execute("SELECT repo FROM docker_watched_repos")
|
||||
watched_repos = [repo[0] for repo in cursor.fetchall()]
|
||||
cursor.close()
|
||||
db.close()
|
||||
return jsonify(watched_repos)
|
||||
|
||||
|
||||
@app.route("/delete_repo", methods=["POST"])
|
||||
def delete_repo():
|
||||
data = request.json
|
||||
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,
|
||||
)
|
||||
|
||||
# Établir une connexion à la base de données
|
||||
conn = get_db_connection()
|
||||
cursor = conn.cursor()
|
||||
|
||||
try:
|
||||
# Vérifier si le dépôt existe dans la base de données
|
||||
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,
|
||||
)
|
||||
|
||||
# Supprimer le dépôt de la base de données
|
||||
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:
|
||||
# Fermer la connexion à la base de données
|
||||
close_db_connection(conn)
|
||||
|
||||
|
||||
@app.route("/delete_docker_repo", methods=["POST"])
|
||||
def delete_docker_repo():
|
||||
data = request.json
|
||||
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,
|
||||
)
|
||||
|
||||
# Établir une connexion à la base de données
|
||||
conn = get_db_connection()
|
||||
cursor = conn.cursor()
|
||||
|
||||
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,),
|
||||
)
|
||||
existing_repo = cursor.fetchone()
|
||||
if not existing_repo:
|
||||
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,),
|
||||
)
|
||||
conn.commit()
|
||||
return jsonify({"message": f"The Docker repo {repo} as been deleted from the watched repos."})
|
||||
finally:
|
||||
# Fermer la connexion à la base de données
|
||||
close_db_connection(conn)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(debug=False)
|
||||
2
pyproject.toml
Normal file
2
pyproject.toml
Normal file
@@ -0,0 +1,2 @@
|
||||
[tool.black]
|
||||
line-length = 120
|
||||
@@ -1,2 +1,4 @@
|
||||
requests==2.31.0
|
||||
pysqlite3==0.5.2
|
||||
pysqlite3==0.5.2
|
||||
flask==3.0.2
|
||||
flask-cors==4.0.0
|
||||
158
script.js
Normal file
158
script.js
Normal file
@@ -0,0 +1,158 @@
|
||||
document.getElementById('addRepoForm').addEventListener('submit', function(event) {
|
||||
event.preventDefault();
|
||||
let repoName = document.getElementById('repo').value;
|
||||
fetch('/app_repo', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({repo: repoName})
|
||||
})
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
// Si la requête s'est bien déroulée, actualiser la liste des dépôts surveillés
|
||||
refreshWatchedRepos();
|
||||
} else {
|
||||
throw new Error('Erreur lors de l\'ajout du dépôt');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById('addDockerRepoForm').addEventListener('submit', function(event) {
|
||||
event.preventDefault();
|
||||
let repoName = document.getElementById('dockerRepo').value;
|
||||
fetch('/app_docker_repo', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({repo: repoName})
|
||||
})
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
// Si la requête s'est bien déroulée, actualiser la liste des dépôts surveillés
|
||||
refreshWatchedRepos();
|
||||
} else {
|
||||
throw new Error('Erreur lors de l\'ajout du dépôt');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
});
|
||||
});
|
||||
|
||||
function refreshWatchedRepos() {
|
||||
fetch('/watched_repos')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const watchedReposList = document.getElementById('watchedReposList');
|
||||
// Vider la liste actuelle
|
||||
watchedReposList.innerHTML = '';
|
||||
// Ajouter chaque dépôt surveillé à la liste
|
||||
data.forEach(repo => {
|
||||
const listItem = document.createElement('li');
|
||||
const repoName = document.createElement('span');
|
||||
repoName.textContent = repo;
|
||||
repoName.className = 'repo-name';
|
||||
listItem.appendChild(repoName);
|
||||
|
||||
const deleteButton = document.createElement('button');
|
||||
deleteButton.textContent = ' X';
|
||||
deleteButton.className = 'delete-btn text-red-500 ml-2';
|
||||
deleteButton.addEventListener('click', () => {
|
||||
// Remove the repo from the watched repos
|
||||
// This is a placeholder. Replace it with your actual code to remove the repo from the watched repos.
|
||||
removeRepoFromWatchedRepos(repo);
|
||||
|
||||
// Remove the repo from the DOM
|
||||
listItem.remove();
|
||||
});
|
||||
listItem.appendChild(deleteButton);
|
||||
|
||||
watchedReposList.appendChild(listItem);
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
});
|
||||
|
||||
fetch('/watched_docker_repos')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
const watchedDockerReposList = document.getElementById('watchedDockerReposList');
|
||||
// Vider la liste actuelle
|
||||
watchedDockerReposList.innerHTML = '';
|
||||
// Ajouter chaque dépôt surveillé à la liste
|
||||
data.forEach(repo => {
|
||||
const listItem = document.createElement('li');
|
||||
const repoName = document.createElement('span');
|
||||
repoName.textContent = repo;
|
||||
repoName.className = 'repo-name';
|
||||
listItem.appendChild(repoName);
|
||||
|
||||
const deleteButton = document.createElement('button');
|
||||
deleteButton.textContent = ' X';
|
||||
deleteButton.className = 'delete-btn text-red-500 ml-2';
|
||||
deleteButton.addEventListener('click', () => {
|
||||
// Remove the repo from the watched repos
|
||||
// This is a placeholder. Replace it with your actual code to remove the repo from the watched repos.
|
||||
removeDockerRepoFromWatchedRepos(repo);
|
||||
|
||||
// Remove the repo from the DOM
|
||||
listItem.remove();
|
||||
});
|
||||
listItem.appendChild(deleteButton);
|
||||
|
||||
watchedDockerReposList.appendChild(listItem);
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
});
|
||||
}
|
||||
|
||||
function removeRepoFromWatchedRepos(repo) {
|
||||
fetch('/delete_repo', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({repo: repo})
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error('Erreur lors de la suppression du dépôt');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
});
|
||||
}
|
||||
|
||||
function removeDockerRepoFromWatchedRepos(repo) {
|
||||
fetch('/delete_docker_repo', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({repo: repo})
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error('Erreur lors de la suppression du dépôt');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
});
|
||||
}
|
||||
|
||||
// Appeler la fonction pour charger les dépôts surveillés au chargement de la page
|
||||
refreshWatchedRepos();
|
||||
98
send_gotify.py
Normal file
98
send_gotify.py
Normal file
@@ -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}")
|
||||
98
send_ntfy.py
Normal file
98
send_ntfy.py
Normal file
@@ -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}")
|
||||
Reference in New Issue
Block a user