diff --git a/services/imports/wakatime.go b/services/imports/wakatime.go index d210161..8b1e00e 100644 --- a/services/imports/wakatime.go +++ b/services/imports/wakatime.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "github.com/duke-git/lancet/v2/datetime" + "github.com/muety/wakapi/utils" "net/http" "time" @@ -154,8 +155,9 @@ func (w *WakatimeHeartbeatImporter) fetchRange(baseUrl string) (time.Time, time. return notime, notime, err } - var allTimeData wakatime.AllTimeViewModel - if err := json.NewDecoder(res.Body).Decode(&allTimeData); err != nil { + // see https://github.com/muety/wakapi/issues/370 + allTimeData, err := utils.ParseJsonDropKeys[wakatime.AllTimeViewModel](res.Body, "text") + if err != nil { return notime, notime, err } diff --git a/utils/json.go b/utils/json.go new file mode 100644 index 0000000..1aa6d0a --- /dev/null +++ b/utils/json.go @@ -0,0 +1,34 @@ +package utils + +import ( + "bytes" + "encoding/json" + "io" +) + +// ParseJsonDropKeys parses the given JSON input object to an object of given type, while omitting the specified keys on the way. +// This can be useful if parsing would normally fail due to ambiguous typing of some key, but that key is not of interest and can be dropped to avoid parse errors. +// Dropping keys only works on top level of the object. +func ParseJsonDropKeys[T any](r io.Reader, dropKeys ...string) (T, error) { + var ( + result T + resultTmp map[string]interface{} + resultTmpBuf = new(bytes.Buffer) + ) + if err := json.NewDecoder(r).Decode(&resultTmp); err != nil { + return result, err + } + + for _, k := range dropKeys { + delete(resultTmp, k) + } + + if err := json.NewEncoder(resultTmpBuf).Encode(resultTmp); err != nil { + return result, err + } + if err := json.NewDecoder(resultTmpBuf).Decode(&result); err != nil { + return result, err + } + + return result, nil +}