Fixed to use restored v1 API
This commit is contained in:
parent
8a13989ba3
commit
663a89785c
10186
cache.json
10186
cache.json
File diff suppressed because it is too large
Load Diff
@ -17,7 +17,7 @@
|
|||||||
{{ range .Favourites }}
|
{{ range .Favourites }}
|
||||||
<tr style="height: 2em; vertical-align: center;">
|
<tr style="height: 2em; vertical-align: center;">
|
||||||
<td style="width: 30em; text-align: center;">
|
<td style="width: 30em; text-align: center;">
|
||||||
<a href="/{{ .ID }}">
|
<a href="/{{ .Code }}">
|
||||||
{{ .Name }} ({{ .Code }})
|
{{ .Name }} ({{ .Code }})
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
176
main.go
176
main.go
@ -14,67 +14,56 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var stopIDs map[int] int;
|
|
||||||
|
|
||||||
type Favourite struct {
|
type Favourite struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Code string `json:"code"`
|
Code string `json:"code"`
|
||||||
ID string `json:"id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type CarFlags struct {
|
|
||||||
Disabled bool `json:"disabled"`
|
|
||||||
AirConditioner bool `json:"klimatik"`
|
|
||||||
BicycleRack bool `json:"bicycle_rack"`
|
|
||||||
DoubleDecker bool `json:"doubledecker"`
|
|
||||||
ByTimeTable bool `json:"by_timetable"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Car struct {
|
type Car struct {
|
||||||
DepartureTime string `json:"departure_time"`
|
Time string `json:"time"`
|
||||||
Flags CarFlags `json:"flags"`
|
}
|
||||||
Destination int `json:"destination"`
|
|
||||||
CourseID int `json:"course_id"`
|
type MaybeString string
|
||||||
DestinationName string `json:"destination_name"`
|
|
||||||
CalculatedTime string `json:"calc_time"`
|
func (ms *MaybeString) UnmarshalJSON(b []byte) error {
|
||||||
DirectionFlag int `json:"direction_flag"`
|
var i any
|
||||||
TTCourseStopID int `json:"ttcoursestop_id"`
|
err := json.Unmarshal(b, &i)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch val := i.(type) {
|
||||||
|
case int, float32, float64:
|
||||||
|
*ms = MaybeString(fmt.Sprint(val))
|
||||||
|
return nil
|
||||||
|
case string:
|
||||||
|
*ms = MaybeString(val)
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unknown type %T", val)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Line struct {
|
type Line struct {
|
||||||
Transport string `json:"transport"`
|
Type string `json:"vehicle_type"`
|
||||||
ID int `json:"id"`
|
Name MaybeString `json:"name"`
|
||||||
Name string `json:"name"`
|
Cars []Car `json:"arrivals"`
|
||||||
Cars []Car `json:"cars"`
|
|
||||||
Color string
|
Color string
|
||||||
}
|
}
|
||||||
|
|
||||||
type VirtualPanelData struct {
|
type SofiaTraffic struct {
|
||||||
ID int `json:"id"`
|
Name string `json:"name"`
|
||||||
|
Code string `json:"code"`
|
||||||
Lines []Line `json:"lines"`
|
Lines []Line `json:"lines"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SofiaTraffic struct {
|
|
||||||
Data VirtualPanelData `json:"virtual_panel_data"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type OutputData struct {
|
|
||||||
ID string
|
|
||||||
Lines []Line
|
|
||||||
}
|
|
||||||
|
|
||||||
type CacheData struct {
|
|
||||||
TargetID int `json:"target_id"`
|
|
||||||
DataID int `json:"data_id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func lessLine(left Line, right Line) bool {
|
func lessLine(left Line, right Line) bool {
|
||||||
val := strings.Compare(left.Transport, right.Transport)
|
val := strings.Compare(left.Type, right.Type)
|
||||||
if val != 0 {
|
if val != 0 {
|
||||||
return val < 0
|
return val < 0
|
||||||
} else {
|
} else {
|
||||||
l, lerr := strconv.Atoi(left.Name)
|
l, lerr := strconv.Atoi(string(left.Name))
|
||||||
r, rerr := strconv.Atoi(right.Name)
|
r, rerr := strconv.Atoi(string(right.Name))
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case lerr == nil && rerr == nil:
|
case lerr == nil && rerr == nil:
|
||||||
@ -84,7 +73,7 @@ func lessLine(left Line, right Line) bool {
|
|||||||
case lerr != nil && rerr == nil:
|
case lerr != nil && rerr == nil:
|
||||||
return false
|
return false
|
||||||
case lerr != nil && rerr != nil:
|
case lerr != nil && rerr != nil:
|
||||||
val = strings.Compare(left.Name, right.Name)
|
val = strings.Compare(string(left.Name), string(right.Name))
|
||||||
return val < 0
|
return val < 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -101,8 +90,7 @@ func handle(resp http.ResponseWriter, req *http.Request) {
|
|||||||
show500(resp)
|
show500(resp)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
target_id := stopIDs[find_int]
|
http.Redirect(resp, req, fmt.Sprintf("/%04d", find_int), http.StatusFound)
|
||||||
http.Redirect(resp, req, fmt.Sprintf("/%d", target_id), http.StatusFound)
|
|
||||||
} else if len(id) == 0 {
|
} else if len(id) == 0 {
|
||||||
showFavourites(resp)
|
showFavourites(resp)
|
||||||
} else {
|
} else {
|
||||||
@ -115,20 +103,39 @@ func show500(resp http.ResponseWriter) {
|
|||||||
fmt.Fprintf(resp, "<h1 style=\"text-align:center;\">500 Internal Server Error</h1>")
|
fmt.Fprintf(resp, "<h1 style=\"text-align:center;\">500 Internal Server Error</h1>")
|
||||||
}
|
}
|
||||||
|
|
||||||
func setLineColor(line *Line) {
|
func fixLine(line *Line) {
|
||||||
switch {
|
switch line.Type {
|
||||||
case line.Transport == "A":
|
case "bus":
|
||||||
line.Color = "FF0000"
|
line.Type = "А"
|
||||||
case line.Transport == "ТБ":
|
case "trolley":
|
||||||
line.Color = "0000FF"
|
line.Type = "ТБ"
|
||||||
case line.Transport == "ТМ":
|
case "tram":
|
||||||
line.Color = "FF8000"
|
line.Type = "ТМ"
|
||||||
|
}
|
||||||
|
|
||||||
|
switch line.Name[0] {
|
||||||
|
case 'E':
|
||||||
|
line.Type = "А"
|
||||||
|
line.Name = line.Name[1:]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSofiaTrafficData(id string) (SofiaTraffic, error) {
|
func setLineColor(line *Line) {
|
||||||
|
switch {
|
||||||
|
case line.Type == "А":
|
||||||
|
line.Color = "BD202E"
|
||||||
|
case line.Type == "ТБ":
|
||||||
|
line.Color = "2AA9E0"
|
||||||
|
case line.Type == "ТМ":
|
||||||
|
line.Color = "F7941F"
|
||||||
|
default:
|
||||||
|
line.Color = "000000"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSofiaTrafficData(code string) (SofiaTraffic, error) {
|
||||||
var data SofiaTraffic
|
var data SofiaTraffic
|
||||||
url := fmt.Sprintf("https://www.sofiatraffic.bg/interactivecard/virtual_panel?stop_id=%s", id)
|
url := fmt.Sprintf("https://api-arrivals.sofiatraffic.bg/api/v1/arrivals/%s/", code)
|
||||||
|
|
||||||
respAPI, err := http.Get(url)
|
respAPI, err := http.Get(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -136,7 +143,7 @@ func getSofiaTrafficData(id string) (SofiaTraffic, error) {
|
|||||||
return data, errors.New("get failed")
|
return data, errors.New("get failed")
|
||||||
}
|
}
|
||||||
if respAPI.StatusCode != 200 {
|
if respAPI.StatusCode != 200 {
|
||||||
log.Printf("Status code for ID %v is %v", id, respAPI.StatusCode)
|
log.Printf("Status code for Code %v is %v", code, respAPI.StatusCode)
|
||||||
return data, errors.New("bad status code")
|
return data, errors.New("bad status code")
|
||||||
}
|
}
|
||||||
if respAPI.Body != nil {
|
if respAPI.Body != nil {
|
||||||
@ -158,29 +165,34 @@ func getSofiaTrafficData(id string) (SofiaTraffic, error) {
|
|||||||
return data, nil
|
return data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func showTable(resp http.ResponseWriter, id string) {
|
func showTable(resp http.ResponseWriter, code string) {
|
||||||
data, err := getSofiaTrafficData(id)
|
data, err := getSofiaTrafficData(code)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
fmt.Println("POOTIS")
|
||||||
show500(resp)
|
show500(resp)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort Lines
|
for idx := range(data.Lines) {
|
||||||
sort.Slice(data.Data.Lines, func (i int, j int) bool {
|
// Fix Line
|
||||||
return lessLine(data.Data.Lines[i], data.Data.Lines[j])
|
fixLine(&(data.Lines[idx]))
|
||||||
})
|
|
||||||
|
|
||||||
// Set Line Colors
|
// Set Line Colors
|
||||||
for idx := range(data.Data.Lines) {
|
setLineColor(&(data.Lines[idx]))
|
||||||
setLineColor(&(data.Data.Lines[idx]))
|
|
||||||
|
// Do not show seconds
|
||||||
|
for car_idx := range(data.Lines[idx].Cars) {
|
||||||
|
data.Lines[idx].Cars[car_idx].Time = data.Lines[idx].Cars[car_idx].Time[:5]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var dataOut OutputData
|
// Sort Lines
|
||||||
dataOut.ID = fmt.Sprintf("%04d", data.Data.ID)
|
sort.Slice(data.Lines, func (i int, j int) bool {
|
||||||
dataOut.Lines = data.Data.Lines
|
return lessLine(data.Lines[i], data.Lines[j])
|
||||||
|
})
|
||||||
|
|
||||||
templ := template.Must(template.ParseFiles("stop.html"))
|
templ := template.Must(template.ParseFiles("stop.html"))
|
||||||
templ.Execute(resp, dataOut)
|
templ.Execute(resp, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func readFavourites() []Favourite {
|
func readFavourites() []Favourite {
|
||||||
@ -216,35 +228,7 @@ func showFavourites(resp http.ResponseWriter) {
|
|||||||
templ.Execute(resp, data)
|
templ.Execute(resp, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadIDs() {
|
|
||||||
stopIDs = make(map[int]int)
|
|
||||||
var cache []CacheData
|
|
||||||
jsonFile, err := os.Open("cache.json")
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer jsonFile.Close()
|
|
||||||
|
|
||||||
bytes, err := io.ReadAll(jsonFile)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = json.Unmarshal(bytes, &cache)
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, val := range(cache) {
|
|
||||||
stopIDs[val.TargetID] = val.DataID
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
loadIDs()
|
|
||||||
http.HandleFunc("/", handle)
|
http.HandleFunc("/", handle)
|
||||||
log.Println("Server Running")
|
log.Println("Server Running")
|
||||||
http.ListenAndServe(":8000", nil)
|
http.ListenAndServe(":8000", nil)
|
||||||
|
|||||||
24
stop.html
24
stop.html
@ -6,38 +6,32 @@
|
|||||||
<title>SofiaTraffic EZ Table</title>
|
<title>SofiaTraffic EZ Table</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<h1 style="text-align: center;">
|
||||||
|
{{.Name}} ({{ .Code }})
|
||||||
|
</h1>
|
||||||
<table style="margin-left: auto; margin-right: auto; text-align: center;">
|
<table style="margin-left: auto; margin-right: auto; text-align: center;">
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td colspan="100%">
|
||||||
<a href="/" style="display:block">
|
<a href="/" style="display:block">
|
||||||
Back
|
Back
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td colspan="2">
|
|
||||||
{{ .ID }}
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
{{ range .Lines }}
|
{{ range .Lines }}
|
||||||
<tr>
|
<tr>
|
||||||
<td style="background-color: #{{ .Color }}; color: #FFFFFF;">
|
<td style="background-color: #{{ .Color }}; color: #FFFFFF;">
|
||||||
<div style="width: 2em; display: inline-block; margin: 0 0 0 0; padding: 0 0 0 0;">
|
<div style="width: 2em; display: inline-block; margin: 0 0 0 0; padding: 0 0 0 0;">
|
||||||
{{ .Transport }}
|
{{ .Type }}
|
||||||
</div><div style="width: 3em; display: inline-block; margin: 0 0 0 0; padding: 0 0 0 0;">
|
</div>
|
||||||
|
<div style="width: 3em; display: inline-block; margin: 0 0 0 0; padding: 0 0 0 0;">
|
||||||
{{ .Name }}
|
{{ .Name }}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
{{ range .Cars }}
|
{{ range .Cars }}
|
||||||
<td>
|
<td>
|
||||||
<div style="width: 1em; display: inline-block; margin: 0 0 0 0; padding: 0 0 0 0;">
|
<div style="width: 4em; display: inline-block; margin: 0 0 0 0; padding: 0 0 0 0;">
|
||||||
{{ if .Flags.AirConditioner }}
|
{{ .Time }}
|
||||||
<svg stroke="#2c54a4" fill="#2c54a4" stroke-width="0" viewBox="0 0 448 512" class="icon" style="vertical-align: baseline; margin-left: 0px;" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg">
|
|
||||||
<path d="M440.3 345.2l-33.8-19.5 26-7c8.2-2.2 13.1-10.7 10.9-18.9l-4-14.9c-2.2-8.2-10.7-13.1-18.9-10.9l-70.8 19-63.9-37 63.8-36.9 70.8 19c8.2 2.2 16.7-2.7 18.9-10.9l4-14.9c2.2-8.2-2.7-16.7-10.9-18.9l-26-7 33.8-19.5c7.4-4.3 9.9-13.7 5.7-21.1L430.4 119c-4.3-7.4-13.7-9.9-21.1-5.7l-33.8 19.5 7-26c2.2-8.2-2.7-16.7-10.9-18.9l-14.9-4c-8.2-2.2-16.7 2.7-18.9 10.9l-19 70.8-62.8 36.2v-77.5l53.7-53.7c6.2-6.2 6.2-16.4 0-22.6l-11.3-11.3c-6.2-6.2-16.4-6.2-22.6 0L256 56.4V16c0-8.8-7.2-16-16-16h-32c-8.8 0-16 7.2-16 16v40.4l-19.7-19.7c-6.2-6.2-16.4-6.2-22.6 0L138.3 48c-6.3 6.2-6.3 16.4 0 22.6l53.7 53.7v77.5l-62.8-36.2-19-70.8c-2.2-8.2-10.7-13.1-18.9-10.9l-14.9 4c-8.2 2.2-13.1 10.7-10.9 18.9l7 26-33.8-19.5c-7.4-4.3-16.8-1.7-21.1 5.7L2.1 145.7c-4.3 7.4-1.7 16.8 5.7 21.1l33.8 19.5-26 7c-8.3 2.2-13.2 10.7-11 19l4 14.9c2.2 8.2 10.7 13.1 18.9 10.9l70.8-19 63.8 36.9-63.8 36.9-70.8-19c-8.2-2.2-16.7 2.7-18.9 10.9l-4 14.9c-2.2 8.2 2.7 16.7 10.9 18.9l26 7-33.8 19.6c-7.4 4.3-9.9 13.7-5.7 21.1l15.5 26.8c4.3 7.4 13.7 9.9 21.1 5.7l33.8-19.5-7 26c-2.2 8.2 2.7 16.7 10.9 18.9l14.9 4c8.2 2.2 16.7-2.7 18.9-10.9l19-70.8 62.8-36.2v77.5l-53.7 53.7c-6.3 6.2-6.3 16.4 0 22.6l11.3 11.3c6.2 6.2 16.4 6.2 22.6 0l19.7-19.7V496c0 8.8 7.2 16 16 16h32c8.8 0 16-7.2 16-16v-40.4l19.7 19.7c6.2 6.2 16.4 6.2 22.6 0l11.3-11.3c6.2-6.2 6.2-16.4 0-22.6L256 387.7v-77.5l62.8 36.2 19 70.8c2.2 8.2 10.7 13.1 18.9 10.9l14.9-4c8.2-2.2 13.1-10.7 10.9-18.9l-7-26 33.8 19.5c7.4 4.3 16.8 1.7 21.1-5.7l15.5-26.8c4.3-7.3 1.8-16.8-5.6-21z">
|
|
||||||
</path>
|
|
||||||
</svg>
|
|
||||||
{{ end }}
|
|
||||||
</div><div style="width: 4em; display: inline-block; margin: 0 0 0 0; padding: 0 0 0 0;">
|
|
||||||
{{ .DepartureTime }}
|
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user