(require 'xml)
(require 'time-date)
+(eval-when-compile
+ (require 'cl))
+
(defgroup google-weather nil
"Google Weather."
:group 'comm)
+(defcustom google-weather-use-https nil
+ "Default protocol to use to access the Google Weather API."
+ :group 'google-weather
+ :type 'boolean)
+
(defconst google-weather-url
- "http://www.google.com/ig/api"
- "URL used to access the Google Weather API.")
+ "www.google.com/ig/api"
+ "URL of the Google Weather API.")
(defconst google-weather-image-url
"http://www.google.com"
(if cache-time
(time-less-p
(time-add
- (url-is-cached url)
+ cache-time
(seconds-to-time expire-time))
(current-time))
t)))))
(url-cache-extract (url-cache-create-filename url))
(current-buffer)))
-(defun google-weather-retrieve-data (url &optional expire-time)
+(defun google-weather-retrieve-data-raw (url &optional expire-time)
"Retrieve URL and return its data as string.
If EXPIRE-TIME is set, the data will be fetched from the cache if
their are not older than EXPIRE-TIME seconds. Otherwise, they
(url-retrieve-synchronously url)
(google-weather-cache-fetch url)))
data)
- (with-current-buffer buffer
+ (when (and expired expire-time)
+ (url-store-in-cache buffer))
+ buffer))
+
+(defun google-weather-retrieve-data (url &optional expire-time)
+ "Retrieve URL and return its data as string.
+If EXPIRE-TIME is set, the data will be fetched from the cache if
+their are not older than EXPIRE-TIME seconds. Otherwise, they
+will be fetched and then cached. Therefore, setting EXPIRE-TIME
+to 0 force a cache renewal."
+ (with-current-buffer (google-weather-retrieve-data-raw
+ url expire-time)
(goto-char (point-min))
- (search-forward "\n\n")
+ (unless (search-forward "\n\n" nil t)
+ (error "Data not found"))
(decode-coding-region
(point) (point-max)
(detect-coding-region (point) (point-max) t))
(set-buffer-multibyte t)
- (setq data (xml-parse-region (point) (point-max)))
- (when (and expired expire-time)
- (url-store-in-cache (current-buffer)))
- (kill-buffer (current-buffer))
- data)))
+ (let ((data (xml-parse-region (point) (point-max))))
+ (kill-buffer (current-buffer))
+ data)))
(defun google-weather-build-url (location &optional language)
"Build URL to retrieve weather for LOCATION in LANGUAGE."
- (concat google-weather-url "?weather=" (url-hexify-string location)
+ (concat "http" (when google-weather-use-https "s") "://" google-weather-url "?weather=" (url-hexify-string location)
(when language
(concat "&hl=" language))))
(cddr (assoc 'forecast_information (google-weather-data->weather data))))
(defun google-weather-assoc (key data)
- "Do some sort of magic 'assoc to find fields in DATA."
+ "Extract value of field KEY from DATA."
(cdr (assoc 'data (cadr (assoc key data)))))
(defun google-weather-data->city (data)
(google-weather-data->forecast-information data)))
(defun google-weather-data->postal-code (data)
- "Return the postal code where the data come from."
+ "Return the postal code where the DATA come from."
(google-weather-assoc
'postal_code
(google-weather-data->forecast-information data)))
(defun google-weather-data->unit-system (data)
- "Return the unit system used for data."
+ "Return the unit system used for DATA."
(google-weather-assoc
'unit_system
(google-weather-data->forecast-information data)))
(defun google-weather-data->forecast-date (data)
- "Return the unit system used for data."
+ "Return the unit system used for DATA."
(google-weather-assoc
'forecast_date
(google-weather-data->forecast-information data)))
(defun google-weather-data->forecast-for-date (data date)
"Return forecast for DATE from DATA.
-DATE should be in the same format used by calendar i.e. (MONTH DAY YEAR)."
- (cdr (assoc date
- (google-weather-data->forecast data))))
+DATE should be in the same format used by calendar,
+i.e. (MONTH DAY YEAR)."
+ (cdr (assoc date (google-weather-data->forecast data))))
(defun google-weather-data->temperature-symbol (data)
- "Return the temperature to be used according to `google-weather-unit-system-temperature-assoc' in DATA."
+ "Return the temperature to be used according in DATA.
+It uses `google-weather-unit-system-temperature-assoc' to find a
+match."
(cdr (assoc (google-weather-data->unit-system data) google-weather-unit-system-temperature-assoc)))
+
+(defun google-weather-data->problem-cause (data)
+ "Return a string if DATA contains a problem cause, `nil' otherwise.
+
+An error message example:
+
+((xml_api_reply
+ ((version . \"1\"))
+ (weather
+ ((module_id . \"0\") (tab_id . \"0\") (mobile_row . \"0\")
+ (mobile_zipped . \"1\") (row . \"0\") (section . \"0\"))
+ (problem_cause ((data . \"Information is temporarily unavailable.\"))))))))"
+ (google-weather-assoc
+ 'problem_cause
+ (google-weather-data->weather data)))
+
(provide 'google-weather)