mirror of
https://github.com/michivonah/themepark-alerts.git
synced 2025-12-22 20:36:27 +01:00
Compare commits
11 commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f3d3fced24 | |||
| 8ac30fd663 | |||
| 566b7e8de1 | |||
| 85d05e0e66 | |||
| 0988256239 | |||
| 5e07460615 | |||
| 921442289a | |||
| 06ba3ef0e1 | |||
| 7522a8026f | |||
| 6cbdb6a61e | |||
| ff4f5e10ae |
7 changed files with 121 additions and 47 deletions
25
.github/workflows/image-build.yml
vendored
Normal file
25
.github/workflows/image-build.yml
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
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
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -1,2 +1,3 @@
|
||||||
.env
|
.env
|
||||||
__pycache__
|
__pycache__
|
||||||
|
venv
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
FROM python:3.11
|
FROM python:3.12
|
||||||
|
|
||||||
# Create directory
|
# Create directory
|
||||||
RUN mkdir app
|
RUN mkdir app
|
||||||
|
|
@ -11,6 +11,7 @@ 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
|
||||||
|
|
|
||||||
25
README.md
25
README.md
|
|
@ -1,10 +1,11 @@
|
||||||
# Europapark Waitingtime Alerts via Discord Webhook
|
# Themepark Wait Time Alerts
|
||||||
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/europapark-alerts <br>
|
GitHub: https://github.com/michivonah/themepark-alerts <br>
|
||||||
Docker: https://hub.docker.com/r/michivonah/ep-alerts
|
Docker: https://hub.docker.com/r/michivonah/ep-alerts
|
||||||
|
|
||||||
Host it on your server:
|
Host it on your own 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```
|
||||||
|
|
@ -15,9 +16,15 @@ Host it on your server:
|
||||||
## Enviormental variables
|
## Enviormental variables
|
||||||
These environment variables are supported
|
These environment variables are supported
|
||||||
|
|
||||||
| Variable | Description | Example |
|
| Variable | Description | Example | Required |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| DISCORD_WEBHOOK | The URL of your discord webhook | ``https://discord.com/api/webhooks/XXXXXXXXXXXXXX/YYYYYYYYYYYYYYYYYYYYYYYYY`` |
|
| NOTIFICATION_TYPE | Define which type of notification you want use. Supported are: discord, ntfy | ``discord`` | yes |
|
||||||
| SUBS | Your subscribed attractions with ID from wartezeiten.app API | ``383533,323530,353030`` |
|
| CHECK_INTERVAL | Defines how often the API is requested and the waittimes are checked for updates (in seconds) | ``30`` | no |
|
||||||
|
| 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.
|
||||||
106
main.py
106
main.py
|
|
@ -1,11 +1,10 @@
|
||||||
# Europapark Waiting Time alerts to Discord
|
# Themepark Wait Time Alerts
|
||||||
# Michi von Ah - October 2023
|
# Michi von Ah - October 2023 (Last Updated on October 2024)
|
||||||
# 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()
|
||||||
|
|
@ -13,49 +12,90 @@ load_dotenv()
|
||||||
# Global defintions
|
# Global defintions
|
||||||
subscribedAttractions = os.getenv('SUBS').split(",")
|
subscribedAttractions = os.getenv('SUBS').split(",")
|
||||||
currentTimes = {}
|
currentTimes = {}
|
||||||
refreshTime = 30
|
refreshTime = int(os.getenv('CHECK_INTERVAL')) if os.getenv('CHECK_INTERVAL') else 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 Discord Webhook
|
# Send messagess via specified notificationType
|
||||||
def sendMessage(message):
|
def sendMessage(message, notificationType):
|
||||||
webhookUrl = os.getenv('DISCORD_WEBHOOK')
|
match notificationType.lower():
|
||||||
webhook = DiscordWebhook(url=webhookUrl, content=message)
|
case "ntfy":
|
||||||
response = webhook.execute()
|
endpoint = os.getenv('NTFY_URL')
|
||||||
return response
|
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
|
||||||
|
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):
|
def checkTimes(subscribedAttractions, themepark):
|
||||||
endpoint = "https://api.wartezeiten.app/v1/waitingtimes"
|
try:
|
||||||
|
endpoint = "https://api.wartezeiten.app/v1/waitingtimes"
|
||||||
|
|
||||||
header = {
|
header = {
|
||||||
"language":"de",
|
"language":"de",
|
||||||
"park":"europapark"
|
"park":themepark
|
||||||
}
|
}
|
||||||
|
|
||||||
req = requests.get(url = endpoint, headers = header)
|
req = requests.get(url=endpoint, headers=header)
|
||||||
result = req.json()
|
except:
|
||||||
attractions = result
|
raise Exception(f"API Request to endpoint {endpoint} failed.")
|
||||||
for attraction in attractions:
|
try:
|
||||||
if attraction["code"] in subscribedAttractions:
|
result = req.json()
|
||||||
if attraction["status"] == "opened":
|
except:
|
||||||
refreshTime = 30
|
raise Exception("Format of API response is invalid. (JSON expected)")
|
||||||
if not attraction["code"] in currentTimes: currentTimes[attraction["code"]] = attraction["waitingtime"];
|
try:
|
||||||
if currentTimes[attraction["code"]] > attraction["waitingtime"]:
|
attractions = result
|
||||||
sendMessage(f"Waiting time of {attraction['name']} sank to {attraction['waitingtime']} Minutes!")
|
for attraction in attractions:
|
||||||
elif currentTimes[attraction["code"]] < attraction["waitingtime"]:
|
if isinstance(attraction, dict) and "code" in attraction:
|
||||||
sendMessage(f"Waiting time for {attraction['name']} increased to {attraction['waitingtime']} Minutes!")
|
if attraction["code"] in subscribedAttractions:
|
||||||
currentTimes[attraction["code"]] = attraction["waitingtime"]
|
if attraction["status"] == "opened":
|
||||||
|
refreshTime = 30
|
||||||
|
if not attraction["code"] in currentTimes: currentTimes[attraction["code"]] = attraction["waitingtime"];
|
||||||
|
if currentTimes[attraction["code"]] > attraction["waitingtime"]:
|
||||||
|
sendMessage(f"Waiting time of {attraction['name']} sank to {attraction['waitingtime']} Minutes!", notificationType)
|
||||||
|
elif currentTimes[attraction["code"]] < attraction["waitingtime"]:
|
||||||
|
sendMessage(f"Waiting time for {attraction['name']} increased to {attraction['waitingtime']} Minutes!", notificationType)
|
||||||
|
currentTimes[attraction["code"]] = attraction["waitingtime"]
|
||||||
|
else:
|
||||||
|
refreshTime = 180
|
||||||
else:
|
else:
|
||||||
refreshTime = 180
|
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("EP Waiting Time Alerting Tool")
|
print("Themepark Wait Time Alerts")
|
||||||
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:
|
||||||
checkTimes(subscribedAttractions)
|
try:
|
||||||
print(f"Checked for updates at {time.strftime('%H:%M:%S', time.localtime())}")
|
checkTimes(subscribedAttractions, themepark)
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
|
||||||
BIN
media/banner.jpg
Normal file
BIN
media/banner.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 232 KiB |
|
|
@ -1,4 +1,4 @@
|
||||||
# requirements.txt
|
# requirements.txt
|
||||||
python-dotenv==1.0.0
|
python-dotenv==1.1.1
|
||||||
#discord.py
|
pipenv==2025.0.4
|
||||||
discord-webhook==1.3.0
|
requests==2.32.5
|
||||||
Loading…
Add table
Add a link
Reference in a new issue