;;; ptv.el -- Public Transport Victoria timetable API client -*- lexical-binding: t -*- ;; Copyright (C) 2023 Free Software Foundation. ;; Author: Yuchen Pei ;; Package-Requires: ((emacs "28.2")) ;; This file is part of ptv.el. ;; ptv.el is free software: you can redistribute it and/or modify it under ;; the terms of the GNU Affero General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; ptv.el is distributed in the hope that it will be useful, but WITHOUT ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General ;; Public License for more details. ;; You should have received a copy of the GNU Affero General Public ;; License along with ptv.el. If not, see . ;;; Commentary: ;; Public Transport Victoria timetable API client. ;;; Code: (require 'hmac-def) (require 'hex-util) ;; FIXME: use a library somehow for json fetching. (require 'my-net) (defvar ptv-host "https://timetableapi.ptv.vic.gov.au" "The PTV Timetable API host.") (defcustom ptv-dev-key nil "The PTV Timetable API dev key." :type '(string) :group 'ptv) (defcustom ptv-dev-id nil "The PTV Timetable API dev id." :type '(string) :group 'ptv) (defun ptv-sha1-binary (text) "Return the sha-1 digest of TEXT in binary." (sha1 text nil nil t)) (define-hmac-function ptv-hmac-sha1-binary ptv-sha1-binary 64 20) (defun ptv-hmac-sha1 (text key) "Return the sha-1 hmac of TEXT using KEY in hex digest." (encode-hex-string (ptv-hmac-sha1-binary text key))) (defun ptv-api-query (path) "Format the query url of a query PATH." (let* ((path-to-sign (format "/v3%s?devid=%s" path ptv-dev-id)) (sig (upcase (ptv-hmac-sha1 path-to-sign ptv-dev-key)))) (my-url-fetch-json (format "%s%s&signature=%s" ptv-host path-to-sign sig)))) (defun ptv-api-search (query) "Call the search API with QUERY." (ptv-api-query (format "/search/%s" (url-hexify-string query)))) (defun ptv-api-departures (route-type stop-id route-id) "Call the departures API with ROUTE-TYPE, STOP-ID and ROUTE-ID." (ptv-api-query (format "/departures/route_type/%s/stop/%s/route/%s" route-type stop-id route-id))) (defun ptv-api-directions (route-id) "Call the directions API with ROUTE-ID." (ptv-api-query (format "/directions/route/%s" route-id))) (defun ptv-api-runs (route-id) "Call the runs API with ROUTE-ID." (ptv-api-query (format "/runs/route/%s" route-id))) (defun ptv-api-pattern (run-ref route-type) "Call the patterns API with RUN-REF and ROUTE-TYPE." (ptv-api-query (format "/pattern/run/%s/route_type/%s" run-ref route-type))) (defun ptv-api-stops (lat lon) "Call the stops API with LAT(itude) and LON(gitude)." (ptv-api-query (format "/stops/location/%s,%s" lat lon))) (defun ptv-api-disruptions () "Call the disruptions API." (ptv-api-query "/disruptions")) (provide 'ptv) ;;; ptv.el ends here