1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
|
#!/bin/bash
read stop
# function to provide data to a for loop
_jq() {
echo ${json} | base64 --decode | jq -r ${1}
}
_liveresult() {
stops=$(curl --fail --silent -H "App-Key: A4E247A48AAF12BF2E97D9F346E56" https://admin.libertybus.je/api/v1/stops/"${stop}")
stopname=$(echo $stops | jq '.[].name')
livetimes=$(curl --fail --silent -H "App-Key: A4E247A48AAF12BF2E97D9F346E56" https://admin.libertybus.je/api/v1/soj/stop_updates/${stop})
exitcode=$?
# sort livetimes by service_number and eta
livetimes=$(echo ${livetimes} | jq 'sort_by((.service_number | sub("[^0-9]$"; "") | tonumber), (.service_number | sub("[^A-Z]$"; "") | tostring), .eta)')
livetimeslen=$(echo ${livetimes} | jq '. | length')
if [ $exitcode != 0 ]; then
_curlerror
elif [ $livetimeslen = 0 ]; then
echo "No results found."
exit 1
elif [[ ${stopname,,} == *"bus"* ]] || [[ ${stopname,,} == *"station"* ]] || [[ ${stopname,,} == *"stand"* ]]; then
_rejectbusstation
else
for json in $(echo "${livetimes}" | jq -r '.[] | @base64'); do
if [[ $(_jq '.service_number') != $outroute ]]; then
result=$(echo $result | sed 's/,$//')
result="$result | Dest: $(_jq '.destination')[$(_jq '.service_number')] - ETAs: $(_jq '.eta'), "
else
result="$result $(_jq '.eta'), "
fi
outroute=$(_jq '.service_number')
done
result=$(echo $result | sed 's/,$//' | sed 's/|//' )
echo -e $result
exit 0
fi
}
_stopsreturn() {
stops=$(curl --fail --silent -H "App-Key: A4E247A48AAF12BF2E97D9F346E56" https://admin.libertybus.je/api/v1/stops/"${stop}")
exitcode=$?
stopslen=$(echo ${stops} | jq '. | length')
# if length of $stops array is 1 then only one bus stop matches and we can return live times for that stop
if [ $exitcode != 0 ]; then
_curlerror
elif [ $stopslen = 1 ]; then
stop=$(echo ${stops} | jq '.[].stop_id')
_liveresult
elif [ $stopslen = 0 ]; then
echo "No results found."
exit 1
# multiple stops returned in $stops so we will return stop names and codes so user can retry
else
for json in $(echo "${stops}" | jq -r '.[] | @base64'); do
result="$result Stop: $(_jq '.name') - Code: $(_jq '.stop_id') |"
#result="$result Code: $(_jq '.stop_id') |"
done
result=$(echo $result | sed 's/ |$//')
echo -e $result
exit 0
fi
}
_rejectbusstation() {
echo "If you want to see when the next bus for a given route leaves the bus station then try ""!bus <route>"" where <route> is a valid bus route or try ""!bus -h"" for help."
exit 1
}
# function for now in case I need to reuse somewhere else...
_help() {
echo ""$error"Usage: 'Usage: '!bus <input> (<time>)' where <input> is: a valid route number, this returns the next bus leaving the station, if <time> is also specified then the next bus after that time is returned; a full or partial bus stop name, if only one result is returned then live times for that stop are returned, if multiple results are returned then a list of matching stops are returned; a valid bus stop code, this returns live tops for that stop; -h --help, returns this help info."
exit 0
}
_curlerror() {
echo "cURL error $exitcode - exiting."
exit 1
}
_nextbus() {
if [ -z ${time} ]; then
time=$(date +"%H:%M")
fi
day=$(date +"%a" | tr [:upper:] [:lower:])
# set routeday to one of three timetable options
if [[ $(date +%u) -lt 6 ]]; then
routeday=mon_fri
else
routeday=$(date +"%a" | tr [:upper:] [:lower:])
fi
# select all stops from todays trips, where days_of_operation is true for tday, for a given service_number, where stop_name contains "Bus Station Stand"
nextbus=$(echo $timetables | jq -r --arg routeday "$routeday" --arg day "$day" --arg stop "$stop" '.timetables[] | select(.service_number == $stop) | .timetable.outbound[$routeday].trips[] | select(.days_of_operation[$day] == true) | .stops[] | select(.stop_name | contains("Bus Station Stand"))')
for json in $(echo "${nextbus}" | jq -r '. | @base64'); do
if [[ $(_jq '.departure_time') > $time ]]; then
echo "Next route "$stop $futuretime"leaving from $(_jq '.stop_name') at $(_jq '.departure_time')"
exit 0
fi
done
# if program didn't exit inside for loop then we know the next bus is on a future day so we need to check future days, unfortunately plenty of routes have days where no bus runs so we need to loop until we find the next day with a running bus
# for loop in range 7 used to prevent possible infinite loop with other methods - if there's not a bus for the next week then something is probably broken
for in in {1..7}; do
day=$(date --date="$i day" +"%a" | tr [:upper:] [:lower:])
case $day in
mon|tue|wed|thu|fri)
routeday=mon_fri;;
sat)
routeday=sat;;
sun)
routeday=sun;;
*) //
esac
nextbus=$(echo $timetables | jq -r --arg routeday "$routeday" --arg day "$day" --arg stop "$stop" '.timetables[] | select(.service_number == $stop) | .timetable.outbound[$routeday].trips[] | select(.days_of_operation[$day] == true) | .stops[] | select(.stop_name | contains("Bus Station Stand"))')
if [[ ! -z "${nextbus// }" ]]; then
echo $(echo "Next route "$stop $futuretime"leaving from $(echo $nextbus | jq -s '.[0].stop_name') at $(echo $nextbus | jq -s '.[0].departure_time') on $(date -d $day +%A)" | sed 's/"//g')
exit 0
fi
done
# if program didn't exit inside for loop then something is probably broken
echo "Something broken - hopefully no one ever sees this..."
exit 1
}
timetables=$(curl --fail --silent -H "App-Key: A4E247A48AAF12BF2E97D9F346E56" https://admin.libertybus.je/cache/timetables/timetable_full.json)
services=$(echo $timetables | jq '.timetables[].service_number')
if [ "$stop" == "-h" ] || [ "$stop" == "--help" ] || [[ -z "${stop// }" ]]; then
_help
# checks if input pattern matches a 4 digit bus stop code
elif [[ ${stop,,} == "source" ]]; then
echo "https://www.blatech.co.uk/ars/liberty-bus-live-times"
exit 0
elif [[ "$stop" =~ ^-?[0-9]+$ ]] && [ $(echo ${#stop} == 4) ]; then
_liveresult
# checks if input is a valid bus route
elif [[ ${services[@]} =~ ${stop^^} ]]; then
_nextbus
# if input has one space and something resembling a time then the user is probably trying to search for the next bus leaving the station for a given route after the given time
elif [[ $(echo $stop | tr -cd ' \t' | wc -c) == 1 ]] && [[ "$stop" =~ [0-9][0-9]:[0-9][0-9] ]]; then
time=$(echo $stop | cut -d ' ' -f2)
stop=$(echo $stop | cut -d ' ' -f1)
if [[ ! "$time" =~ ^(0[0-9]|1[0-9]|2[0-3]|[0-9]):[0-5][0-9]$ ]]; then
# prepend help output with $error
error="Invalid time, specify time with HH:MM '!bus <route> <time>' - "
_help
elif [[ ! ${services[@]} =~ ${stop^^} ]]; then
echo $stop
echo $services
# prepend help output with $error
error="Invalid route provided - "
_help
else
# futuretime adds clarity to _nextbus output
futuretime="after $time, "
_nextbus
fi
elif [[ ${stop,,} == *"bus"* ]] || [[ ${stop,,} == *"bus station"* ]] || [[ ${stop,,} == *"stand"* ]]; then
_rejectbusstation
# input not matching any of the ifs can be searched against API
else
_stopsreturn
fi
|