Skip to content

Instantly share code, notes, and snippets.

@tichytom
Last active March 15, 2025 17:50
Show Gist options
  • Save tichytom/f162670602185d959654263d443fedda to your computer and use it in GitHub Desktop.
Save tichytom/f162670602185d959654263d443fedda to your computer and use it in GitHub Desktop.
Prague Public transport departure board for BASH

How to install

Get API KEY

Replace INSERT_YOUR_API_KEY_HERE with original API key.

After registration your get API key here: https://api.golemio.cz/api-keys/auth/

SYSTEM REQUIREMENTS

  • curl
  • jq
  • join
  • awk, sed, grep

Optional

  • tput in package ncurses-bin
  • wget (only check if internet is available)
#!/bin/bash
green=$(tput setaf 10) #Jede_včas
red=$(tput setaf 1) #Jede_pozdě/brzo
yellow=$(tput setaf 208) #Jede_lehce_pozdě
norm=$(tput sgr0) #Normální_barvy
acko=$(tput setaf 35) #Linka_A
becko=$(tput setaf 214) #Linka_B
cecko=$(tput setaf 160) #Linka_C
tram=$(tput setaf 88) #Tramvaje
bus=$(tput setaf 31) #Autobusy
vlak=$(tput setaf 18) #Vlaky
xkob=$(tput setaf 31 && tput setab 208) #Náhradní_autobusy
xkot=$(tput setaf 88 && tput setab 208) #Náhradní_tramvaje
ld=$(tput setaf 184) #Lanovka_na_Petřín
privoz=$(tput setaf 6) #Přívozy
region=$(tput sgr0) #Příměstské_autobusy
noctram=$(tput setab 88 && tput setaf 15) #Noční_tramvaje
nocbus=$(tput setab 31 && tput setaf 15) #Noční_autobusy
nocreg=$(tput setab 0 && tput setaf 15) #Noční_příměstské_autobusy
zvl=$(tput setaf 150) #Zvláštní_linky
trol=$(tput setaf 89) #Trolejbusy
apikey=INSERT_YOUR_API_KEY_HERE
eopt=false
earg=""
hopt=false
iopt=false
lopt=false
larg=""
mopt=false
nopt=false
narg=""
oopt=false
oarg=""
ropt=false
zopt=false
zarg=""
die () {
echo -e "\e[1m\e[91mCHYBA\e[0m$* " >&2
exit 1
}
while getopts 'e:hil:mn:o:rz:' opt; do
case "$opt" in
e)
eopt=true
earg=$OPTARG ;;
h)
hopt=true ;;
i)
iopt=true ;;
l)
lopt=true
larg=$OPTARG ;;
m)
mopt=true ;;
n)
$zopt && die "\e[1m\e[91m:\e[0m Nelze Vybrat zároveň jméno a ID zastávky!"
nopt=true
narg=$OPTARG ;;
o)
oopt=true
oarg=$OPTARG ;;
r)
ropt=true ;;
z)
$nopt && die "\e[1m\e[91m:\e[0m Nelze Vybrat zároveň jméno a ID zastávky!"
zopt=true
zarg=$OPTARG ;;
esac
done
line1='┌──────┬──────────┬─────┬───────┬──────┬─────┬─────────────────────────────────────────────────────────────────────────┐'
line2='├──────┼──────────┼─────┼───────┼──────┼─────┼─────────────────────────────────────────────────────────────────────────┤'
line3='└──────┴──────────┴─────┴───────┴──────┴─────┴─────────────────────────────────────────────────────────────────────────┘'
line4='├──────┴──────────┴─────┴───────┴──────┴─────┴─────────────────────────────────────────────────────────────────────────┤'
line5='└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘'
hdr='%-36s'
ods='%-72s'
if $zopt; then
zast="ids=$zarg"
else
if $nopt; then
if [ "$narg" = "Smíchovské nádraží" ]; then
zast="names=Sm%C3%ADchovsk%C3%A9+n%C3%A1dra%C5%BE%C3%AD&names=Praha-Sm%C3%ADchov" #Provázání Smíchovského nádraží s vlaky
elif [ "$narg" = "Hlavní nádraží" ]; then
zast="names=Hlavn%C3%AD+n%C3%A1dra%C5%BE%C3%AD&names=Praha+hl.n." #Provázání Hlavního nádraží s vlaky
elif [ "$narg" = "Nádraží Holešovice" ]; then
zast="names=N%C3%A1dra%C5%BE%C3%AD+Hole%C5%A1ovice&names=Praha-Hole%C5%A1ovice" #Provázání Nádraží Holešovice s vlaky
elif [ "$narg" = "Nádraží Veleslavín" ]; then
zast="names=N%C3%A1dra%C5%BE%C3%AD+Veleslav%C3%ADn&names=Praha-Veleslav%C3%ADn" #Provázání Nádraží Veleslavín s vlaky
elif [ "$narg" = "Masarykovo nádraží" ]; then
zast="ids=U480Z3P&ids=U480Z4P&ids=U480Z4&ids=U480Z101P&ids=U480Z102P&ids=U480Z301" #Provázání Masarykova nádraží s vlaky a metrem
else
zast="names=$(python3 -c 'import sys, urllib.parse as ul; print (ul.quote_plus(sys.argv[1]))' "$narg")" #Převod češtiny do html podoby
fi
else
echo -e '\e[1m\e[4m\e[31mNení zadáno jméno zastávky\e[0m'
hopt=true
fi
fi
if $hopt; then
echo -e '\e[1m\e[4mParametry:\e[0m'
echo -e ' \e[1m-e [#] \e[0mVyloučí určené linky.'
echo -e ' \e[1m-h \e[0mTato nápověda.'
echo -e ' \e[1m-i \e[0mVypne zobrazování informací, jsou-li k dispozici.'
echo -e ' \e[1m-l [#] \e[0mLimit spojů.'
echo -e ' \e[1m-m \e[0mZpoždění v minutách.'
echo -e ' \e[1m-n ["Jméno zastávky"] \e[0mOdjezd ze zastávky. \e[31mNelze kombinovat s -z.\e[0m'
echo -e ' \e[1m-o [#] \e[0mVypíše pouze uvedenou linku.'
echo -e ' \e[1m-r \e[0mVypíše čas odjezdů dle JŘ'
echo -e ' \e[1m-z [UidZ] \e[0mOdjezd ze zastávky. \e[31mNelze kombinovat s -n.\e[0m'
echo -e ' \e[1m[#] \e[0mČíslo 0-9999'
echo -e ' \e[1m[UidZ] \e[0mID zastávky, např. U237Z1P'
echo -e ' \e[1m["Jméno zastávky"] \e[0mJméno zastávky v uvozovkách, např. "Smíchovské nádraží"'
exit
fi
if $eopt; then
filtr="grep -v ',\"$earg\",'"
elif $oopt; then
filtr="grep ',\"$oarg\",'"
else
filtr="grep -v '*'"
fi
if $mopt; then
delay="\x27"
zel=3
if $ropt; then
par=".departures[] | [.departure_timestamp.scheduled, .delay.minutes, .route.short_name, .last_stop.name, .trip.headsign, .stop.platform_code, .trip.id, .trip.is_wheelchair_accessible, .trip.is_air_conditioned] | @csv"
else
par=".departures[] | [.departure_timestamp.predicted, .delay.minutes, .route.short_name, .last_stop.name, .trip.headsign, .stop.platform_code, .trip.id, .trip.is_wheelchair_accessible, .trip.is_air_conditioned] | @csv"
fi
else
delay="\x22"
zel=180
if $ropt; then
par=".departures[] | [.departure_timestamp.scheduled, .delay.seconds, .route.short_name, .last_stop.name, .trip.headsign, .stop.platform_code, .trip.id, .trip.is_wheelchair_accessible, .trip.is_air_conditioned] | @csv"
else
par=".departures[] | [.departure_timestamp.predicted, .delay.seconds, .route.short_name, .last_stop.name, .trip.headsign, .stop.platform_code, .trip.id, .trip.is_wheelchair_accessible, .trip.is_air_conditioned] | @csv"
fi
fi
if $lopt; then
lim=$larg
else
lim=8
fi
#Kontrola dostupnosti dat
wget -q --spider https://api.golemio.cz
if [ $? -eq 4 ]; then
die "\e[1m\e[91m:\e[0m Není přístup na internet!"
fi
json=$(curl -s --header "Content-Type: application/json; charset=utf-8" --header "x-access-token: $apikey" 'https://api.golemio.cz/v2/pid/departureboards/?'$zast'&preferredTimezone=Europe%2FPrague&includeMetroTrains=true&airCondition=true&limit='$lim) # Stažení dat a uložení do paměti.
#Kontrola stavů
if echo $json | grep -q '"error_status":404'; then
die "\e[1m\e[91m 404:\e[0m Požadovaná zastávka neexistuje!"
fi
if echo $json | grep -q '"error_status":403'; then
die "\e[1m\e[91m 403:\e[0m Přístup odmítnut!"
fi
if echo $json | grep -q '"error_status":401'; then
die "\e[1m\e[91m 401:\e[0m Přístup zakázán!"
fi
evc=$(curl -Ls --header "Content-Type: application/json; charset=utf-8" --header "x-access-token: $apikey" 'https://api.golemio.cz/v2/vehiclepositions' | cat | jq -r '.features[] | [.properties.trip.gtfs.trip_id, .properties.trip.vehicle_registration_number] | @csv') # Poloha vozidel (pro evidenční čísla)
if [ "$narg" = "Masarykovo nádraží" ]; then
stop="Masarykovo nádraží"
elif [ "$narg" = "Palackého náměstí" ]; then
stop="Palackého náměstí"
else
stop=$(echo $json | jq -r '.stops[0].stop_name')
fi
zt2=$(printf '%s\n' "${json}" | jq -r "$par" | eval $filtr) #Převod oddělení hodnot z , na ; Kvůli mimopražským zastávkám (Mají v názvu čárky, např. Černošice,žel.st.)
file1=$(printf '%s\n' "${zt2}" | sed -z 's/",/;/g' | sed -z 's/,"/;/g' | sed -z 's/,true/;true/g'| sed -z 's/true,/true;/g' | sed -z 's/,false/;false/g'| sed -z 's/false,/false;/g' | sed -z 's/"//g' | sort -t\; -k7)
file2=$(printf '%s\n' "${evc}" | sed -z 's/",/;/g' | sed -z 's/,"/;/g' | sed -z 's/,true/;true/g'| sed -z 's/true,/true;/g' | sed -z 's/,false/;false/g'| sed -z 's/false,/false;/g' | sed -z 's/"//g' | sort)
if [ -z "$file1" ]; then
die "\e[1m\e[91m:\e[0m Žádný nejbližší odjezd!"
fi
#Spojení odjezdů a evidenčních čísel vozidel
spolu=$(join --nocheck-order -t\; -a1 -1 7 -2 1 -o 1.1 1.2 1.3 1.5 1.6 2.2 1.4 1.8 1.9 -e "" <(printf '%s\n' "${file1}") <(printf '%s\n' "${file2}") | sort )
info=$(printf '%s\n' "${json}" | jq -r ".infotexts[] | [.text] | @csv" | tr -d '"')
velinfo=$(echo $info | wc -w)
datum=$(date +"%a %d.%m.%y %X" | sed 's/Mon/Po/g' | sed 's/Tue/Út/g' | sed 's/Wed/St/g' | sed 's/Thu/Čt/g' | sed 's/Fri/Pá/g' | sed 's/Sat/So/g' | sed 's/Sun/Ne/g')
echo $line1
echo | awk -v datum="$datum" -v stop="$stop" -v hdr=$hdr 'BEGIN{printf "│ LINK │ ODJEZD │ NÁS │ ZPOZD │ EVID │ STS │Stav k %10s z "hdr" │\n", datum, stop}'
echo $line2
printf '%s\n' "${spolu}" | uniq | sed 's/MHD /MHD/g' | awk -v zel=$zel -F\; 'BEGIN {ods="'"$ods"'";delay="'"$delay"'";red="'"$red"'";green="'"$green"'";yellow="'"$yellow"'";norm="'"$norm"'";acko="'"$acko"'";becko="'"$becko"'";cecko="'"$cecko"'";tram="'"$tram"'";bus="'"$bus"'";vlak="'"$vlak"'";xkot="'"$xkot"'";xkob="'"$xkob"'";ld="'"$ld"'";privoz="'"$privoz"'";region="'"$region"'";noctram="'"$noctram"'";nocbus="'"$nocbus"'";nocreg="'"$nocreg"'";zvl="'"$zvl"'";trol="'"$trol"'"}{printf norm "│"};{if($3=="A") printf acko " %4s ", $3;else if($3=="B") printf becko " %4s ", $3; else if ($3=="C") printf cecko " %4s ", $3; else if ($3=="Cyklohráček") printf vlak " CykH "; else if ($3=="Český ráj") printf vlak " ČesR "; else if ($3=="Cyklo Brdy") printf vlak " CykB "; else if ($3=="Rakovnický rychlík") printf vlak " RakR "; else if ($3=="Kokořínský rychlík") printf vlak " KokR "; else if ($3=="Lužický rychlík") printf vlak " LužR "; else if ($3=="Pražský motoráček") printf vlak " PraM "; else if ($3=="Posázavský motoráček") printf vlak " PosM "; else if ($3=="AE") printf bus " %4s ", $3; else if (1<=$3&& $3<=26) printf tram " %4s ", $3; else if (26<$3 && $3<40) printf xkot " %4s ", $3; else if (40<=$3 && $3<50) printf zvl " %4s ", $3; else if (50<=$3 && $3<60) printf trol " %4s ", $3; else if (90<=$3 && $3<=99) printf noctram " %4s ", $3; else if (99<$3 && $3<=299) printf bus " %4s ", $3; else if ($3 ~ /^BB/) printf zvl " %4s ", $3;else if (300<=$3 && $3<850) printf region " %4s ", $3; else if (850<=$3 && $3<=899) printf zvl " %4s ", $3; else if (900<=$3 && $3<950) printf nocbus " %4s ", $3; else if (950<=$3 && $3<=999) printf nocreg " %4s ", $3; else if ($3=="IKEA") printf zvl " %4s ", $3; else if ($3 ~ /^MHD/) printf region " %4s ", $3; else if ($3=="LD") printf ld " %4s ", $3; else if ($3 ~ /^X/) printf xkob " %4s ", $3; else if ($3 ~ /^P/) printf privoz " %4s ", $3; else if ($3 ~ /^L/) printf vlak " %4s ", $3; else if ($3 ~ /^U/) printf vlak " %4s ", $3; else if ($3 ~ /^S/) printf vlak " %4s ", $3; else if ($3 ~ /^R/) printf vlak " %4s ", $3};{printf norm "│ %8s │", substr($1,12,8)};{if (length($5) == 1) printf norm " %2s │", $5; else if (length($5) == 2) printf norm " %2s │", $5; else if (length($5) == 3) printf norm " %3s │", $5; else printf norm " %3s │", substr($5,1,3)}; {if($2<0) printf red " %4d"delay" ", $2 norm; else if ($2 <= zel) printf green " %4d"delay" ",$2; else printf yellow " %4d"delay" ",$2 norm};{printf norm "│ %-5s│", $6}; {if($8=="true") printf bus " %2s","♿" norm; else printf norm "%3s"," "}; {if($9=="true") printf bus "%1s │","*" norm;else printf norm "%1s │", " "};{stp=$7" → "$4; printf " "ods"│\n", stp}' | head -n $lim
if [ "$iopt" == true ] || [ "$velinfo" -lt 1 ]; then
echo $line3
else
echo $line4
echo $info | fold -sw 116 | while read line; do printf "│ %-116s │\n" "$line"; done
echo $line5
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment