Last active
June 7, 2021 12:26
-
-
Save PJUllrich/a7805692469f317f9e8ee8a4c09a61ad to your computer and use it in GitHub Desktop.
Checks for available appointments in the "Bürgeramt" in Cologne and notifies via Pushover
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Terminvergabe do | |
@moduledoc """ | |
This script checks for available appointments in the "Bürgeramt" (city hall) | |
every 5min and notifies a user via Pushover if new appointments become were added. | |
In order to use Pushover, you must configure the following environment variables: | |
PUSHOVER_USER | |
PUSHOVER_TOKEN | |
Unfortunately, the "book the appointment"-link received from the website does | |
not work because the website is not stateless, but uses some PHP-state in order | |
to save which type of appointment you want to book. | |
After receiving a notification through this script, you must then go yourself | |
to https://termine-online.stadt-koeln.de and book the appointment. | |
This script is simply a notifier. | |
""" | |
@base_url "https://termine-online.stadt-koeln.de" | |
@request_path "/index.php" | |
@file_path "./termine" | |
@company "stadtkoeln" | |
@year Date.utc_today().year | |
@month Date.utc_today().month | |
@step "2" | |
@aemter %{ | |
1 => "Chorweiler", | |
2 => "Ehrenfeld", | |
3 => "Innenstadt", | |
4 => "Kalk", | |
5 => "Lindenthal", | |
6 => "Mülheim", | |
7 => "Nippes", | |
8 => "Porz", | |
9 => "Rodenkirchen" | |
} | |
# 10sec | |
@sleep_between_requests 10_000 | |
# 5min | |
@sleep_between_checks 5 * 60 * 1000 | |
def check_appointments do | |
maybe_create_termine_dir() | |
for amt_nummer <- Map.keys(@aemter) do | |
req_url = @base_url <> @request_path | |
HTTPoison.get!(req_url, [], | |
params: %{ | |
company: @company, | |
step: @step, | |
year: @year, | |
month: @month, | |
cur_cause: amt_nummer | |
} | |
) | |
|> find_appointments(amt_nummer) | |
:timer.sleep(@sleep_between_requests) | |
end | |
IO.inspect( | |
""" | |
------------------------------------------------------------------------------------- | |
""" | |
) | |
:timer.sleep(@sleep_between_checks) | |
check_appointments() | |
end | |
defp find_appointments(%{body: html}, amt_nummer) do | |
{:ok, document} = Floki.parse_document(html) | |
appointments = Floki.find(document, "a.nat_calendar_weekday_bookable") | |
if appointments != [] do | |
for appointment <- appointments do | |
parse_appointment(appointment, amt_nummer) | |
end | |
end | |
end | |
defp parse_appointment(appointment, amt_nummer) do | |
amt_name = Map.get(@aemter, amt_nummer) | |
[link] = Floki.attribute(appointment, "href") | |
[_, day, date] = Floki.children(appointment) | |
day = String.trim(day) | |
date_text = Floki.text(date) | |
datum = day <> date_text | |
full_link = @base_url <> link | |
maybe_send_notification(amt_name, datum, full_link) | |
end | |
defp maybe_send_notification(amt_name, datum, link) do | |
if not termin_bekannt?(amt_name, datum) do | |
IO.inspect("#{amt_name}: #{datum} - #{link}") | |
push_notification(amt_name, datum) | |
save_termin(amt_name, datum) | |
end | |
end | |
defp push_notification(amt_name, datum) do | |
message = %{ | |
data: "#{amt_name}: #{datum}", | |
title: "Neuer Termin in Köln", | |
priority: 0 | |
} | |
Pushover.Api.Messages.send(message) | |
end | |
defp termin_bekannt?(amt_name, datum) do | |
path = filename(amt_name) | |
if File.exists?(path) do | |
path | |
|> File.stream!() | |
|> CSV.decode!() | |
|> Enum.reduce(false, fn [item], exists? -> exists? || item == datum end) | |
else | |
false | |
end | |
end | |
defp maybe_create_termine_dir do | |
File.mkdir_p(@file_path) | |
end | |
defp save_termin(amt_name, datum) do | |
path = filename(amt_name) | |
File.write!(path, "#{datum}\n", [:append]) | |
end | |
defp filename(amt_name) do | |
"#{@file_path}/#{amt_name}.csv" | |
end | |
end | |
Mix.install([:csv, :httpoison, :floki, :pushover]) | |
Terminvergabe.check_appointments() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment