Initial commit
This commit is contained in:
parent
22957fa34e
commit
0d04a0f790
2
.gitignore
vendored
2
.gitignore
vendored
@ -168,3 +168,5 @@ cython_debug/
|
|||||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
#.idea/
|
#.idea/
|
||||||
|
|
||||||
|
|
||||||
|
state.json
|
||||||
|
|||||||
11
README.md
11
README.md
@ -1,2 +1,13 @@
|
|||||||
# docker-repository-query
|
# docker-repository-query
|
||||||
|
|
||||||
|
|
||||||
|
## Necessary environment variables saved in .env
|
||||||
|
GITHUB_TOKEN=
|
||||||
|
|
||||||
|
DOCKER_TOKEN=
|
||||||
|
|
||||||
|
DOCKER_USERNAME=
|
||||||
|
|
||||||
|
MAIL_ADDRESS=
|
||||||
|
|
||||||
|
FROM_ADDRESS=
|
||||||
29
dockerhub_api.py
Normal file
29
dockerhub_api.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import requests
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
import os
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
DOCKER_TOKEN = os.getenv("DOCKER_TOKEN")
|
||||||
|
DOCKER_USERNAME = os.getenv("DOCKER_USERNAME")
|
||||||
|
|
||||||
|
def login_and_get_token():
|
||||||
|
login_url = "https://hub.docker.com/v2/users/login/"
|
||||||
|
response = requests.post(login_url,
|
||||||
|
json={"username": DOCKER_USERNAME, "password": DOCKER_TOKEN})
|
||||||
|
if response.status_code == 200:
|
||||||
|
token = response.json()["token"]
|
||||||
|
return token
|
||||||
|
else:
|
||||||
|
print(f"Login failed: {response.status_code} - {response.text}")
|
||||||
|
|
||||||
|
def find_package_version_with_tag(repo, tag):
|
||||||
|
token = login_and_get_token()
|
||||||
|
headers = {"Authorization": f"JWT {token}"}
|
||||||
|
tags_url = f"https://hub.docker.com/v2/repositories/{repo}/tags/{tag}?page_size=1"
|
||||||
|
tags_response = requests.get(tags_url, headers=headers)
|
||||||
|
id = tags_response.json()["id"]
|
||||||
|
return id
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print(find_package_version_with_tag("pihole/pihole", "latest"))
|
||||||
42
github_api.py
Normal file
42
github_api.py
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import requests
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
import os
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
GITHUB_TOKEN = os.getenv("GITHUB_TOKEN")
|
||||||
|
|
||||||
|
def find_package_version_with_tag(org , package, target_tag):
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
"Authorization": f"Bearer {GITHUB_TOKEN}",
|
||||||
|
"Accept": "application/vnd.github+json"
|
||||||
|
}
|
||||||
|
|
||||||
|
page = 1
|
||||||
|
per_page = 100
|
||||||
|
|
||||||
|
while True:
|
||||||
|
url = f"https://api.github.com/orgs/{org}/packages/container/{package}/versions"
|
||||||
|
params = {"per_page": per_page, "page": page}
|
||||||
|
|
||||||
|
response = requests.get(url, headers=headers, params=params)
|
||||||
|
if response.status_code != 200:
|
||||||
|
print(f"Error {response.status_code}: {response.text}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
versions = response.json()
|
||||||
|
if not versions:
|
||||||
|
print(f"Reached end of pages — tag '{target_tag}' not found.")
|
||||||
|
return None
|
||||||
|
|
||||||
|
for version in versions:
|
||||||
|
tags = version.get("metadata", {}).get("container", {}).get("tags", [])
|
||||||
|
if target_tag in tags:
|
||||||
|
print(f"Found tag '{target_tag}' on page {page}:\n")
|
||||||
|
return version["id"]
|
||||||
|
|
||||||
|
page += 1
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
find_package_version_with_tag("Suwayomi", "tachidesk", "stable")
|
||||||
45
query_and_compare.py
Normal file
45
query_and_compare.py
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
from github_api import find_package_version_with_tag as find_package_version_with_tag_github
|
||||||
|
from dockerhub_api import find_package_version_with_tag as find_package_version_with_tag_dockerhub
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
|
||||||
|
def retrieve_state ():
|
||||||
|
default_state = {
|
||||||
|
"suwayomi_id": "",
|
||||||
|
"pihole_id":""
|
||||||
|
}
|
||||||
|
if os.path.exists("state.json"):
|
||||||
|
with open("state.json", "r") as f:
|
||||||
|
return json.load(f)
|
||||||
|
else:
|
||||||
|
state = default_state.copy()
|
||||||
|
return state
|
||||||
|
|
||||||
|
def save_state(state):
|
||||||
|
with open("state.json", "w") as f:
|
||||||
|
json.dump(state, f, indent=2)
|
||||||
|
|
||||||
|
def check_for_new_suwayomi_version():
|
||||||
|
latest_online_version = find_package_version_with_tag_github("Suwayomi", "tachidesk", "stable")
|
||||||
|
local_state = retrieve_state()
|
||||||
|
if latest_online_version != local_state["suwayomi_id"]:
|
||||||
|
local_state["suwayomi_id"] = latest_online_version
|
||||||
|
save_state(local_state)
|
||||||
|
print("New Suwayomi version has been found")
|
||||||
|
return True
|
||||||
|
print("No new Suwayomi version found")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def check_for_new_pihole_version():
|
||||||
|
latest_online_version = find_package_version_with_tag_dockerhub("pihole/pihole", "latest")
|
||||||
|
local_state = retrieve_state()
|
||||||
|
if latest_online_version != local_state["pihole_id"]:
|
||||||
|
local_state["pihole_id"] = latest_online_version
|
||||||
|
save_state(local_state)
|
||||||
|
print("New Pi-hole version has been found")
|
||||||
|
return True
|
||||||
|
print("No new Pi-hole version found")
|
||||||
|
return False
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
check_for_new_pihole_version()
|
||||||
14
requirements.txt
Normal file
14
requirements.txt
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
blinker==1.9.0
|
||||||
|
certifi==2025.7.14
|
||||||
|
charset-normalizer==3.4.2
|
||||||
|
click==8.2.1
|
||||||
|
dotenv==0.9.9
|
||||||
|
Flask==3.1.1
|
||||||
|
idna==3.10
|
||||||
|
itsdangerous==2.2.0
|
||||||
|
Jinja2==3.1.6
|
||||||
|
MarkupSafe==3.0.2
|
||||||
|
python-dotenv==1.1.1
|
||||||
|
requests==2.32.4
|
||||||
|
urllib3==2.5.0
|
||||||
|
Werkzeug==3.1.3
|
||||||
19
send_mail.py
Normal file
19
send_mail.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import smtplib
|
||||||
|
from email.message import EmailMessage
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
import os
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
MAIL_ADDRESS = os.getenv("MAIL_ADDRESS")
|
||||||
|
FROM_ADDRESS = os.getenv("FROM_ADDRESS", "noreply@localhost")
|
||||||
|
|
||||||
|
def send_mail(subject):
|
||||||
|
msg = EmailMessage()
|
||||||
|
msg["From"] = FROM_ADDRESS
|
||||||
|
msg["To"] = MAIL_ADDRESS
|
||||||
|
msg["Subject"] = subject
|
||||||
|
msg.set_content("New Docker image is available")
|
||||||
|
|
||||||
|
with smtplib.SMTP("localhost", 25) as server:
|
||||||
|
server.send_message(msg)
|
||||||
22
webserver.py
Normal file
22
webserver.py
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
from query_and_compare import check_for_new_suwayomi_version,check_for_new_pihole_version
|
||||||
|
from flask import Flask
|
||||||
|
from send_mail import send_mail
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
@app.route('/suwayomi', methods=['GET'])
|
||||||
|
def handle_suwayomi():
|
||||||
|
print("Suwayomi handler invoked")
|
||||||
|
if check_for_new_suwayomi_version():
|
||||||
|
send_mail("New Suwayomi version available")
|
||||||
|
return '', 200
|
||||||
|
|
||||||
|
@app.route('/pihole', methods=['GET'])
|
||||||
|
def handle_pihole():
|
||||||
|
print("Pi-hole handler invoked")
|
||||||
|
if check_for_new_pihole_version():
|
||||||
|
send_mail("New Pi-hole version available")
|
||||||
|
return '', 200
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
app.run(host='0.0.0.0', port=5000)
|
||||||
Loading…
x
Reference in New Issue
Block a user