Compare commits

..

No commits in common. "main" and "v1.0.0" have entirely different histories.
main ... v1.0.0

7 changed files with 47 additions and 121 deletions

View file

@ -1,25 +0,0 @@
name: Build Docker Image
on:
push:
branches:
- main
jobs:
build:
name: push docker image to docker hub
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: login to docker hub
id: docker-hub
env:
username: ${{secrets.DOCKER_USERNAME}}
password: ${{secrets.DOCKER_TOKEN}}
run: |
docker login -u $username -p $password
- name: build the docker image
id: build-docker-image
run: |
docker build -t michivonah/ep-alerts:latest .
- name: push the docker image
id: push-docker-image
run: docker push michivonah/ep-alerts:latest

1
.gitignore vendored
View file

@ -1,3 +1,2 @@
.env .env
__pycache__ __pycache__
venv

View file

@ -1,4 +1,4 @@
FROM python:3.12 FROM python:3.11
# Create directory # Create directory
RUN mkdir app RUN mkdir app
@ -11,7 +11,6 @@ COPY requirements.txt .
# Set enviromental variables # Set enviromental variables
ENV DISCORD_WEBHOOK "https://discord.com/api/webhooks/XXXXXXXXXXXXXX/YYYYYYYYYYYYYYYYYYYYYYYYY" ENV DISCORD_WEBHOOK "https://discord.com/api/webhooks/XXXXXXXXXXXXXX/YYYYYYYYYYYYYYYYYYYYYYYYY"
ENV SUBS "383533, 323530, 353030" ENV SUBS "383533, 323530, 353030"
ENV NOTIFICATION_TYPE "discord"
# Install needed packages # Install needed packages
RUN pip3 install --upgrade pip RUN pip3 install --upgrade pip

View file

@ -1,11 +1,10 @@
# Themepark Wait Time Alerts # Europapark Waitingtime Alerts via Discord Webhook
![](media/banner.jpg) A tool which alerts you when the waiting times of subscribed europapark attractions sinks or increase. Powered by the [wartezeiten.app](https://www.wartezeiten.app/page/api.html) API.
A tool which alerts you when the waiting times of subscribed attractions in your favourite themepark sinks or increase. The notifications are sent to a Discord webhook or to your ntfy-server. Powered by the [wartezeiten.app](https://www.wartezeiten.app/page/api.html) API.
GitHub: https://github.com/michivonah/themepark-alerts <br> GitHub: https://github.com/michivonah/europapark-alerts <br>
Docker: https://hub.docker.com/r/michivonah/ep-alerts Docker: https://hub.docker.com/r/michivonah/ep-alerts
Host it on your own server: Host it on your server:
1. Install docker on your system 1. Install docker on your system
```apt-get install docker.io docker-compose -y``` ```apt-get install docker.io docker-compose -y```
@ -16,15 +15,9 @@ Host it on your own server:
## Enviormental variables ## Enviormental variables
These environment variables are supported These environment variables are supported
| Variable | Description | Example | Required | | Variable | Description | Example |
| --- | --- | --- | --- | | --- | --- | --- |
| NOTIFICATION_TYPE | Define which type of notification you want use. Supported are: discord, ntfy | ``discord`` | yes | | DISCORD_WEBHOOK | The URL of your discord webhook | ``https://discord.com/api/webhooks/XXXXXXXXXXXXXX/YYYYYYYYYYYYYYYYYYYYYYYYY`` |
| CHECK_INTERVAL | Defines how often the API is requested and the waittimes are checked for updates (in seconds) | ``30`` | no | | SUBS | Your subscribed attractions with ID from wartezeiten.app API | ``383533,323530,353030`` |
| DISCORD_WEBHOOK | The URL of your discord webhook | ``https://discord.com/api/webhooks/XXXXXXXXXXXXXX/YYYYYYYYYYYYYYYYYYYYYYYYY`` | no* |
| NTFY_URL | The URL to your ntfy topic | ``https://ntfy.example.com/mytopic`` | no* |
| NTFY_ACCESS_TOKEN | Optional access token for authenticating against your ntfy server if authentication is enabled. | ``tk_2cdbcfea1702cc3bd2c874beab1`` | no |
| SUBS | Your subscribed attractions with ID from wartezeiten.app API | ``383533,323530,353030`` | yes |
| THEMEPARK | Select your desired themepark from the wartezeiten.app API. Defaults to ``europapark`` | ``europapark`` | no |
> Required enviromental variables: DISCORD_WEBHOOK, SUBS
> *Depending on the selected service for notifications (``NOTIFICATION_TYPE``) ether ``DISCORD_WEBHOOK`` or ``NTFY_URL`` is required.

72
main.py
View file

@ -1,10 +1,11 @@
# Themepark Wait Time Alerts # Europapark Waiting Time alerts to Discord
# Michi von Ah - October 2023 (Last Updated on October 2024) # Michi von Ah - October 2023
# Thanks to https://www.wartezeiten.app/ for their API # Thanks to https://www.wartezeiten.app/ for their API
import requests import requests
import os import os
from dotenv import load_dotenv from dotenv import load_dotenv
from discord_webhook import DiscordWebhook
import time import time
load_dotenv() load_dotenv()
@ -12,90 +13,49 @@ load_dotenv()
# Global defintions # Global defintions
subscribedAttractions = os.getenv('SUBS').split(",") subscribedAttractions = os.getenv('SUBS').split(",")
currentTimes = {} currentTimes = {}
refreshTime = int(os.getenv('CHECK_INTERVAL')) if os.getenv('CHECK_INTERVAL') else 30 refreshTime = 30
notificationType = os.getenv('NOTIFICATION_TYPE') if os.getenv('NOTIFICATION_TYPE') else "discord"
themepark = os.getenv('THEMEPARK') if os.getenv('THEMEPARK') else "europapark"
# Send messagess via specified notificationType # Send messagess via Discord Webhook
def sendMessage(message, notificationType): def sendMessage(message):
match notificationType.lower(): webhookUrl = os.getenv('DISCORD_WEBHOOK')
case "ntfy": webhook = DiscordWebhook(url=webhookUrl, content=message)
endpoint = os.getenv('NTFY_URL') response = webhook.execute()
accessToken = os.getenv('NTFY_ACCESS_TOKEN')
if accessToken:
header = {
"Authorization":f"Bearer {accessToken}"
}
try:
response = requests.post(url=endpoint, headers=header, data=message)
except Exception as error:
raise Exception(f"Got an error while sending the notification: {error}")
else:
try:
response = requests.post(url=endpoint, data=message)
except Exception as error:
raise Exception(f"Got an error while sending the notification: {error}")
return response return response
case "discord" | _:
endpoint = os.getenv('DISCORD_WEBHOOK')
data = {
"content": message,
}
try:
response = requests.post(url=endpoint, json=data)
return response
except Exception as error:
raise Exception(f"Got an error while sending the notification: {error}")
# Check for the current waiting times # Check for the current waiting times
def checkTimes(subscribedAttractions, themepark): def checkTimes(subscribedAttractions):
try:
endpoint = "https://api.wartezeiten.app/v1/waitingtimes" endpoint = "https://api.wartezeiten.app/v1/waitingtimes"
header = { header = {
"language":"de", "language":"de",
"park":themepark "park":"europapark"
} }
req = requests.get(url=endpoint, headers=header) req = requests.get(url = endpoint, headers = header)
except:
raise Exception(f"API Request to endpoint {endpoint} failed.")
try:
result = req.json() result = req.json()
except:
raise Exception("Format of API response is invalid. (JSON expected)")
try:
attractions = result attractions = result
for attraction in attractions: for attraction in attractions:
if isinstance(attraction, dict) and "code" in attraction:
if attraction["code"] in subscribedAttractions: if attraction["code"] in subscribedAttractions:
if attraction["status"] == "opened": if attraction["status"] == "opened":
refreshTime = 30 refreshTime = 30
if not attraction["code"] in currentTimes: currentTimes[attraction["code"]] = attraction["waitingtime"]; if not attraction["code"] in currentTimes: currentTimes[attraction["code"]] = attraction["waitingtime"];
if currentTimes[attraction["code"]] > attraction["waitingtime"]: if currentTimes[attraction["code"]] > attraction["waitingtime"]:
sendMessage(f"Waiting time of {attraction['name']} sank to {attraction['waitingtime']} Minutes!", notificationType) sendMessage(f"Waiting time of {attraction['name']} sank to {attraction['waitingtime']} Minutes!")
elif currentTimes[attraction["code"]] < attraction["waitingtime"]: elif currentTimes[attraction["code"]] < attraction["waitingtime"]:
sendMessage(f"Waiting time for {attraction['name']} increased to {attraction['waitingtime']} Minutes!", notificationType) sendMessage(f"Waiting time for {attraction['name']} increased to {attraction['waitingtime']} Minutes!")
currentTimes[attraction["code"]] = attraction["waitingtime"] currentTimes[attraction["code"]] = attraction["waitingtime"]
else: else:
refreshTime = 180 refreshTime = 180
else:
print(f"Info: Attraction was skipped because it has an invalid data structure. Affected attraction: {attraction}")
except Exception as error:
raise Exception(f"Got an error while checking for differences since the last API call. Error: {error}")
# Main Loop # Main Loop
# Checks every 30 seconds for changes in the waiting times of the subscribed attractions # Checks every 30 seconds for changes in the waiting times of the subscribed attractions
# If some attractions are closed the check will only be executed every 180 seconds # If some attractions are closed the check will only be executed every 180 seconds
if __name__ == '__main__': if __name__ == '__main__':
print("Themepark Wait Time Alerts") print("EP Waiting Time Alerting Tool")
print("By Michi von Ah") print("By Michi von Ah")
print("Big thanks to the wartezeiten.app API!") print("Big thanks to the wartezeiten.app API!")
while True: while True:
try: checkTimes(subscribedAttractions)
checkTimes(subscribedAttractions, themepark)
print(f"Checked for updates at {time.strftime('%H:%M:%S', time.localtime())}") print(f"Checked for updates at {time.strftime('%H:%M:%S', time.localtime())}")
except Exception as error:
raise Exception(error)
time.sleep(refreshTime) time.sleep(refreshTime)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 232 KiB

View file

@ -1,4 +1,4 @@
# requirements.txt # requirements.txt
python-dotenv==1.1.1 python-dotenv==1.0.0
pipenv==2025.0.4 #discord.py
requests==2.32.5 discord-webhook==1.3.0