#!/usr/bin/env bash # shellcheck disable=SC2155 set -e # # Script to track waiting customer count and estimated travel time # of a Telekom appointment. # # Usage: # ./telekom_appointment_tracker.sh # # Arguments: # uuid 6-digit UUID sent by Telekom via https://termin.telekom.de/? # readonly uuid="$1" readonly wait_interval=60 readonly ajax_url="https://termin.telekom.de/ajax.php" readonly web_url="https://termin.telekom.de/?${uuid}" readonly title="Telekom appointment #${uuid}" state_changed=false customers_count=0 travel_time=0 RED="\033[0;31m" GREEN="\033[0;32m" NC="\033[0m" # # Generate request payload for Telekom AJAX endpoint. # function generate_payload() { echo "{\"uuid\":\"${uuid}\",\"humanInteraction\":true}" | base64 } # # Perform request to AJAX endpoint and parse result using jq with given query. # function perform_and_parse_request() { local query="$1" curl -X POST -sSL -d "$(generate_payload)" "${ajax_url}" | base64 -d | jq -r "$query" } # # Count waiting customers in queue. # function count_customers() { perform_and_parse_request '.kundenauftrag.auftragszaehler // empty' } # # Fetch technician's estimated travel time. # function get_travel_time() { perform_and_parse_request '.kundenauftrag.traveltime // empty' } # # Check if appointment is in waiting state. # function is_in_waiting_state() { local result="$(perform_and_parse_request 'if (.kundenauftrag | has("wartegrund")) then 0 else 1 end')" if [ -z "$result" ]; then return 1 fi return "$result" } # # Display number of waiting customers in queue. # # Prints a message to the console displaying the number of waiting customers # in queue. In addition, a notification is raised to raise attention. # function display_customer_count() { if [ "$customers_count" -le 0 ]; then local message="A technician is on its way." elif [ "$customers_count" -eq 1 ]; then local message="One customer left." else local message="${customers_count} customers left." fi if "$state_changed"; then echo -e "${GREEN}State changed:${NC} ${message}" osascript -e "display notification \"${message}\" with title \"${title}\" subtitle \"State changed\"" else echo "$message" osascript -e "display notification \"${message}\" with title \"${title}\"" fi } # # Display technician's travel time. # # Prints a message to the console displaying the technician's estimated # travel time. In addition, a notification is raised to raise attention. # function display_travel_time() { if [ "$travel_time" -le 0 ]; then local message="A technician should have arrived." elif [ "$travel_time" -eq 1 ]; then local message="A technician should arrive in less than one minute." else local message="A technician should arrive in less than ${travel_time} minutes." fi if "$state_changed"; then echo -e "${GREEN}State changed:${NC} ${message}" osascript -e "display notification \"${message}\" with title \"${title}\" subtitle \"State changed\"" else echo "$message" osascript -e "display notification \"${message}\" with title \"${title}\"" fi if [ "$travel_time" -le 0 ]; then exit fi } # # Display error message. # function display_error() { local message="$1" echo >&2 -e "${RED}${message}${NC}" } # Validate jq binary if ! which jq >/dev/null; then display_error "jq needs to be installed in your system." echo >&2 "Read more at https://jqlang.github.io/jq/download/." exit 1 fi # Validate given UUID if [ -z "$uuid" ]; then display_error "Please pass the 6-digit UUID you received from https://termin.telekom.de/?." exit 1 fi # Exit early if appointment is in waiting state if is_in_waiting_state; then display_error "Appointment is currently in waiting state." echo >&2 "For more details, visit ${web_url}." exit fi # Show link to website echo "Appointment website: ${web_url}" # Check every x seconds for current customers count and/or technician's travel time while true; do current_count="$(count_customers)" # If no customer count is provided, check if technician is already on its way if [ -z "$current_count" ]; then current_travel_time="$(get_travel_time)" fi # Show error if neither customer count nor travel time are accessible if [ -z "$current_count" ] && [ -z "$current_travel_time" ]; then display_error "Error while checking appointment details. Trying again in ${wait_interval} seconds..." sleep "$wait_interval" continue fi # Display notice if technician is on its way if [ "$current_travel_time" -ne "$travel_time" ]; then current_count=0 customers_count=0 travel_time="$current_travel_time" display_travel_time fi # Display notice about customers in queue if [ "${current_count:-0}" -ne "$customers_count" ]; then customers_count="$current_count" current_travel_time=0 travel_time=0 display_customer_count fi # Mark global state change state_changed=true # Exit if appointment is finished if [ "$customers_count" -le 0 ] && [ "$current_travel_time" -le 0 ]; then exit fi sleep "$wait_interval" done